I am using laravel scout to upload records for searching in algolia. I have added the searchable trait to my model, and everything is working fine.
There is a case now where I don't want to add certain records to my index if they have set status I.E UNPUBLISHED.
is there away I can evaluate the status field and decide if I want the model to be uploaded to the index?
Just use $model_name->unsearchable() to remove it from your Algolia index.
See "Removing Records" in the documentation for more details: https://laravel.com/docs/5.3/scout#removing-records
You can use method toSearchableData() and in case the status is Unpublished, just return empty array and the record will be skipped.
Otherwise just return $this->toArray().
It will do the trick.
Say we have a Post model, with a boolean published attribute, and a model factory to seed our table as follows:
$factory->define(App\Post::class, function (Faker\Generator $faker) {
$tile = $faker->realText(50);
$date = $faker->dateTime;
return [
'title' => $tile,
'body' => $faker->realText(500),
'published' => $faker->boolean(80),
'created_at' => $date,
'updated_at' => $date
];
});
Let's say we will seed 10 records.
public function run()
{
factory(App\Article::class, 10)->create();
}
If we tried to exclude unpublished records within the toSearchableArray() method, as suggested:
public function toSearchableArray()
{
if (! $this->published) {
return[];
}
// ...
}
When seeding the posts table, instead of ignoring unpublished records by returning an empty array, scout will keep asking the model factory for a published model.
For example, if two of the seeded records were randomly unpublished, scout would index all 10 records (instead of 8) anyway, replacing the unpublished ones by a new model factory (with a published set attribute). Thus causing to have two inexistent (on our table) records in the algolia index. Quite confusing.
The "neatest" way around this I could come up with, was to listen to the saved/updated events (saving/updating won't cut it) in the model's boot method.
protected static function boot()
{
static::saved(function ($model) {
if (! $model->published) {
$model->unsearchable();
}
});
static::updated(function ($model) {
if (! $model->published) {
$model->unsearchable();
}
});
parent::boot();
}
Check out this question. This problem has been solved in the new version of Scout
Adding Index to Laravel Scout Conditionally (Algolia)
Related
Here is my action.
public function actions(Request $request)
{
return [
new ApprovedUserAction,
(new RejectUserAction)->make()->standalone(),
];
}
This is my action code.
{
Log::info('test',['test' => $models]);
Log::info('test',['field' => $fields]);
foreach ($models as $model) {
Log::info("here);
$actionEvent = ActionEvent::forResourceUpdate(auth()->user(), $model);
$model->update(['status' => 'reject']);
$actionEvent->save();
}
return $models;
// return Action::message('You have been Updated');
}
Why the models' values are empty??
I want to update the selected values, but the models return an empty array.
When its a standalone action these fields are omitted since it works on a whole resource and not selected records.
There are a few solutions here but i think creating two actions, one for the whole resource if you need a standalone and one for a collection of models if you need to select them.
Unless nova 4 released the other day has a better solution.
Here is link to relevant documentation for nova 3.
https://nova.laravel.com/docs/3.0/actions/registering-actions.html#standalone-actions
I'm brand new to Laravel and am working my way through the Laravel 6 from Scratch course over at Laracasts. The course is free but I can't afford a Laracasts membership so I can't ask questions there.
I've finished Section 6 of the course, Controller Techniques, and am having unexpected problems trying to extend the work we've done so far to add a few new features. The course has students build pages that let a user show a list of articles, look at an individual article, create and save a new article, and update and save an existing article. The course work envisioned a very simple article containing just an ID (auto-incremented in the database and not visible to the web user), a title, an excerpt and a body and I got all of the features working for that. Now I'm trying to add two new fields: an author name and a path to a picture illustrating the article. I've updated the migration, rolled back and rerun the migration to include the new fields and got no errors from that. (I also ran a migrate:free and got no errors from that.) I've also updated the forms used to create and update the articles and added validations for the new fields. However, when I go to execute the revised create code, it fails because the SQL is wrong.
The error message complains that the author field doesn't have a default, which is true, I didn't assign a default. However, I did give it a value on the form. What perplexes me most is the SQL that it has generated: the column list doesn't show the two new columns. And that's not all: the values list is missing apostrophes around any of the string/text values. (All of the columns are defined as string or text.)
As I said, I'm completely new to Laravel so I don't know how to persuade Laravel to add the two new columns to the Insert statement nor how to make it put apostrophes around the strings in the values list. That hasn't come up in the course and I'm not sure if it will come up later. I was hoping someone could tell me how to fix this. All of my functionality was working fine before I added the two new fields/columns.
Here is the error message:
SQLSTATE[HY000]: General error: 1364 Field 'author' doesn't have a default value (SQL: insert into `articles` (`title`, `excerpt`, `body`, `updated_at`, `created_at`) values (Today in Canada, The ideal winter-beater, This car is the ideal winter-beater for the tough Canadian climate. It is designed to get you from A to B in style and without breaking the bank., 2020-02-15 17:37:54, 2020-02-15 17:37:54))
Here is ArticlesController:
<?php
namespace App\Http\Controllers;
use App\Article;
use Illuminate\Http\Request;
class ArticlesController extends Controller
{
public function index()
{
$articles = Article::latest()->get();
return view ('articles.index', ['articles' => $articles]);
}
public function show(Article $article)
{
return view('articles.show', ['article' => $article]);
}
public function create()
{
return view('articles.create');
}
public function store()
{
//Stores a NEW article
Article::create($this->validateArticle());
return redirect('/articles');
}
public function edit(Article $article)
{
return view('articles.edit', ['article' => $article]);
}
public function update(Article $article)
{
//Updates an EXISTING article
$article->update($this->validateArticle());
return redirect('/articles/', $article->id);
}
public function validateArticle()
{
return request()->validate([
'title' => ['required', 'min:5', 'max:20'],
'author' => ['required', 'min:5', 'max:30'],
'photopath' => ['required', 'min:10', 'max:100'],
'excerpt' => ['required', 'min:10', 'max:50'],
'body' => ['required', 'min:50', 'max:500']
]);
}
public function destroy(Article $article)
{
//Display existing record with "Are you sure you want to delete this? Delete|Cancel" option
//If user chooses Delete, delete the record
//If user chooses Cancel, return to the list of articles
}
}
Is there anything else you need to see?
It may be possible because of you don't have defined that column in fillable property, to use mass assignment you have to specify that columns.
Try after adding that columns in fillable property.
Laravel mass assignment
Hope this helps :)
in my controller i create an Eloquent Model Instance passign throug a relation. The model is loaded on controller's __construct, that's why is present a $this->store and not a $store.
public function index()
{
if (is_null($this->store->gallery)) {
$this->store->gallery()->create([
'title' => 'gallery_title,
'description' => 'gallery_description',
]);
}
$gallery = $this->store->gallery;
dd($gallery);
return view('modules.galleries.index', compact('gallery'));
}
Simply if a store's gallery is not present yet, let's create it.
The first time i print out my dd() is ALWAYS null, if i reload the page the dd() show correctly my gallery model.
The things is weird for me, seems like the first time the creation is done but not ready... I can work around but why this code doesn't work the first time?
Help is very appreciate.
Relationship codes: on gallery ....
public function store()
{
return $this->belongsTo(Store::class);
}
on store...
public function gallery()
{
return $this->hasOne(Gallery::class);
}
When using the $this->store->gallery()->create() method, the original method is not hydrated with the new value, you can simply do a
$gallery = $this->store->refresh()->gallery;
OR
$gallery = $this->store->load('gallery')->gallery;
if you want to make your code cleanner you can do that in your Store Model:
public function addGallery($gallery){
$this->gallery()->create($gallery);
return $this->load('gallery')->gallery;
}
And that in your controller:
$gallery = $this->store->addGallery([
'title' => 'gallery_title',
'description' => 'gallery_description',
]);
and voila ! You have your gallery ready to be used :)
It's the lazy load part of Eloquent. basicly, when you tested for it with is_null($this->store->gallery) it sets it to that value.
when you tried to recover it again, it did not do the DB query, it just loaded the value already present (null).
after creation you need to force reload the relation:
$this->store->load('gallery');
or
unset($this->store->gallery);
or
$gallery = $this->store->gallery()->get();
I am developing a Web Application using Laravel Nova. Laravel Nova is quite new. I am now having problem with database relationship and Fields. I like to ignore a field from database operations. This is my scenario.
In the Job resource, I have this fields method
public function fields(Request $request)
{
return [
ID::make()->sortable(),
Text::make('Name', 'name'),
Text::make('Email', 'email'),
Select::make('Contract Types')->options($array_of_options)//I want to ignore this field
];
}
As you can see, the last field is Contract Types.
When I create a new job from Dashboard, it is throwing error because there is no contract_types column on the Job model. I like to ignore that field from database operation. How can I get it?
The accepted answer is not completely correct. It prevents storing the value in the database but also completely hides the field in the form. In some weird cases you might want to show a field that is not stored.
My suggestion would be to add the following to the resource (or put in somewhere more re-usable if you want this in multiple resources):
public static function fill(NovaRequest $request, $model)
{
return static::fillFields(
$request, $model,
(new static($model))->creationFieldsWithoutReadonly($request)->reject(function ($field) use ($request) {
return in_array('ignoreOnSaving', $field->meta);
})
);
}
In the relevant field(s) you could than add:
->withMeta(['ignoreOnSaving'])
This will give you a field to fill without saving it in the model.
According to the docs https://nova.laravel.com/docs/1.0/resources/fields.html#showing-hiding-fields
Select::make('Contract Types')
->options($array_of_options)
->hideWhenCreating()
You can make an own custom handling of the Field data, just use fillUsing() method of the Field class. An example
public function fields(Request $request)
{
return [
ID::make()->sortable(),
Text::make('Name', 'name'),
Text::make('Email', 'email'),
Select::make('Contract Types', 'unique_key_for_model')
->options($array_of_options)
->fillUsing(function(NovaRequest $request, $model, $attribute, $requestAttribute) {
/*
$request->input('unique_key_for_model') // Value of the field
$model->unique_key_for_model // DOES NOT exists, so no errors happens
*/
// or just return null;
return null;
}),
];
}
I'm unsure of the best practice when inserting mass assignment relationships within Laravel 5.4 - I'm new to the framework. The below code is working correctly, however can you tell me is there a way to simply into one line (inserting relationships)?
I've tried to look at 'save()'and 'push()' but it's not working as expected. Would this have an impact if transactions would scale up?
I have a Listing model, with a hasOne relationship:
public function garage()
{
return $this->hasOne('App\Garage', 'post_id');
}
First of all I have some validation, then I use the following to store, which I want to simplify to one one line of code:
public function store(Request $request)
{
// Validation has passed, insert data into database
$listing = Listing::create($request->all());
$listing->Garage()->create($request->all());
}
Also if I wanted to return the data inserted, how would I do this as the following is only returning the Listing model and not the Garage relationship? Yes I know that I wouldn't do this in a real world application.
return \Response::json([
'message' => 'Post Created Succesfully',
'data' => $listing
]);
Any help is muchly appreciated
Method chaining
Your store method looks good. You could chain methods though, if you don't need the listing object itself:
public function store(Request $request)
{
// Validation has passed, insert data into database
$garage = Listing::create($request->all())
->garage()->create($request->all();
}
But if you need the listing object, it's fine as you did it before!
Returning relation models
If you want to return the garage relation model too, you can simply do that by accessing it like a normal class propery:
return \Response::json([
'message' => 'Post Created Succesfully',
'data' => [$listing, $listing->garage]
//Access collection of garage relation ship
]);