plank / before-and-after-model-events
Add before and after events to each existing Laravel Model event.
Fund package maintenance!
Plank
Requires
- php: ^8.2
- illuminate/contracts: ^12.0
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.1.1
- orchestra/testbench: ^10.0.0
- pestphp/pest: ^3.0
- pestphp/pest-plugin-arch: ^3.0
- pestphp/pest-plugin-laravel: ^3.0
- phpstan/extension-installer: ^1.3
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
README
Before and After Model Events
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.
Features
- ๐ 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
Event Flow
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
Installation
You can install the package via composer:
composer require plank/before-and-after-model-events
Usage
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']; }
Basic Usage
1. Add the Trait
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']; }
2. Register Event Listeners
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); });
Advanced Features
Event Prevention
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
Custom Events
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(); });
Multiple Listeners
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); } });
Soft Deletes Support
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"); });
Integration with Existing Event Systems
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 });
Event Reference
Standard Laravel Events
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
Custom Events
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);
How It Works
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.
Requirements
- PHP 8.3 or higher
- Laravel 10.0, 11.0, or 12.0
Testing
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
ย
Credits
ย
License
The MIT License (MIT). Please see License File for more information.
ย
Security Vulnerabilities
If you discover a security vulnerability within siren, please send an e-mail to security@plank.co. All security vulnerabilities will be promptly addressed.
ย
Check Us Out!
ย
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.