reedware / laravel-events
Define all of your events in a simple configuration file.
Requires
- php: ^7.1.3|^8.0
- laravel/framework: ^6.19|^7.0|^8.0
Requires (Dev)
- mockery/mockery: ^1.0
- phpunit/phpunit: ^7.5|^8.0
This package is auto-updated.
Last update: 2024-10-23 01:54:22 UTC
README
This package allows you to define all of your events in a simple configuration file.
Introduction
Events in Laravel are a fantastic tool to use. However, once you start leaning into events heavily, managing everything through the service provider can be a bit cumbersome. While event discovery exists (since Laravel 5.8), this doesn't always solve the entire problem. This package will allow you to define listeners, subscribers, and observers within a configuration file. Additionally, the implementation allows you to be a bit more lackadaisical with registration, with no performance cost after caching events.
Installation
Composer
First, start by installing this package.
composer require reedware/laravel-events
Configuration
Next, you'll need to get your hands on the events.php
configuration file. You can either copy it directly, or publish it.
php artisan vendor:publish
Service Provider
Finally, you'll need to modify your service provider. You can either extend the example provider in the package, or you can utilize the trait.
Extending the Service Provider
<?php namespace App\Providers; use Reedware\LaravelEvents\EventServiceProvider as ServiceProvider; class EventServiceProvider extends ServiceProvider { }
Using the Trait instead
<?php namespace App\Providers; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; use Reedware\LaravelEvents\ConfiguredEvents; class EventServiceProvider extends ServiceProvider { use ConfiguredEvents; }
If you've overridden the default listens()
method, be sure to yield the configured events:
/** * Returns the events and handlers. * * @return array */ public function listens() { $myEventOverrides = [/* ... */]; return array_merge_recursive( $myEventOverrides, $this->configuredEvents() ); }
After that, you're good to start configuring your events!
Usage
This package offers four types of event registration:
- Event / Listener Mapping
- Subscriber / Event Mapping
- Observer / Model Mapping
- Model / Observer Mapping
As you dive in, you'll discover that there's more than one way to register an event binding. This package offers various alternatives so that you can do whatever makes the most since for you and your application.
Event / Listener Mapping
This is the traditional "listens" array that is typically a property within your EventServerProvider
. You can list each event, and the listeners that listen to them.
Example:
'listen' => [ // When a user has registered... Illuminate\Auth\Events\Registered::class => [ // Send an email verification notification Illuminate\Auth\Listeners\SendEmailVerificationNotification::class ], ],
Explicit Bindings
If your listener doesn't use the traditional handle
method, you can call out the method directly like so:
'listen' => [ // When a user has registered... Illuminate\Auth\Events\Registered::class => [ [App\Listeners\MyCustomListener::class, 'handleRegistration'], // or 'App\Listeners\MyCustomListener@handleRegistration' ], ],
Implicit Bindings
If your alternative method starts with the word handle
(e.x. handleRegistration
), and accepts the type-hinted event, you don't have do specify the custom method explicitly:
Listener:
<?php namespace App\Listeners; use Illuminate\Auth\Events\Registered; class MyCustomListener { /** * Handles the specified registration event. * * @param \Illuminate\Auth\Events\Registered $event * * @return void */ public function handleRegistration(Registered $event) { // } }
Configuration:
'listen' => [ // When a user has registered... Illuminate\Auth\Events\Registered::class => [ // Handle the event App\Listeners\MyCustomListener::class, ], ],
Alternative Subscriber Bindings
Since you can utilize a non handle
method through implicit or explicit binding, you could technically register your subscribers within the Event / Listener mapping. This can make sense if you want to list your subscribers under each respective event, rather than listing all events that are subscribed to.
Example:
'listen' => [ // When a user has registered... Illuminate\Auth\Events\Registered::class => [ // Send a slack notification App\Listeners\SendSlackNotification::class, ], // When a user has logged out... Illuminate\Auth\Events\Logout::class => [ // Send a slack notification App\Listeners\SendSlackNotification::class, ], ],
Subscriber / Event Mapping
When working with subscribers, it often makes sense to list the subscribed events together. When listing subscribers in the configuration file, they do not need a subscribe
method.
Configuration:
'subscribe' => [ // Log a security event... App\Listeners\LogSecurityEvent::class => [ // When a user provided incorrect credentials Illuminate\Auth\Events\Failed::class, // When a user has been locked out Illuminate\Auth\Events\Lockout::class, // When a user has reset their password Illuminate\Auth\Events\PasswordReset::class, ], ],
Subscriber:
<?php namespace App\Listeners; use Illuminate\Auth\Events\Failed; use Illuminate\Auth\Events\Lockout; use Illuminate\Auth\Events\PasswordReset; class LogSecurityEvent { /** * Handles failed login attempts. */ public function handleFailed(Failed $event) { // } /** * Handles too many login attempts. */ public function handleLockout(Lockout $event) { // } /** * Handles successful password resets. */ public function handlePasswordReset(PasswordReset $event) { // } }
Remember that implicit bindings requires the method to start with the word handle
, even when type-hinted.
Pro-Tip: If you plan to always use implicit bindings for subscribers, consider using Event Discovery!
Explicit Bindings
Similar to the event / listener mapping, you may also use expicit binding:
'subscribe' => [ // Log a security event... App\Listeners\LogSecurityEvent::class => [ // When a user provided incorrect credentials [Illuminate\Auth\Events\Failed::class, 'failed'], // When a user has been locked out [Illuminate\Auth\Events\Lockout::class, 'lockout'], // When a user has reset their password 'Illuminate\Auth\Events\PasswordReset@reset', ], ],
Observer / Model Mapping
When fully utilized, observers often observe more than one model. Listing the models under the observers make more sense in this case. Here's how you can configure observers:
'observe' => [ // Track the creator for each of the following models... App\Observers\UserObserver::class => [ App\Models\Country::class, App\Models\Post::class, App\Models\State::class, App\Models\User::class, ] ],
This package fully supports custom observables, provided that they are registered either as a property or within the construction of the model.
Model / Observer Mapping
You may prefer to instead list out models, and describe the observers beneath them. Both options are provided so that you can do what makes the most sense for you and your application. Here's how listing the model first would work:
'models' => [ // Observe the user App\Models\User::class => [ App\Observers\UserObserver::class, ] ],
Event Caching
This package fully supports Event Caching. In fact, given how observers are registered under the hood, you will likely see a significant performance boost if you're using a lot of observers within your application.
To cache events, run the event:cache
artisan command. Should you need to clear the event cache, you can run the event:clear
artisan command.
Event Discovery
This package fully supports Event Discovery, and it does not conflict with the configuration file. Both configured events and discovered events are merged in the registration process.
Additionally, any section of the event configuration can be omitted entirely. If you decide to use event discovery for all of your events, and wish to only configure your observers, you can remove the "listen" and "subscribe" arrays without issue.