Laravel including "appends" attribute while creating new resource - php

I am using appends attribute of laravel model 'Contact' to return a custom field 'image_url' with json response.
I also made an accessor getImageUrlAttribute for it.
All working fine except create method. I am using
Contact::create(Input::except('_token');
Its raising an exception "Unknown column image_url in field list". This image_url field is what I am using as append and added to $append array of Contact model.
protected $appends = ['image_url'];
So its adding this custom attribute while creating a new resource. I googled a lot about this but all I got is how to use it to append extra attributes while fetching data. Is there any way to get around this?

Related

Laravel replace variable on Model

I would like to be able to override a variable on the model, so that a normal field is instead replaced by a relationship's field, i.e.
Where product.image might normally be a field, I want to run a function which will go through all of the resulting products from a query and replace the image field with something like the following --
(Product.php) Model
...
public function variantImages(){
return $this->image = $this->variants()->first()->pluck('image_url');
}
...
So the default product image field is replaced by the "first product variant's image". I don't want to do this in a collection once I have already got the data, the problem here is being able to do this at a Model level.
Is there a way to do this within a scope?
You can create an accessor instead of a normal function:
// Singular because it only gets one
public function getVariantImageAttribute(){
return $this->image = $this->variants()->first()->pluck('image_url');
}
This will make it available under $product->variant_image
Then you can ensure it is always appended to your model (if you want) by adding it to the appends e.g.:
$appends = [ 'variant_image' ];
Since this is not the best idea since it will force load the relationship every time you get a product (even if you didn't request it) you can conditionally control when to append it via e.g.:
return response()->json($product->append('variant_image'));
Note that the append method also works for collecitions of eloquent models.

Laravel fill not setting component property

I have run into an issue with Laravel that hopefully someone could help explain. The fill command is not setting the properties of the model, and instead can only be used to save them to the database with the ->save() function. Is there a way to do fill where it actually sets the properties of the model from an array.
Example of problem below.
$comment = new comment();
$comment->fill(['name' => 'Bob']);
echo($comment->name); // Gives null/error.
$comment = new comment();
$comment->name = 'Bob';
echo($comment->name); // Gives Bob.
The reason is name filed is not fillable in comment model .To Solve this issue you have to add fillable for that field in comment model
protected $fillable = [
'name',
];
If you try to access non fillable field then it will return null.
If don't want to add it in fillable then you can use forceFill.
forceFill: Fill the model with an array of attributes with force mass assignment.
$comment = new comment();
$comment->forceFill(['name' => 'Bob']);
echo($comment->name);
Yes, you need to use fillable property of the model and need to add name inside fillable array. That's the recommended way to do it.
As suggested by John Lobo's answer, You can forcibly override that mechanism using forceFill or forceCreate.
Both ignores fillable property in the model. It may possible that you may have a column like is_admin and you do not want to update it but force will do it.
Notes :
The main problem with forceCreate or forceFill, is that we have to manage the foreign key assignment manually.
forceFill will do fill (properties) only. You need save method call to save the actual record while forceCreate will do fill (properties) and Save both together.

Laravel - Store new record in database through API

I want to create a new record in my database through the API but i get the error "message": "Array to string conversion (SQL: insert into....) from Postman
API Route:
Route::post('/posts','PostController#store');
The store function in my controller:
public function store(Request $request)
{
$post= new Post;
$post->all = $request->all();
$post->save();
}
First, check your post#all field type. If it a database field - you can set only data of the same type, for example for string type you can set only php string.
If it is not a filed but you want to set all attributes from request to model, you can do it with Model::create($request->all()).
However, before doing so, you will need to specify either a fillable
or guarded attribute on the model, as all Eloquent models protect
against mass-assignment by default.
Source - Mass Assignment
In other words to may define a property in model fillable which will be an array and contains fields that will be mass assignable (in your way - fields from request).
It might be better to use $request->only() and provide only the data you want to take out of the request, which will reduce the possibility of user errors causing you a problem, as $request->all() will include any input data, including the query string.

How to add value of guarded fields in database

I am using laravel 5.3 and in my custom model, I have some guarded fields like following.
protected $guarded = ['id', 'tnant_id', 'org_id', 'fac_id', 'slug', 'created_at', 'updated_at', 'deleted_at'];
Now When I try to add record using following.
CUSTOM::create(['tnant_id'=>123]);
It returns me following error.
Field 'tnant_id' doesn't have a default value.
Setting field default value in table will not work because each time I am passing value and it is giving error for all guarded fields.
So how I can add guarded fields value in database? In update query, It is allowing to update but on create it gives error.
You simply can't. Model::create(array $attributes = []) is using method fill(array $attributes = []), which, we may say, filter out all guarded attributes, so they will not be assigned. So in point of creation tnant_id will be null.
I come up with two ways of doing this:
A
create a new model instance
set your attribute
save (persist) it to dabase;
So:
$model = new Model;
$model->tnant_id = 123;
$model->save();
B
This is more likely update than create, but, might be useful for you.
Change your DB schema to allow null values for your attribute or put default value.
create model using Model::create()
set attribute & update.
So:
Assuming you are using migrations, in your migration file use:
Schema::create(..
$table->integer('trant_id')->nullable();
//OR
$table->integer('trant_id')->default(0);
...);
Note: It's hard to say which one is more suitable for you use-case, but I see your attribute is called trant_id, which is some form of relation I guess, so I suggest you to take look at Eloquent's relationship, which might be a better answer.

Is possible get olny form fields have Similar Name of model properties in update method of resource controller

I have a Course Model that have many fields like this :
course_id
title
description
creator
start_date
end_date
reg_start_date
reg_end_date
picture
lesson_count
cost
status
active
teacher
created_at
updated_at
deleted_at
And I have a Form to edit a specified Model. action attribute of the edit form tag is referenced to course.update route.
In the edit Form,in addition to fields with same names of above Model properties, there are many other form fields that not related to Course Model (and used for manyTomany relations or other operations)
Now in public update method , when I want to use Eloquent update() method , Since the number of irrelevant field names are many, I must to use except() method for incoming request. like this :
public
function update (StoreCourseRequest $request, $id)
{
$data = $request->except(['search_node', '_token', 'start_date_picker', 'end_date_picker', 'reg_start_date_picker', 'reg_end_date_picker', 'orgLevels', 'courseCats','allLessonsTable_length']);
$course = Course::findOrFail($id);
$course->update($data);
$course->org_levels()->sync($request->get('orgLevels'));
$course->course_categories()->sync($request->get('courseCats'));
$result = ['success' => true];
return $result;
}
As you see on usage of $request->except() method, I passed many field names to it to filter only proper attributes for use in $course->update($data);.
Now my Question is that Are there any way that we can get only same name model attributes from a field name?
If I understand your question correctly you are trying to avoid having to use the except() method for incoming requests, correct?
If that is the case, you can just skip it altogether and pass the entire request to the update() method as it will only update matching fields (provided they are listed as "fillable" in the method class). This process is called "mass-assignment".

Categories