My controller looks like this:
public function show($id)
{
$model = MyModel::with([
'model2.model3.model4:id,value',
...
]);
if (myCondition) {
unset($model->model2->model3->model4);
$model->model2->model3->model4 = Model4::where('value', 'Some Value')->first();
}
return $audit;
}
In certain condition I'd like to override the result from the query with another value from the Model4 to return the good data to the client.
But I want to know if there is another way with laravel to do that. Actually I have to use unset and then push the new content if I want to change the value of the model4 property. If I don't use unset the object isn't changed, the value new value assigned to model4 is ignored I don't know why I can't just write this line
$model->model2->model3->model4 = Model4::where('value', 'Some Value')->first();
So I want to know why I can't see changes in my json object when I don't use unset and I want to know if there is anotehr way to deal with laravel for my situation ?
You can simply use setRelation method.
if ($myCondition) {
$model->model2->model3->setRelation('model4', Model4::where(...)->first());
}
I'm working with Laravel 5.8 and I have added this code to my Controller:
public function denyRequest($id)
{
$findRequest = WithdrawWallet::find($id);
$findRequest->status = 'cancelled';
$findRequest->save();
return redirect()->back();
}
And here is route for this:
Route::get('{id}','Wallet\WalletController#denyRequest')->name('denyRequest');
Now I get this error:
ErrorException (E_WARNING) Creating default object from empty value
Which is referring to this:
So what's going really wrong here? How to fix this issue?
When you search for existing Withdraw Wallet with an id that doesnt exist, it will return null. and since you assign 'cancelled' as an object attribute on the variable, php will convert $findRequest to a default object (StdObject::class) to be able to assign the attribute to it.
One simple solution would be to use findOrFail() instead of find() wich will trigger an exception when the id doesnt exist in your DataBase and return a 404 response on the request.
$findRequest = WithdrawWallet::findOrFail($id);
$findRequest->status = 'cancelled';
$findRequest->save();
return redirect()->back();
another suggestion (if you have soft delete on on the model and the id exists in the database) is to use withTrashed()
$findRequest = WithdrawWallet::withTrashed()->findOrFail($id);
$findRequest->status = 'cancelled';
$findRequest->save();
return redirect()->back();
Replace find with findOrFail:
$findRequest = WithdrawWallet::findOrFail($id);
I'm trying to call save method on an object of a Model Complaints Model to update a specific resource in Database but when I send a POST request on api url it gives this error
BadMethodCallException: Method Illuminate\Database\Eloquent\Collection::save does not exist.
I also tried calling update method but same error.
Code for edit:
$complaint = Complaint::where('complaint_id', $request->input('id'))->get();
$complaint->title = $request->input('Complaint_Subject');
$complaint->description = $request->input('Complaint_Details');
$complaint->address = $request->input('Complaint_Address');
$complaint->update();
return [
'save_status' => "success"
];
the very first line is returning the response and correct response.
AND
also I'm trying to call delete or destroy method to delete the resource but it also gives the same error
BadMethodCallException: Method Illuminate\Database\Eloquent\Collection::delete does not exist.
or
BadMethodCallException: Method Illuminate\Database\Eloquent\Collection::destroy does not exist.
Code for delete:
$complaint = Complaint::where('complaint_id', $request->input('id'))->get();
$complaint->destroy($request->input('id'));
return [
'request_status' => 'success',
'complaint' => $complaint
];
here also the response is being returned correctly.
Note that the complaint_id is not Primary Key in the table so I cannot simply call Complaint::find($request->input('id')) I must have to cross check with this complaint_id column value to find the resource. I have been searching since yesterday but could not find any solution. How can I solve this problem. Thanks!!!
If your $complaint is a collection of output. So save didn't work for this if you change your code like $complaint = Complaint::where('complaint_id', $request->input('id'))->first(); Then save() will work.
just use first() instead of get()
Complaint::where('complaint_id', $request->id)->first()
In your query
$complaint = Complaint::where('complaint_id', $request->input('id'))->get();
it returns Associative Arrays
But if you use
$complaint = Complaint::where('complaint_id', $request->input('id'))->first();
it returns Indexed or Numeric Arrays. Then you have to use $complaint[0]->destroy($request->input('id')); or $complaint[1]->destroy($request->input('id')); and so one
The title is mostly self-explanatory. Eloquent has a method called
updateOrCreate()
documented here: https://laravel.com/docs/5.5/eloquent#other-creation-methods
In some cases this is really useful. However after doing updateOrCreate() I need either the updated/created object or its primary key or its id.
Of course I could do MyModel::where(...)->first() and give all those data again but this is clumsy and may be some expensive request.
However updateOrCreate() only returns true or false.
Any ideas?
The method will return ID of created or updated object, so just do this:
$object = Model::updateOrCreate(['name' => 'John'], ['age' => 25]);
$id = $object->id;
Query for the last one
$lastRecord = MyModel::last();
Or
$lastRecord = MyModel::orderBy('id', 'DESC')->first();
Is it possible to update a user without touching the timestamps?
I don't want to disable the timestamps completly..
grtz
Disable it temporarily:
$user = User::find(1);
$user->timestamps = false;
$user->age = 72;
$user->save();
You can optionally re-enable them after saving.
This is a Laravel 4 and 5 only feature and does not apply to Laravel 3.
In Laravel 5.2, you can set the public field $timestamps to false like this:
$user->timestamps = false;
$user->name = 'new name';
$user->save();
Or you can pass the options as a parameter of the save() function :
$user->name = 'new name';
$user->save(['timestamps' => false]);
For a deeper understanding of how it works, you can have a look at the class \Illuminate\Database\Eloquent\Model, in the method performUpdate(Builder $query, array $options = []) :
protected function performUpdate(Builder $query, array $options = [])
// [...]
// First we need to create a fresh query instance and touch the creation and
// update timestamp on the model which are maintained by us for developer
// convenience. Then we will just continue saving the model instances.
if ($this->timestamps && Arr::get($options, 'timestamps', true)) {
$this->updateTimestamps();
}
// [...]
The timestamps fields are updated only if the public property timestamps equals true or Arr::get($options, 'timestamps', true) returns true (which it does by default if the $options array does not contain the key timestamps).
As soon as one of these two returns false, the timestamps fields are not updated.
Above samples works cool, but only for single object (only one row per time).
This is easy way how to temporarily disable timestamps if you want to update whole collection.
class Order extends Model
{
....
public function scopeWithoutTimestamps()
{
$this->timestamps = false;
return $this;
}
}
Now you can simply call something like this:
Order::withoutTimestamps()->leftJoin('customer_products','customer_products.order_id','=','orders.order_id')->update(array('orders.customer_product_id' => \DB::raw('customer_products.id')));
To add to Antonio Carlos Ribeiro's answer
If your code requires timestamps de-activation more than 50% of the time - maybe you should disable the auto update and manually access it.
In eloquent when you extend the eloquent model you can disable timestamp by putting
UPDATE
public $timestamps = false;
inside your model.
If you need to update single model queries:
$product->timestamps = false;
$product->save();
or
$product->save(['timestamps' => false]);
If you need to update multiple model queries use
DB::table('products')->...->update(...)
instead of
Product::...->update(...)
For Laravel 5.x users who are trying to perform a Model::update() call, to make it work you can use
Model::where('example', $data)
->update([
'firstValue' => $newValue,
'updatedAt' => \DB::raw('updatedAt')
]);
As the Model::update function does not take a second argument anymore.
ref: laravel 5.0 api
Tested and working on version 5.2.
I ran into the situation of needing to do a mass update that involves a join, so updated_at was causing duplicate column conflicts. I fixed it with this code without needing a scope:
$query->where(function (\Illuminate\Database\Eloquent\Builder $query) {
$query->getModel()->timestamps = false;
})
For Larvel 5.1, you can also use this syntax:
Model::where('Y', 'X')
->update(['Y' => 'Z'], ['timestamps' => false]);
Laravel 9 and above
Taken directly from the documentation.
If you would like to perform model operations without the model having its updated_at timestamp modified, you may operate on the model within a closure given to the withoutTimestamps method:
Model::withoutTimestamps(fn () => $post->increment(['reads']));
So in OP's case, the code will be something like this:
User::withoutTimestamps(function () {
$user = User::find(1);
$user->name = 'John';
$user->save();
});
Laravel 8
Doing some overrides using seeders and on one test I have:
$item = Equipment::where('name', item_name))->first();
$item->description = 'some description';
$item->save(['timestamps' => false]);
Which works fine, but if I use firstOrNew then the $item->save(['timestamps' => false]); does not work.
// This does not work on Seeder file
$item = Model::firstOrNew(['name' => 'item_name']);
$item->description = 'some description';
$item->save(['timestamps' => false]);
// Doing the following works tho
$item = Model::firstOrNew(['name' => 'item_name']);
$item->description = 'some description';
$item->timestamps = false;
$item->save();
So in some cases you would use one over the other... Just check with die and dump to see whether +timestamps: false
$item->timestamps = false;
$item->save();
or
$item->save(['timestamps' => false]);
Edit:
In my project I opted using $item->timestamps = false; so I would recommend using this as well. Here is a working snippet from laravelplayground:
https://laravelplayground.com/#/snippets/4ae950f2-d057-4fdc-a982-34aa7c9fee15
Check the HasTimestamps on Laravel api:
https://laravel.com/api/8.x/Illuminate/Database/Eloquent/Concerns/HasTimestamps.html
and the save method on Model:
https://laravel.com/api/8.x/Illuminate/Database/Eloquent/Model.html
The save method still accepts options but passing timestamps will not work.