How to ignore field from database operation in Laravel Nova - laravel

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;
}),
];
}

Related

Laravel Nova action models empty

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

Laravel - How to change response format for specific fields

I've "Product" model.
And need to change some value formats for only responses.
For example;
I've "price" on database as decimal (11,2).
I want this as "1.000.000,00" format on response.
Or created_at field to "Carbon::parse($this->created_at)->toDayDatetimeString()"
Or I want to add 3 specific columns with my user attribute, on response. (is_allowed etc.)
How can this be possible on model?
How can I response like that?
You can use Mutator and Accessor to set format :
https://laravel.com/docs/8.x/eloquent-mutators#accessors-and-mutators
public function setDateAttribute($date) {
$this->attributes['date'] = Carbon::createFromFormat('Y-m-d', $date);
}
public function getFirstNameAttribute($value)
{
return ucfirst($value);
}
As a best practice in Laravel you can use Eloquent Resources: Eloquent Resources
It's basically a "transformer" between models data and API/Responses Output.
The only one thing to notice is that in the Resource files yout must specify all fields and relations (if needed) of the Model manually.
In the toArray() function you can modify the type of all data of your model as you prefer.
If not, you can access the new field by $model->my_custom_field (Laravel can resolve the name of the getter function automatically).
public function toArray($request)
{
$editedFieldValue = doSomething();
return [
'my_field' => $editedFieldValue,
'other_field' => '',
];
}
If you want to do that in Model, you can create customs fields:
class MuModel extends Model
{
protected $appends = ['my_custom_field'];
public function getMyCustomFiledAttribute(){
$newData = doSomething($this->existent_field);
return $newData;
}
}
The $appends variable add the new fields to all responses generated from the Model, as a normal database field.
P.S.: You can create a getAttribute() function for existent database attribute and return the value as you want!
For example: getCreatedAtAttribute()

laravel 5.6 Eloquent : eloquent relationship model creation issue

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();

Laravel 5.4 storing mass assignment model and relationship

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
]);

exclude certain records from laravel scout/algolia

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)

Resources