Not able to call SAVE method on Model object Laravel - php

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

Related

Laravel 5.8: Creating default object from empty value

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

Can't set new value to Model's property

I am trying to set new value to Model's property but it's not working. I am using dd() right after I set the new value but it keeps the old value.
$business->users()
->where('userable_id', $business->id)
->where('userable_type', 'App\Models\Business')
->first()->first_name = "New";
Try this instead:
$business->users()
->where('userable_id', $business->id)
->where('userable_type', 'App\Models\Business')
->first()->update(['first_name' => "New"]);
Direct object property assign like $model->attribute = 'foo'; affects only in-memory state and doesn't make changes in the database.
So you want to go either
$model->update(['attribute' => 'value']);
or
$model->attribute = 'value';
$model->save();
Reference
Update 1:
as I've written in the comments to my answer, first() might return null sometimes if no one model was found. I'd like to advice firstOrFail() instead.
Note, that there is no predefined handler for ModelNotFound exeption (thrown by firstOrFail()), so you'd like to handle such error manually in Handler class, otherwise you'll get default 404 Laravel page.
$business->users()
->where('userable_id', $business->id)
->where('userable_type', 'App\Models\Business')
->first()->update(['first_name' => 'New']);
To access a method/field right after the ->first() method is a very bad practice.
If no model is found, PHP will raise an error because you are trying to access method/property on a null value.
Use instead
$user = $business->users()
->where('userable_id', $business->id)
->where('userable_type', 'App\Models\Business')
->first();
$user->first_name = 'New';
$user->save();
// or, if 'first_name' is in your model $fillable array
$user->update(['first_name' => 'new' ]);

Eloquent / Laravel: How to get last insert/update ID/instance of updateOrCreate()?

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

Laravel model mock

I am trying to mock a model and return false on insert so i can test failure case.
here is my test mocking
$mockModel = Mockery::mock(\App\Models\MyModel::class)->shouldReceive(['insertGetId'])->once()->andReturn(false);
and here is my insert method in controller
$result = MyModel::insertGetId(['something' => 'somevalue',]);
dd($result);
and i am expecting $result to be false but instead i get the id (int).
if i remove dd(); i get this error on the terminal.
Mockery\Exception\InvalidCountException: Method insertGetId() from Mockery_0_App_Models_MyModel should be called
exactly 1 times but called 0 times.
You are using insertGetId() which returns the inserted id. Use insert() instead.
If the table has an auto-incrementing id, use the insertGetId method to insert a record and then retrieve the ID like:
$id = DB::table('users')->insertGetId(
['email' => 'john#example.com', 'votes' => 0]
);
but in case of insert it return true or false based on success or failure of query.

Laravel 5 - Updating associated models using push()

I am trying to do this:
$volunteer = Volunteer::with('user')->find($id);
$input = $updateVolunteerRequest->all();
$volunteer->fill($this->fillFields($input));
$volunteer->user->fill([
'email' => $input['email']
]);
$volunteer->push();
But push() method does not seem to work.
It throws the following error:
FatalErrorException in Model.php line 1463:
Call to a member function push() on a non-object
It worked in Laravel 4. Is there a new way of doing this in version 5? Or am I doing something wrong.
I checked $volunteer and it returns the model.
The push method loops through all of the loaded relationships on the model and calls push on them, as well. So, it isn't the push on the $volunteer that's failing, it is a push on a related model that is failing.
In Laravel 4, push has the following code:
foreach ($this->relations as $models)
{
foreach (Collection::make($models) as $model)
{
if ( ! $model->push()) return false;
}
}
In this code, if the relationship returned a NULL, there would be no error. Collection::make(NULL) returns an empty array, so the foreach would never execute. However, in Laravel 5, push has this code:
foreach ($this->relations as $models)
{
$models = is_array($models) ? $models : array($models);
foreach ($models as $model)
{
if ( ! $model->push()) return false;
}
}
In this case, if the relationship is null, there will be an error, since array(NULL) returns an array with one entry: the NULL value. So, the foreach loop will execute, and it will try to call push on the NULL value, resulting in your Call to a member function push() on a non-object error.
So, it looks like this is a bug in Laravel 5.
Edit
It looks like the push() method was updated because of an update made to the Collection object. I have submitted a pull request to correct the issue. You can check out the pull request here, which also contains links to reported issues and other background information.
Edit 2
My pull request was merged in, so you should be able to update your Laravel 5 to the newest version and the issue should be corrected.

Categories