Laravel Eloquent - $fillable is not working? - laravel

I have set the variable $fillable in my model. I wanted to test the update functionality, and I get this error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column '_method' in 'field list' (SQL: update positions set name = Casual Aquatic Leader, _method = PUT, id = 2, description = Here is my description, updated_at = 2014-05-29 17:05:11 where positions.client_id = 1 and id = 2)"
Why is this yelling at _method when my fillable doesn't have that as a parameter? My update function is:
Client::find($client_id)
->positions()
->whereId($id)
->update(Input::all());

Change following:
->update(Input::all());
to this (exclude the _method from the array)
->update(Input::except('_method'));
Update:
Actually following update method is being called from Illuminate\Database\Eloquent\Builder class which is being triggered by _call method of Illuminate\Database\Eloquent\Relations class (because you are calling the update on a relation) and hence the $fillable check is not getting performed and you may use Input::except('_method') as I answered:
public function update(array $values)
{
return $this->query->update($this->addUpdatedAtColumn($values));
}
If you directly call this on a Model (Not on a relation):
Positions::find($id)->update(Input::all());
Then this will not happen because fillable check will be performed within Model.php because following update method will be called from Illuminate\Database\Eloquent\Model class:
public function update(array $attributes = array())
{
if ( ! $this->exists)
{
return $this->newQuery()->update($attributes);
}
return $this->fill($attributes)->save();
}

write a parent class
class BaseModel extends Model
public static function getFillableAttribute(Model $model, $data){
$array = $model->getFillable();
$arr = [];
foreach ($array as $item){
if( isset($data["$item"])){
$arr["$item"] = $data["$item"];
}
}
return $arr;
}

I experienced this breaking after updating from Laravel 5.2 to 5.4 - I can't find anything in the documentation / migration guide that covers it.
As covered in this github issue the correct fix/use of Eloquent seems to be:
Positions::find($id)->fill(Input::all())->save();
To trigger the fillable check by laravel and then perist the changes.

You could also do this
$data = request()->all();
//remove them from the array
unset($data['_token'],$data['_method']);
//then
Client::find($client_id)
->positions()
->whereId($id)
->update($data);
This removes the _method and _token from the array

Related

Laravel 8 - I have an error in when using method in Model when using paratheses with the method

I have two models [The relation is one-many / Category-Trip]:
Category Model Code:
class Category extends Model
{
use HasFactory;
protected $fillable = [
'id',
'category_name',
'category_desc',
'category_img',
];
public function trip() {
return $this->hasMany(Trip::class);
}
}
Trip Model Code:
class Trip extends Model
{
use HasFactory;
protected $fillable = [
'name',
'description',
'max_visitors',
'price',
'date',
'image',
'guide_id',
'category_id',
];
public function category()
{
return $this->belongsTo(Category::class);
}
}
when I use this code, I will get this error:
TypeError Symfony\Component\HttpFoundation\Response::setContent():
Argument #1 ($content) must be of type ?string,
Illuminate\Database\Eloquent\Relations\BelongsTo given, called in
C:\Users\Orange\Desktop\ON
GITHUB\Tours-Booking\vendor\laravel\framework\src\Illuminate\Http\Response.php
on line 72
$trip = Trip::findOrFail(1);
return $trip->category();
But when write this without paratheses, i will not get this error, what is the problem?
$trip = Trip::findOrFail(1);
return $trip->category;
As a user explained (but not fully):
You are returning a relationship in your controller, but that is not valid (based on the error). Because BelongsTo cannot be serialized to a string, it tries to return the BelongsTo object, hence giving you that error (look, it is saying it is wanting null or a string, but you are returning BelongsTo).
When you do $model->relation (without ()), that means it will try to get all the data that satisfies the relation and store it as a Category in $model->relation (because it is a BelongsTo), but when you use $model->relation() you creating a query so you can query the relation with whatever you want/need, like $model->relation()->where('status', 'Active')->get()...
You have 2 solutions: either return $trip->category (it is going to be a Category object/model) or $trip->category()->get() or any query but use ->get() (will return a Collection) or ->first() (will return a Category model) at the end...
Read the documentation again so you understand better now: Relationships and First vs Get and BelongsTo documentation.
When you call the method its instantiating a eloquent instance in which you can extend it to a query which will give you a Category model
example (this might not be the most appropriate example)
$trip = Trip::findOrFail(1);
return $trip->category()->where('category_name', 'something')->first();
And the latter returns a collection.

How to use Model in function parameter to reduce code in laravel?

This is how i am trying to update record in my laravel function which doesn't work
public function completePacking(SaleOrder $saleOrder)
{
$saleOrder->update(['status' => 'Draft']);
}
it is working
public function completePacking($id)
{
$saleOrder = SaleOrder::findOrFail($id);
$saleOrder->status = 'Dispatched';
$saleOrder->save();
}
i want to use first method because it is less code but that is not working
Add 'status' to your $fillable attribute in your SaleOrder model.
Or remove 'status' from $guarded attribute in SaleOrder model.
After doing any of the following, you would be able to use your desired version to update status.
Read more on https://laravel.com/docs/5.7/eloquent#mass-assignment
$saleOrder = SaleOrder::where('id', $id)->update(['status' => 'Draft']);

Laravel Eloquent Save doesn't save

I am trying to save survey answers in my db, because of some to me unknown reason the ->save() method is not working, ->update() is working however.
I keep getting the error Array to string conversion every time I try to save.
I have used dd/return/var_dump/print_r whatever would work, to show that it was working up to that step. So now I know it works up to the ->save() method.
My controller:
$array = json_decode($request->getContent(), true);
foreach ($array as $survey) {
$objAns = new Survey_Answer();
$objAns->name = $survey['surveyName'];
$objAns->answers = $survey['answersPerQuestion'];
if($survey['complete'] === true) {
$objAns['complete'] = 1;
} else if($survey['complete'] === false) {
$objAns->complete = 0;
}
$objAns->save();
}
return;
My model:
class Survey_Answer extends Model
{
protected $fillable = ['name', 'answers', 'complete'];
}
My migration:
public function up()
{
Schema::create('survey__answers', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('survey_id')->unsigned()->nullable()->index();
$table->foreign('survey_id')->references('id')->on('surveys')->onDelete('cascade');
$table->string('name');
$table->json('answers');
$table->boolean('complete');
$table->timestamps();
});
}
I expect the code to save everything that I send along with the $request. This only results in a error: Array to string conversion.
Thank you very much for your help
You need to store your $survey['answersPerQuestion'] in json format not as an array.
$objAns->answers = json_encode($survey['answersPerQuestion']);
Although as #Lucas Arbex pointed out in the comments, there's certainly a better way to store it.
I would suspect that $survey['answersPerQuestion'] is an array but you are trying to store it in a json column.
You can use Laravel's Array & JSON Casting to cast the array to a json string.
The array cast type is particularly useful when working with columns
that are stored as serialized JSON. For example, if your database has
a JSON or TEXT field type that contains serialized JSON, adding the
array cast to that attribute will automatically deserialize the
attribute to a PHP array when you access it on your Eloquent model:
Your Model:
class Survey_Answer extends Model
{
protected $fillable = ['name', 'answers', 'complete'];
protected $casts = [
'answers' => 'array',
];
}
Once the cast is defined, you may access the options attribute and it
will automatically be deserialized from JSON into a PHP array. When
you set the value of the options attribute, the given array will
automatically be serialized back into JSON for storage:
$user = App\User::find(1);
$options = $user->options;
$options['key'] = 'value';
$user->options = $options;
$user->save();

Why eloquent doesn't return error on diffrent primarykey?

I was working on an old database which primarykey is 'Id'. Eloquent set up the primary key to default 'id', so it is little change, but still can be confusing. Of course I didnt notice that, and I wanted to save updated models to database. There was no error, and $model->save() return was good but database didn't update. Furthermore I have other functions that get models from the database, and they work as they should without overriding $primarykey.
So here is my question: Why isn't eloquent returning any warnings or errors ? Of course I found in the documentation that I should override $primarykey in the model, and then everything worked perfectly.
I was using MySql 10.1.16-MariaDB.
Here is Laravel controller
public function update(Request $request, Order $order)
{
$order->fill($request->get('data'));
$order->save();
$order->products;
return $order;
}
Vue.js function
editOrder () {
this.fullscreenLoading = true
axios.put('/web/' + this.url + '/' + this.rowId, {'data': this.row})
.then(({data}) => {
this.row = data;
this.fullscreenLoading = false
});
},
Laravel Model was standard, of course my model is now properly updated, when i got this problem there was no $primarykey, I didnt mention $fillable and relationship to products but in my project they are defined and working.
class Order extends Model
{
use LogsActivity;
protected $table = 'orders';
protected $primaryKey = 'Id';
protected $fillable = []
}
If you execute the query with get(), create() or similar method, it will work as before because Eloquent doesn't use PK in this case. But some methods like find() will not work for you until you setup $primaryKey property in the model.
You didn't get an error because there was no error.
When you ran $order->save(), the query generated would have been something like:
update `orders` set `field1` = ?, `fieldN` = ?, `updated_at` = ? where `id` is null
This is a perfectly valid SQL statement, and when it runs, it would produce no errors. However, it will also not update any records (unless you do have a record where the id is null).
The reason why the update query is using null is because your Order model does not have an id attribute, it has an Id attribute, and PHP array keys are case-sensitive. So, when Laravel attempts to get the value for the id attribute, it returns null, and uses that in the query.

How to update field when delete a row in laravel

Let I have a table named customer where customer table has a field named deleted_by.
I implement softDelete in customer model. Now I want to update deleted_by when row delete. So that I can trace who delete this row.
I do search on google about it But I don't found anything.
I use laravel 4.2.8 & Eloquent
You may update the field using something like this:
$customer = Customer::find(1); // Assume 1 is the customer id
if($customer->delete()) { // If softdeleted
DB::table('customer')->where('id', $customer->id)
->update(array('deleted_by' => 'SomeNameOrUserID'));
}
Also, you may do it in one query:
// Assumed you have passed the id to the method in $id
$ts = Carbon\Carbon::now()->toDateTimeString();
$data = array('deleted_at' => $ts, 'deleted_by' => Auth::user()->id);
DB::table('customer')->where('id', $id)->update($data);
Both is done within one query, softDelete and recorded deleted_by as well.
Something like this is the way to go:
// override soft deleting trait method on the model, base model
// or new trait - whatever suits you
protected function runSoftDelete()
{
$query = $this->newQuery()->where($this->getKeyName(), $this->getKey());
$this->{$this->getDeletedAtColumn()} = $time = $this->freshTimestamp();
$deleted_by = (Auth::id()) ?: null;
$query->update(array(
$this->getDeletedAtColumn() => $this->fromDateTime($time),
'deleted_by' => $deleted_by
));
}
Then all you need is:
$someModel->delete();
and it's done.
I would rather use a Model Event for this.
<?php
class Customer extends \Eloquent {
...
public static function boot() {
parent::boot();
// We set the deleted_by attribute before deleted event so we doesn't get an error if Customer was deleted by force (without soft delete).
static::deleting(function($model){
$model->deleted_by = Auth::user()->id;
$model->save();
});
}
...
}
Then you just delete it like you would normally do.
Customer::find(1)->delete();
I know this is an old question, but what you could do (in the customer model) is the following....
public function delete()
{
$this->deleted_by = auth()->user()->getKey();
$this->save();
return parent::delete();
}
That would still allow the soft delete while setting another value just before it deletes.

Resources