In some situations you may want to process multiple activities back to a single activity batch.
For example when a User
deletes an Author
, then that cascades soft deletes to the Book
s that were owned by the Author
. This way all modifications caused by that initial action are still associated with the same causer and batch UUID.
To start a new batch call LogBatch::startBatch()
before any activity is done. Then all following actions will link back by UUID to that batch. After finishing activities you should end the batch by calling LogBatch::endBatch()
.
Here's an example:
use Spatie\Activitylog\Facades\LogBatch;
use Spatie\Activitylog\Models\Activity;
LogBatch::startBatch();
$author = Author::create(['name' => 'Philip K. Dick']);
$book = Book::create(['name' => 'A Scanner Brightly', 'author_id' => $author->id]);
$book->update(['name' => 'A Scanner Darkly']);
$author->delete();
LogBatch::endBatch();
Doing this would allow all the activities within this batch to log together as described. This helps ensure those non-explicit actions like the cascade delete of the book get captured too.
##Retrieve Activities by batch
Once the batch is closed, if you save the batch's UUID, then you can retrieve all activities related to that batch. Do this by using the Activity::whereBatchUuid($batchUuid)
lookup scope.
For example:
$batchUuid = LogBatch::getUuid();
LogBatch::endBatch();
$batchActivities = Activity::forBatch($batchUuid)->get();
Example results:
Note that in the examples both Author
and Book
are implementing LogsActivity
trait.
use Spatie\Activitylog\Facades\LogBatch;
use Spatie\Activitylog\Models\Activity;
LogBatch::startBatch();
$author = Author::create(['name' => 'Philip K. Dick']);
$book = Book::create(['name' => 'A Scanner Brightly', 'author_id' => $author->id]);
$book->update(['name' => 'A Scanner Darkly']);
$book2 = Book::create(['name' => 'Paycheck', 'author_id' => $author->id]);
$author->delete();
$batchUuid = LogBatch::getUuid();
LogBatch::endBatch();
$batchActivities = Activity::forBatch($batchUuid)->get();
var_dump($batchActivities);
##Note on starting new batches
You may not start a new batch before ending the current open batch. Opening new batch while another one is open in the same request will result in the same uuid
.
Activity batches works similarly to database transactions where number of started transactions/batches must be equal to the number of committed/closed transactions/batches.
##Check if batch is open
It's important to not open a new batch from within an existing batch. This type of thing may come up within a queue job or middleware.
To verify if a batch is open or closed you can do the following:
LogBatch::startBatch();
if(LogBatch::isOpen()) {
}
##Keep LogBatch openend during multiple job/requests
In some cases when you have multiple jobs that goes through queue batch, and you want to log all the activities during these different jobs using the same LogBatch
, or you want to log multiple activities throughout multiple requests.
You may utilize LogBatch::setBatch($uuid)
passing $uuid
or any unique value that identify the batch to keep it open.
Here's an example:
use Spatie\Activitylog\Facades\LogBatch;
use Illuminate\Bus\Batch;
use Illuminate\Support\Str;
$uuid = Str::uuid();
Bus::batch([
new SomeJob('some value', $uuid),
new AnotherJob($uuid),
new WorkJob('work work work', $uuid),
])->then(function (Batch $batch) {
})->catch(function (Batch $batch, Throwable $e) {
})->finally(function (Batch $batch) use ($uuid) {
LogBatch::getUuid() === $uuid
LogBatch::endBatch();
})->dispatch();
Activity::forBatch($uuid)->get();
class SomeJob
{
public function handle(string $value, ?string $batchUuid = null)
{
LogBatch::startBatch();
if($batchUuid) LogBatch::setBatch($batchUuid);
}
}
##Batch activities using callback
You can also batch activities using closure passed to LogBatch::withinBatch()
. Every activity executed will happen inside that closure will be included in the same batch.
Here's an example:
use Spatie\Activitylog\Facades\LogBatch;
LogBatch::withinBatch(function(string $uuid) {
$uuid;
activity()->log('my message');
$item = NewsItem::create(['name' => 'new batch']);
$item->update(['name' => 'updated']);
$item->delete();
});
Activity::latest()->get();