Reputation: 11
I want that If any of the products is updated we fire an event once after the transaction finish
DB::transaction(function() {
foreach($products as $product) {
$product = Product::find($product->id) ;
$product->price = 2;
$product->update();
}
});
Upvotes: 1
Views: 9858
Reputation: 2595
Laravel Eloquent models allowing you to hook into the following moments
retrieved
, creating
, created
, updating
, updated
, saving
, saved
, deleting
, deleted
, restoring
, restored
, and replicating
The above events are varies based on the laravel version.
Laravel 8.x
If you are using Laravel 8.x, then Laravel took care of eloquent events with the transaction.
You just need to use public $afterCommit = true;
in your observer.
Then the eloquent event will fire after committing a transaction.
Reference: https://laravel.com/docs/8.x/eloquent#observers-and-database-transactions
Laravel < 8.x
Those who are using the below version, Please have a look at the below code.
You need to create a trait inside app/Traits
folder
In app/Traits/TransactionalEloquentEvents.php
<?php
namespace App\Traits;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Events\TransactionCommitted;
use Illuminate\Support\Facades\Log;
trait TransactionalEloquentEvents
{
protected static $eloquentEvents = ['created', 'updated'];
protected static $queuedTransactionalEvents = [];
public static function bootTransactionalEloquentEvents()
{
$dispatcher = static::getEventDispatcher();
if (!$dispatcher) {
return;
}
foreach (self::$eloquentEvents as $event) {
static::registerModelEvent($event, function (Model $model) use ($event) {
/*get updated parameters*/
$updatedParams = array_diff($model->getOriginal(),$model->getAttributes());
if ($model->getConnection()->transactionLevel()) {
self::$queuedTransactionalEvents[$event][] = $model;
} else {
Log::info('Event fired without transaction '.$event. json_encode($updatedParams));
/* Do your operation here*/
}
});
}
$dispatcher->listen(TransactionCommitted::class, function (TransactionCommitted $event) {
if ($event->connection->transactionLevel() > 0) {
return;
}
foreach ((self::$queuedTransactionalEvents ?? []) as $eventName => $models) {
foreach ($models as $model) {
Log::info('Event fired with transaction '.$eventName);
/* Do your operation here*/
}
}
self::$queuedTransactionalEvents = [];
});
}
}
In your model app/Models/Product.php
<?php
namespace App\Models;
use App\Traits\TransactionalEloquentEvents;
class Product extends Model
{
use TransactionalEloquentEvents;
}
Note: In case of updated
eloquent event. You will get the updated parameters through the $updatedParams
variable.
The above case handles both transaction and non-transaction model operations.
I am maintaining a log here for each activity. You can do your operation too.
Upvotes: 3
Reputation: 3035
I have just checked the Laravel source code. I think you can utilize the Illuminate\Database\Events\TransactionCommitted
event, which is provided out of the box. You can simply register this event with a listener in the EventServiceProvider
:
namespace App\Providers;
class EventServiceProvider extends ServiceProvider
{
protected $listen = [
TransactionCommitted::class => [
WhatYouWantToDo::class,
],
];
}
Upvotes: -1