Triggering Laravel observers on multiple records - laravel

I have been using Laravel Observers to handle my app logic whenever my models get deleted/updated/saved. I noticed in some cases these observers don't get triggered. For example if I use
Model::where(active,1)->update([some stuff]);
the observers never get triggered. It is very annoying to have to fetch all records and run a forloop on each instance and call update. Is there a way around this or are there any good practices to handle these scenarios?

When you do this:
Model::where(active,1)->update([some stuff]);
Query Builder's update() method is executed instead of Eloquent's update() method.
If you want to trigger Eloquent events, you need to update rows one by one.

Events and listeners instead? You can run the update either raw or query builder, pass those effected rows in the event.

Related

Laravel eloquent doesn't insert data when bug occur during multiple insert

I'm trying to insert users using csv.
My model has an observer on "created" event.
However I can have a bug after some $users->save() because of code in my function created event (which I fixed).
The code in created event send an email to the user. The problem is if code crash after 5iterations, I got my 5emails send but no user in my db.
I'm wondering if Eloquent use transaction when you call multiple times save() ?
If yes how to force Eloquent to really save my object after each end of event created ?
May be I'm misunderstanding something with event, because I don't see the point of using this event if your not sure to have your model insert in your DB.
Finally found what was wrong...
To insert csv my project use :
https://github.com/Maatwebsite/Laravel-Excel
And after some research, this is "why" eloquent use transaction in my case :
https://docs.laravel-excel.com/3.1/imports/validation.html#database-transactions

How to display in blade which rows are soft deleted?

I have created a polling system and in the backend (CMS area) I want the ability for admins to be able to remove polls. When an admin removes a poll, it should soft delete the poll. This is working as intended, however I also want to have the ability for the admin to be able to restore a poll. To do this I am displaying all of the polls (including the soft deleted polls) in the admin area.
PollController index() to get all polls
$polls = Poll::withTrashed()->get();
In the blade I want to have two different buttons for each poll. One of restoring and one for deleting but I only want to display 1 button for each poll depending on whether it can be restored or deleted.
To do this, I have put this inside the foreach in the blade:
#if($poll->trashed())
// Restore button
#else
// Delete button
#endif
However the issue is, trashed() keeps returning true for all the polls when only 1 out of the 3 polls I have are actually soft deleted. I am unsure as to why trashed() returns all of these are true?
How would I get this method working correctly? Thanks.
PART 1
It depends on your query. When using soft deletes, Laravel will query all models that are not soft-deleted by default. When you also want to get the soft-deleted models, you need to call the withTrashed() method on your query. Read more here:
https://laravel.com/docs/5.5/eloquent#querying-soft-deleted-models
To understand what withTrashed() does, you need to understand how soft-deleting works. Soft-deleting models works by adding a new column to your database tables called deleted_at. It's value defaults to null. When you soft-delete a model, Laravel will put the current timestamp into that column. Therefore, this field doesn't contain a null value anymore.
When querying models when using soft-deletes, Laravel appends a deleted_at is null condition to the query. Calling the withTrashed() method, removes that condition from the query.
Have a look on the source of the default query modifier and the withTrashed method.
PART 2
That are events. You can call that to tell Laravel, that it should execute that specific closure when this event happens. In your example, it is listening for the "deleting" event. See more on that here:
https://laravel.com/docs/5.5/eloquent#events
PART 3
You can entirely delete soft-deletable models with the forceDelete() method. See "Permanently Deleting Models" here:
https://laravel.com/docs/5.5/eloquent#querying-soft-deleted-models
FOR EXAMPLE
$items = App\Model::withTrashed()->get();
If you want to restore a single item, just find it by ID:
$item = App\Model::find($id);

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 5 - what's the difference for creating and created model events?

Sorry I am new to Laravel and confused a little bit about the difference of creating and created model events. I found in laravel docs:
Eloquent models fire several events, allowing you to hook into various
points in the model's lifecycle using the following methods: creating,
created, updating, updated, saving, saved, deleting, deleted,
restoring, restored...Whenever a new model is saved for the first
time, the creating and created events will fire.
But what's the difference of creating and created events? Will creating and created events always be fired together? Or is there a situation when creating is fired but created is not?
The main difference (at least for me) is that:
The creating event is more "powerful" because as the example of the docs states, you're able to cancel the creation of a model during the creating event, if, for example, it's not valid.
On the other hand, the created event will be fired when the model is already saved to the database so you're not able to cancel anything, you only could prepare other data, for example, once the model is saved.
A possible case when one event is fired, but not the other: in the example of the docs, if the model is not valid, the creating event will be fired, but not the created event as it's not valid, and it won't be saved to the database.
Greetings!
Creating is before Created so you won't have access to the the model id.

Laravel Cashier - adding a column that must be updated on subscription create, resume or cancel

I want to provide my users with the ability to lock in their rate for X number of years. However, this is not possible with Stripe API or Cashier. That is why I will have to do it on my application end. To do this I will need a subscribed_at column. I know I can get it straight from Stripe customer's subscription (field current_period_start) but it takes too much time to retrieve it and I will need this functionality quite a lot. So, in my subscriptions table, where I have all of Cashier's needed fields (stripe_id, stripe_active, ..., subscription_ends_at) I want to add this subscribed_at column. Now, I want to automatically update this value anytime a subscription is create, resume, or cancel. On cancel I need to set the value to NULL.
I don't want (and it's not a good practice) to modify Cashier's code. (In StripeGateway.php there is a method updateLocalStripeData() which fires exactly for these three options but as I said I don't want to modify it).
I cannot override the StripeGateway.php method updateLocalStripeData() because my Subscription Model does not extend it.
So far the only solution that worked but which I don't really like is to use Model events saving and there retrieve the subscription's current_period_start field and insert it into my Subscription Model's subscribed_at field.
What other ways to do this?

Resources