This package adds before and after events for every Laravel Eloquent model event, giving you complete control over your model's lifecycle. It works with all standard Laravel model events (creating
, created
, updating
, updated
, deleting
, deleted
, etc.) and any custom events you define.
- 🚀 Zero Configuration - Just add the trait and start using before/after events
- 🎯 Works with ALL Events - Standard Laravel events AND custom events
- 🔒 Event Prevention - Before events can prevent the main event from firing
- 🏗️ Clean API - Static methods for registering event listeners with full IDE support
- 🧪 Fully Tested - Comprehensive test suite with 22 tests and 68 assertions
- ⚡ Performance Focused - Minimal overhead with dynamic event registration
- 🔧 Laravel Integration - Works seamlessly with existing Laravel event systems
When working with model events, this package ensures the following execution order:
For standard Laravel events (like saving a model):
beforeCreating
→creating
→afterCreating
beforeSaving
→saving
→afterSaving
beforeCreated
→created
→afterCreated
beforeSaved
→saved
→afterSaved
For custom events (like publishing a post):
beforePublishing
→publishing
→afterPublishing
You can install the package via composer:
composer require plank/before-and-after-model-events
Simply add the BeforeAndAfterEvents
trait to any Eloquent model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Plank\BeforeAndAfterModelEvents\Concerns\BeforeAndAfterEvents;
class User extends Model
{
use BeforeAndAfterEvents;
protected $fillable = ['name', 'email'];
}
Add the BeforeAndAfterEvents
trait to any Eloquent model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Plank\BeforeAndAfterModelEvents\Concerns\BeforeAndAfterEvents;
class Post extends Model
{
use BeforeAndAfterEvents;
protected $fillable = ['title', 'content', 'status'];
}
Use the static methods to register before and after event listeners:
use App\Models\Post;
// Standard Laravel events
Post::beforeEvent('creating', function ($post) {
$post->slug = Str::slug($post->title);
$post->status = 'draft';
});
Post::afterEvent('created', function ($post) {
Cache::tags(['posts'])->flush();
Log::info("New post created: {$post->title}");
});
Post::beforeEvent('updating', function ($post) {
if ($post->isDirty('title')) {
$post->slug = Str::slug($post->title);
}
});
Post::afterEvent('deleted', function ($post) {
Storage::delete($post->image_path);
});
Before events can prevent the main event (and subsequent after events) from firing by returning false
:
Post::beforeEvent('deleting', function ($post) {
if ($post->is_protected) {
// Prevent deletion of protected posts
return false;
}
});
// This will fail silently if the post is protected
$post->delete(); // Returns false, post not deleted
The package works seamlessly with any custom events you fire on your models:
class Post extends Model
{
use BeforeAndAfterEvents;
public function publish()
{
// Fire custom event with before/after support
if ($this->fireModelEvent('publishing') === false) {
return false;
}
$this->status = 'published';
$this->published_at = now();
$this->save();
return true;
}
}
// Register listeners for the custom event
Post::beforeEvent('publishing', function ($post) {
if (!$post->isReadyForPublishing()) {
return false; // Prevent publishing
}
$post->seo_title = $post->seo_title ?: $post->title;
});
Post::afterEvent('publishing', function ($post) {
Mail::to($post->author)->send(new PostPublishedNotification($post));
Cache::tags(['published-posts'])->flush();
});
You can register multiple listeners for the same event:
Post::beforeEvent('creating', function ($post) {
$post->author_id = auth()->id();
});
Post::beforeEvent('creating', function ($post) {
$post->reading_time = $this->calculateReadingTime($post->content);
});
Post::beforeEvent('creating', function ($post) {
if (!$post->excerpt) {
$post->excerpt = Str::limit(strip_tags($post->content), 150);
}
});
The package works perfectly with Laravel's soft deletes:
use Illuminate\Database\Eloquent\SoftDeletes;
class Post extends Model
{
use BeforeAndAfterEvents, SoftDeletes;
}
// Handle soft delete events
Post::beforeEvent('deleting', function ($post) {
$post->deleted_by = auth()->id();
});
// Handle restoration events
Post::beforeEvent('restoring', function ($post) {
Log::info("Restoring post: {$post->title}");
});
Post::afterEvent('restored', function ($post) {
Cache::forget("deleted_posts");
});
The package works alongside existing Laravel event dispatchers and observers:
class Post extends Model
{
use BeforeAndAfterEvents;
// Existing Laravel event dispatchers still work
protected $dispatchesEvents = [
'saved' => PostSavedEvent::class,
];
}
// Both systems work together
Post::beforeEvent('saving', function ($post) {
// Runs before the 'saving' event and PostSavedEvent
});
All standard Laravel model events are supported:
retrieved
- Before/after model is retrieved from databasecreating
- Before/after model is being createdcreated
- Before/after model has been createdupdating
- Before/after model is being updatedupdated
- Before/after model has been updatedsaving
- Before/after model is being saved (create or update)saved
- Before/after model has been saveddeleting
- Before/after model is being deleteddeleted
- Before/after model has been deletedrestoring
- Before/after soft-deleted model is being restoredrestored
- Before/after soft-deleted model has been restoredreplicating
- Before/after model is being replicatedforceDeleting
- Before/after model is being force deletedforceDeleted
- Before/after model has been force deleted
Any event name can be used - the package will automatically register the before/after variants:
// These all work automatically
Post::beforeEvent('publishing', $callback);
Post::beforeEvent('archiving', $callback);
Post::beforeEvent('featuring', $callback);
Post::beforeEvent('customBusinessLogic', $callback);
The package uses a simple but powerful approach:
-
Dynamic Event Registration: When you call
beforeEvent()
orafterEvent()
, the package registers the base event (e.g.,publishing
) in a static registry and adds the before/after variants (beforePublishing
,afterPublishing
) to the model's observable events. -
Event Interception: The trait overrides the
fireModelEvent()
method to intercept all model events and fire the before/after events at the appropriate times. -
Minimal Overhead: Events are only registered when actually used, and the trait adds minimal performance overhead to your models.
- PHP 8.3 or higher
- Laravel 10.0, 11.0, or 12.0
The package includes a comprehensive test suite with 22 tests covering:
- Standard Laravel events (creating, updating, deleting, etc.)
- Custom events and dynamic registration
- Event prevention and flow control
- Soft deletes and restoration
- Multiple listeners per event
- Edge cases and error handling
- Integration with existing Laravel event systems
Run the tests:
composer test
Run tests with coverage:
composer test-coverage
Run static analysis:
composer analyse
The MIT License (MIT). Please see License File for more information.
If you discover a security vulnerability within siren, please send an e-mail to security@plank.co. All security vulnerabilities will be promptly addressed.
Plank focuses on impactful solutions that deliver engaging experiences to our clients and their users. We're committed to innovation, inclusivity, and sustainability in the digital space. Learn more about our mission to improve the web.