Why Laravel/Eloquent single object save() updates multiple records - laravel

I'm fetching a specific record with a DB table using
$myTableObj = MyTable::where(['type' => $sometype])->first();
Getting it successfully, updating some fields and saving with
$myTableObj->save();
Surprisingly, this record is updated along with another record that also has 'type' = $sometype. What can be done to prevent this?
NOTE: originally the table did not have the auto increment id field, but I have read in forums that it may make problems in Laravel so I did add it, which did not solve the problem.

Method save() working with 'id' filed only.
You can try this
$myTableObj = MyTable::where(['type' => $sometype])->update(['something' => 'value']);
Source

I understand update() is to update, but, my answer works fine and fits good for update too. Its useful where you dont want columns to be defined once again for update, (sp when they are not fillable, its tested with primary key as condition)
$myTableObj->save(); basically its for saving new record, if you want to update that row you can update like below code:
$myTableObj=new MyTable;
$myTableObj->exists=true;
$myTableObj->type=$sometype;//this is your condition, identify
$myTableObj->update();
I think what's happening here is Laravel is saving as well as updating row.

Related

when using laravel scout, searchable() isn't updating related models

I am having an issue getting related models to update with scout elastic search.
$event->priceranges()->delete();
$event->priceranges()->Create([
'price' => $ticket['ticket_price']
]);
$event->update([
'show_times' => $request->showtimes,
]);
$event->searchable();
In my database I see the event and price range tables update. However when I look at my elastic search data, only data on the event has been updated. Any related models are not updated.
If I make a second update to the model and price range model, then the elastic search data shows my data from the first update I made (it is always one update behind for related models)
I tried doing
$event->pricerange->searchable()
but gives me an error because I don't have a searchable index for pricerange, I am just using my event model and its relationship to index. Is there a way to force the update other than searchable()?
Looks like your relationship is being indexed in the Event model index, correct?
Probably it's not being updated because the relationships are already loaded, and Laravel doesn't update the relationship data that is already loaded, for example:
$event = Event::with('priceranges')->first()
var_dump($event->priceranges->count()): // outputs for example 5
$event->priceranges()->create([...]);
var_dump($event->priceranges->count()): // still outputs 5, meaning that the created pricerange is not loaded
So, to fix this issue you can reload the model before calling searchable():
$event = $event->fresh();
$event->searchable();
But, note that everytime you update, the searchable method is already being called, so you will be indexing it two times on every update.
So, alternatively you can update your toSearchableArray() method in Event model to get a fresh model before returning the data (I'm assuming that you are using the babenkoivan/scout-elasticsearch-driver).

How to undo database after update in laravel?

I have two buttons, updates and undo. For example, after I update the new database, I want to undo it back to the original. I can only execute the update button.
function update(Request $req)
{
$id = $req->contact_id;
$contract = Contacts::find($id);
$contract->area_id = $req->areas;
$contract->code = $req->code;
$contract->created_at = $req->sign_in;
$contract->value = $req->total;
$contract->save();
return redirect('contact/'.$id)->with('message', 'Update successful !!');
}
To do that you must keep somewhere your old record before you update.
There is no "undo" so don't think it like that. You basically want to update the table with the old values.
Since as you said you have 2 buttons which one of them is the update which updates the current record what you can do, to make undo possible is that you have another table like records which you are going to fill in every update.
So according to your code the field contact_id seems like the unique identifier for each contract. Before you update then with the new values you can use a select like:
$oldRecord = DB::table('my_main_table')
->where('id', $req->contact_id)->first();
Inside your $oldRecord variable is stored all the info of your record that you want to update but is not yet updated , so it's your old record. Having that you can just hit an insert query to the records table i mentioned before so you can keep your "older version" there in case you want to undo.
So the undo functionality will just be the same logic. Select the record with the specific contract_id but this time from the records table and just update your main table.
I don't know if I fully got your question, but as long as you haven't called the save() method on your model, you can use
$eloquentModel->getChanges()
to list all attributes you did already change.
You can retrieve original attribute values by calling
$eloquentModel->getOriginal();

facade.edit does not change the database

I am working on a JSF project that deals with MySQL DB.
in my backbean method I did:
entityFacade.edit(entity object);
after that I wanted to make sure of the changes, I queried my database to retrieve the edited record, However, the retrieved values are the old ones. it is like entityFacade.edit(entity object); was not made.
I solved this problem by doing this
entityFacade.remove(entity object);
entityFacade.create(entity object);
But the problem is that the object has ID which is auto-increment & I want to keep the old ID.
I don't get why the edit does not change values. what are the possible causes of this problem?
Looking forward to your answers, experts.
For those who are facing the same problem, I solved it as follows:
The problem was not with the facade.edit()
it was with the queries.
Try facade.find(id) to retrieve the records from the database instead of queries. The retrieved records will show the edited data.

Algolia Update Index On Relational Database change with Laravel Scout

I have implemented Aloglia for my Movies table with actors as relational table and it works fine.
Problem:
When I update any movie its also updating algolia index (its good). But how can I update index if I made any change in relational table (for example update an actor of movie).
How to push a specific record manually with laravel scout.
Thanks
The issue itself lies in laravel's events. Whats happening is scout is listening for an 'updated' event which only occurs in laravel when the model object is saved and is dirty (aka value differ from that in the db).
There are two ways you can do this.
The bad lazy way would simply be to add ->touch() to the model prior to save - this will force the updated_at field to update and ultimately trigger the updated event. This is bad as you're wasting a DB query.
The second and preferable way is to register another observer on 'saved' which triggers regardless of whether or not the object is dirty. Likely you either want to check if the model is dirty and only index when its not (to prevent double indexing from the updated event) or just de-register the 'updated' listener that comes in Scout.

Laravel 4 - how to use a unique validation rule / unique columns with soft deletes?

Assume, you are trying to create a new user, with a User model ( using soft deletes ) having a unique rule for it's email address, but there exists a trashed user within the database.
When trying to validate the new user's data, you will get a validation error, because of the existing email.
I made some kind of extra validation within my Controllers, but wouldn't it be nice to have it all within the Model?
Would you suggest creating a custom validation rule?
As I haven't found a clean solution now, I am interessted in how others solved this problem.
You can validate passing extra conditions:
'unique:users,deleted_at,NULL'
This sounds like an issue with your business logic rather than a technical problem.
The purpose of a soft delete is to allow for the possibility that the soft-deleted record may be restored in the future. However, if your application needs uniqueness of email (which is completely normal), you wouldn't want to both create a new user with that email address and be able to restore the old one as this would contravene the uniqueness requirement.
So if there is a soft deleted record with the email address for which you are adding as a new record, you should consider instead restoring the original record and applying the new information to it as an update, rather than trying to circumvent the uniqueness check to create a new record.
This is the best approach
'email' => 'required|email|unique:users,email,NULL,id,deleted_at,NULL',
It give you this query
select count(*) as aggregate from `users` where `email` = ? and `deleted_at` is null
Laravel offers "Additional Where Clauses".
My url validation rule (from the update model method) looks like this:
$rules['url'] = 'required|unique:pages,url,'.$page->id.',id,deleted_at,NULL';
This means that the url must be unique, must ignore the current page and ignore the pages where deleted_at id not NULL.
Hope this helps.
Your Eloquent model should have the $softDeletes property set. If so, then when you perform a WHERE check, like User::where('username', 'jimbob'), Eloquent will automatically add in the query WHERE deleted_at IS NULL... which excludes soft deleted items.
In laravel 6.2+ you can use
'email' => ['required', Rule::unique('users')->whereNull('deleted_at')]

Resources