plank/before-and-after-model-events

Add before and after events to each existing Laravel Model event.

v12.0.0 2025-08-02 04:51 UTC

This package is auto-updated.

Last update: 2025-08-02 05:30:22 UTC


README

PHP Version Support PHP Version Support GitHub Workflow Status

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):

  1. beforeCreating โ†’ creating โ†’ afterCreating
  2. beforeSaving โ†’ saving โ†’ afterSaving
  3. beforeCreated โ†’ created โ†’ afterCreated
  4. beforeSaved โ†’ saved โ†’ afterSaved

For custom events (like publishing a post):

  1. 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 database
  • creating - Before/after model is being created
  • created - Before/after model has been created
  • updating - Before/after model is being updated
  • updated - Before/after model has been updated
  • saving - Before/after model is being saved (create or update)
  • saved - Before/after model has been saved
  • deleting - Before/after model is being deleted
  • deleted - Before/after model has been deleted
  • restoring - Before/after soft-deleted model is being restored
  • restored - Before/after soft-deleted model has been restored
  • replicating - Before/after model is being replicated
  • forceDeleting - Before/after model is being force deleted
  • forceDeleted - 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:

  1. Dynamic Event Registration: When you call beforeEvent() or afterEvent(), 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.

  2. Event Interception: The trait overrides the fireModelEvent() method to intercept all model events and fire the before/after events at the appropriate times.

  3. 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.