Automating Eloquent Observers with Custom Stubs in Laravel
Overview
Standard

Prerequisites
To implement this pattern, you should be comfortable with
Key Libraries & Tools
- Laravel Framework: The core environment providing the EloquentORM.
- Artisan CLI: Used for generating code and publishing framework templates.
- PHP File System: Utilized by custom commands to iterate through model directories.
Code Walkthrough
Step 1: Create the Base Notification Trait
Instead of defining notification logic in every observer, move it to a shared trait. This keeps your observers slim.
trait SendsNotifications
{
public function sendSuccessNotification($model, $action)
{
// Logic to send database notification
}
public function sendDangerNotification($model, $action)
{
// Logic for deletions or errors
}
}
Step 2: Customizing the Observer Stub
Run php artisan stub:publish to bring stubs/ directory. Modify observer.stub to include your trait and default methods.
namespace {{ namespace }};
use {{ namespacedModel }};
use App\Traits\SendsNotifications;
class {{ class }}
{
use SendsNotifications;
public function created({{ model }} ${{ modelVariable }})
{
$this->sendSuccessNotification(${{ modelVariable }}, 'created');
}
}
Step 3: The Bulk Generation Command
A custom
public function handle()
{
$models = File::allFiles(app_path('Models'));
foreach ($models as $file) {
$modelName = $file->getFilenameWithoutExtension();
$this->call('make:observer', [
'name' => "{$modelName}Observer",
'--model' => $modelName
]);
}
}
Syntax Notes
{{ model }} in its stubs. When you run a make command, the framework's generator replaces these with the actual class names you provide in the terminal. This allows for dynamic code generation while maintaining strict typing.
Practical Examples
This approach shines in large-scale applications requiring a robust activity log or audit trail. Instead of installing heavy packages, you generate lightweight observers that trigger database notifications every time a record changes. It ensures every new model added to the system is automatically tracked without additional developer effort.
Tips & Gotchas
Watch out for infinite loops. If your observer saves data back to the same model it is observing, it will trigger itself again. Always use the saveQuietly() method if you need to update the model instance within the observer logic to prevent recursive crashes.