event system
- Generate events & listeners
- Manual Register event
- Wildcard event listener
- Event listener queue
- Distributing events
- Register Event Subscriber
Event system
- Introduction
- Register event & listener
- Definition event
- Definition Listener
- Event listener queue
- Distributing events
- Event subscribers
app/Events
The event system provides a great way to decouple various aspects of the application, because a single event can have multiple listeners that are independent of each other. For example, you might want to push a Slack notification to your users every time an order ships. Instead of coupling your order processing code and Slack notification code together, you can simply raise andirectory, and the listeners for these event classes are stored in the
app/Listenersdirectory. If you don't see these directories in your application, don't worry, they will be created automatically when you use Artisan console commands to generate events and listeners.
OrderShipped
Registering events and listenersevent that can be received by a listener and converted into a Slack notification.
EventServiceProvider
in the Laravel application is to register all Event listeners provide a convenient place to do this. Among them, the
listenattribute contains an array of all events (keys) and the listeners (values) corresponding to the events. Of course, you can add multiple events to the array contained in the
listenattribute according to the needs of the application. For example, let's add an
OrderShippedevent:
/** * 应用程序的事件监听器映射 * * @var array */ protected $listen = [ 'App\Events\OrderShipped' => [ 'App\Listeners\SendShipmentNotification', ], ];
Generating Events & Listeners
Of course, manually creating event and listener files is a hassle. Here, you only need to add listeners and events to
EventServiceProvider
, and then use theevent:generate
command. This command will generate all events and listeners listed inEventServiceProvider
. Of course, already existing events and listeners will remain unchanged:php artisan event:generate
Manually register events
Normally, Events are registered in the
$listen
array ofEventServiceProvider
; however, you can also manually register based on closure in theboot
method ofEventServiceProvider
These events of the package:/** * 注册应用中的其它事件 * * @return void */ public function boot(){ parent::boot(); Event::listen('event.name', function ($foo, $bar) { // }); }
Wildcard event listener
You can use
*
as the wildcard parameter when registering the listener, so that you can Capture multiple events on the same listener. A wildcard listener receives the event name as its first argument and the entire event data array as its second argument:Event::listen('event.*', function ($eventName, array $data) { // });
Define events
The event class is a container that saves information related to events. For example, assume that the
OrderShipped
event we generated receives an Eloquent ORM object:<?php namespace App\Events; use App\Order; use Illuminate\Queue\SerializesModels; class OrderShipped{ use SerializesModels; public $order; /** * 创建一个事件实例。 * * @param \App\Order $order * @return void */ public function __construct(Order $order) { $this->order = $order; } }
As you can see, there is no other logic included in this event class. It is just a container for a purchased instance of
Order
. If you use PHP'sserialize
function to serialize an event object, theSerializesModels
trait used by the event will gracefully serialize any Eloquent model.Define the listener
Next, let’s take a look at the listener for the event in the example. The event listener receives the instance in the
handle
method. Theevent:generate
command will automatically load the correct event class and add the event type hint to thehandle
method. In thehandle
method, you can perform any necessary actions in response to the event:<?php namespace App\Listeners; use App\Events\OrderShipped; class SendShipmentNotification{ /** * 创建事件监听器。 * * @return void */ public function __construct() { // } /** * 处理事件。 * * @param \App\Events\OrderShipped $event * @return void */ public function handle(OrderShipped $event) { // 使用 $event->order 来访问 order ... } }
{tip} Your event listener can also add any dependencies in the constructor type hint. All event listeners are resolved through Laravel's service container, so all dependencies will be automatically injected.
Stop event propagation
Sometimes, you can do this by returning
false
in the listener'shandle
method. To prevent the event from being picked up by other listeners.Event Listener Queue
If your listener wants to perform a slow task such as sending an email or making an HTTP request, you can choose to throw it to the queue for processing. Before you start using a queue listener, make sure you can configure queues and start a queue listener on your server or local development environment.
To specify a listener to start the queue, you can add the
ShouldQueue
interface to the listener class. The listener generated by the Artisan commandevent:generate
has this interface imported into the current namespace, so you can use it directly:<?php namespace App\Listeners; use App\Events\OrderShipped; use Illuminate\Contracts\Queue\ShouldQueue; class SendShipmentNotification implements ShouldQueue{ // }
That’s it! When this listener is called by an event, the event dispatcher automatically uses Laravel's queuing system. If no exception is thrown when executing the listener in the queue, the task will be automatically deleted from the queue after execution is completed.
Custom queue connection & queue name
If you want to customize the connection and name of the queue used by the event listener, you can do so in the listener class Define
$connection
,$queue
or$delay
properties:<?php namespace App\Listeners; use App\Events\OrderShipped; use Illuminate\Contracts\Queue\ShouldQueue; class SendShipmentNotification implements ShouldQueue{ /** * The name of the connection the job should be sent to. * * @var string|null */ public $connection = 'sqs'; /** * The name of the queue the job should be sent to. * * @var string|null */ public $queue = 'listeners'; /** * The time (seconds) before the job should be processed. * * @var int */ public $delay = 60; }
Manual access to the queue
If you need to manually access the
delete
andrelease
methods of the queue task under the listener, you can useIlluminate\ Queue\InteractsWithQueue
trait to implement. This trait is loaded into the generated listener by default and provides access to these methods:<?php namespace App\Listeners; use App\Events\OrderShipped; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; class SendShipmentNotification implements ShouldQueue{ use InteractsWithQueue; /** * 处理事件。 * * @param \App\Events\OrderShipped $event * @return void */ public function handle(OrderShipped $event) { if (true) { $this->release(30); } } }
Handling failed tasks
Sometimes the queue task of the event listener may fail. If the listener's queue tasks exceed the maximum number of attempts defined in the queue, the
failed
method is called on the listener.failed
The method receives an event instance and the exception that caused the failure as parameters:<?php namespace App\Listeners;use App\Events\OrderShipped; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; class SendShipmentNotification implements ShouldQueue{ use InteractsWithQueue; /** * 处理事件。 * * @param \App\Events\OrderShipped $event * @return void */ public function handle(OrderShipped $event) { // } /** * 处理失败任务。 * * @param \App\Events\OrderShipped $event * @param \Exception $exception * @return void */ public function failed(OrderShipped $event, $exception) { // } }
Distribution event
If you want to distribute an event, you can pass the event instance to the helper function
event
. This helper function will distribute the event to all registered listeners corresponding to the event.event
The helper function can be used globally and you can call it anywhere in the application:<?php namespace App\Http\Controllers; use App\Order;use App\Events\OrderShipped; use App\Http\Controllers\Controller; class OrderController extends Controller{ /** * 将传递过来的订单发货 * * @param int $orderId * @return Response */ public function ship($orderId) { $order = Order::findOrFail($orderId); // 订单发货逻辑 ... event(new OrderShipped($order)); } }
##Event Subscriber{tip} When testing, you only need to assert that a specific event is dispatched, and No need to actually trigger the listener. Laravel's built-in test helpers make this easy.
Writing event subscribers
Event subscribers are classes that can subscribe to multiple events within themselves, that is, they can define multiple event handlers in a single class. Subscribers should define a
subscribe
method that receives an event dispatcher instance. You can register an event listener by calling thelisten
method on a given event dispatcher:<?php namespace App\Listeners; class UserEventSubscriber{ /** * 处理用户登录事件。 */ public function onUserLogin($event) {} /** * 处理用户注销事件。 */ public function onUserLogout($event) {} /** * 为订阅者注册监听器 * * @param \Illuminate\Events\Dispatcher $events */ public function subscribe($events) { $events->listen( 'Illuminate\Auth\Events\Login', 'App\Listeners\UserEventSubscriber@onUserLogin' ); $events->listen( 'Illuminate\Auth\Events\Logout', 'App\Listeners\UserEventSubscriber@onUserLogout' ); } }
Register Event Subscriber
After writing the subscriber, you can register the subscriber through the event distributor. You can register subscribers in the
$subscribe
property inEventServiceProvider
. For example, let us addUserEventSubscriber
to the array list:<?php namespace App\Providers; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; class EventServiceProvider extends ServiceProvider{ /** * 应用中事件监听器的映射。 * * @var array */ protected $listen = [ // ]; /** * 需要注册的订阅者类。 * * @var array */ protected $subscribe = [ 'App\Listeners\UserEventSubscriber', ]; }
This article first appeared on the LearnKu.com website.