12/08/2018, 15:13

Laravel: Events

Introduction Các Event (sự kiện) của Laravel cung cấp việc thực hiện observer 1 cách đơn giản. Cho phép bạn đăng ký và lắng nghe các event khác nhau xảy ra trong ứng dụng của bạn. Các class Event thường được lưu trữ trong thư mục app/Events, trong khi listener của chúng được lưu trong ...

Introduction


Các Event (sự kiện) của Laravel cung cấp việc thực hiện observer 1 cách đơn giản. Cho phép bạn đăng ký và lắng nghe các event khác nhau xảy ra trong ứng dụng của bạn. Các class Event thường được lưu trữ trong thư mục app/Events, trong khi listener của chúng được lưu trong app/Listeners. Đừng lo lắng nếu bạn không tìm thấy những thư mục này trong app của bạn, vì chúng sẽ được tạo ra cho bạn khi bạn tạo các Event và Listener bằng các lệnh console của Artisan.

Event phục vụ như một cách tuyệt vời để tách rời các khía cạnh khác nhau trong app của bạn, vì một Event đơn lẻ có thể có nhiều Listener mà không phụ thuộc lẫn nhau. Ví dụ: bạn có thể muốn gửi thông báo Slack cho user mỗi lần một đơn đặt hàng đã được giao. Thay vì nối mã xử lý lệnh của bạn với mã thông báo Slack của bạn, bạn chỉ cần thêm một Event OrderShipped mà Listener có thể nhận và chuyển đổi thành một thông báo Slack.


Registering Events & Listeners


EventServiceProvider có trong ứng dụng Laravel của bạn cung cấp một vị trí thuận tiện để đăng ký tất cả event listeners của ứng dụng của bạn. Thuộc tính listen chứa một mảng của tất cả các event (keys) và các listeners của chúng (value). Tất nhiên, bạn có thể thêm nhiều event cho mảng này như yêu cầu của ứng dụng của bạn. Ví dụ: hãy thêm sự kiện OrderShipped:

/**
 * The event listener mappings for the application.
 *
 * @var array
 */
protected $listen = [
    'AppEventsOrderShipped' => [
        'AppListenersSendShipmentNotification',
    ],
];

Generating Events & Listeners


Tất nhiên, thủ công tạo ra các file cho mỗi event và listener là rườm rà. Thay vào đó, chỉ cần thêm listener và event vào EventServiceProvider của bạn và sử dụng lệnh event: generate. Lệnh này sẽ tạo ra bất kỳ event hoặc listener nào được liệt kê trong EventServiceProvider của bạn. Tất nhiên, các event và listener đã tồn tại sẽ không bị ảnh hưởng:

php artisan event:generate

**Manually Registering Events**
Thông thường, các event cần được đăng ký qua ```EventServiceProvider``` ```$listen``` array. Tuy nhiên, bạn cũng có thể đăng ký các Closure based event theo cách thủ công trong method ```boot``` của ```EventServiceProvider``` của bạn: ``` /** * Register any other events for your application. * * @return void */ public function boot() { parent::boot();
Event::listen('event.name', function ($foo, $bar) {
    //
});

}

_Wildcard Event Listeners_

Bạn thậm chí có thể đăng ký listener bằng cách sử dụng ```*``` như một tham số ký tự đại diện, cho phép bạn nắm bắt nhiều event trên cùng một listener. Wildcard listener nhận tên event làm đối số đầu tiên và toàn bộ mảng dữ liệu event là đối số thứ hai của nó:

Event::listen('event.*', function (eventName,arrayeventName, array eventName,arraydata) { // });

<br>
### Defining Events
<br>
một class Event chỉ đơn giản là một bộ chứa dữ liệu chứa thông tin liên quan đến event. Ví dụ: giả sử event ```OrderShipped``` đã tạo của chúng ta nhận được một đối tượng ```Eloquent ORM```:
<?php namespace AppEvents; use AppOrder; use IlluminateQueueSerializesModels; class OrderShipped { use SerializesModels; public $order; /** * Create a new event instance. * * @param Order $order * @return void */ public function __construct(Order $order) { $this->order = $order; } } ``` Như bạn thấy, class event này không chứa logic. Nó chỉ đơn giản là một container cho trường hợp ```Order``` đã được mua. Thuộc tính ```SerializesModels``` trait được sử dụng bởi event này sẽ khéo léo sắp xếp theo thứ tự bất kỳ Eloquent model nếu đối tượng event được nối tiếp bằng cách sử dụng funtion ```serialize``` của PHP.
### Defining Listeners
Tiếp theo, chúng ta hãy nhìn vào listener cho event ví dụ của chúng ta. Event listeners nhận instance event trong phương thức```handle``` của nó. câu lệnh ```event:generate``` sẽ tự động nhập đúng class event và type-hint event trên phương thức ```handle```. Với phương thức ```handle```, bạn có thể thực hiện bất kỳ action cần thiết để đáp ứng event: ``` <?php namespace AppListeners; use AppEventsOrderShipped; class SendShipmentNotification { /** * Create the event listener. * * @return void */ public function __construct() { // } /** * Handle the event. * * @param OrderShipped $event * @return void */ public function handle(OrderShipped $event) { // Access the order using $event->order... } } ```
### Queued Event Listeners
Hàng đợi listener có thể có lợi nếu listener của bạn sẽ thực hiện một tác vụ chậm như gửi e-mail hoặc yêu cầu HTTP. Trước khi bắt đầu với queued listener, hãy chắc chắn [configure your queue](https://laravel.com/docs/5.4/queues) và start queue listener trên server hoặc môi trường phát triển local của bạn. Để xác định rằng một listener nên được xếp hàng đợi, thêm interface ```ShouldQueue``` vào class listener. Listener được tạo ra bởi lệnh Artisan ```event:generate``` đã có interface này trên namespace hiện tại, do đó bạn có thể sử dụng nó ngay lập tức: ``` <?php namespace AppListeners; use AppEventsOrderShipped; use IlluminateContractsQueueShouldQueue; class SendShipmentNotification implements ShouldQueue { // } ``` Bây giờ, khi listener này được gọi cho một event, nó sẽ tự động xếp hàng bởi event dispatcher bằng [queue system](https://laravel.com/docs/5.4/queues) của Laravel. Nếu không có ngoại lệ nào được ném ra khi listener được thực hiện bởi hàng đợi, công việc được xếp hàng sẽ tự động bị xóa sau khi đã hoàn tất quá trình xử lý.
_Customizing The Queue Connection & Queue Name_
Nếu bạn muốn tùy chỉnh queue connection và queue name được sử dụng bởi một event listener, bạn có thể định nghĩa ```$connection``` và ```$queue``` trên listener class của bạn: ``` <?php namespace AppListeners; use AppEventsOrderShipped; use IlluminateContractsQueueShouldQueue; 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'; } ```
**Manually Accessing The Queue**
Nếu bạn cần truy cập theo cách thủ công các phương thức ```delete``` và ```realse``` , bạn có thể thực hiện bằng cách sử dụng ```IlluminateQueueInteractsWithQueue``` trait. Trait này được import mặc định trên listener được tạo và cung cấp quyền truy cập vào các phương thức sau: ``` <?php namespace AppListeners; use AppEventsOrderShipped; use IlluminateQueueInteractsWithQueue; use IlluminateContractsQueueShouldQueue; class SendShipmentNotification implements ShouldQueue { use InteractsWithQueue; public function handle(OrderShipped $event) { if (true) { $this->release(30); } } } ```
**Handling Failed Jobs**
Đôi khi queued event listener của bạn có thể không thành công. Nếu queued listener vượt quá số lần cố gắng tối đa được xác định bởi queue worker của bạn, phương thức ```failed``` sẽ được gọi vào listener của bạn. Phương thức ```failed``` nhận được thể hiện của event và exception gây ra sự cố: ``` <?php namespace AppListeners; use AppEventsOrderShipped; use IlluminateQueueInteractsWithQueue; use IlluminateContractsQueueShouldQueue; class SendShipmentNotification implements ShouldQueue { use InteractsWithQueue; public function handle(OrderShipped $event) { // } public function failed(OrderShipped $event, $exception) { // } } ```
**Dispatching Events**
Để gửi một event, bạn có thể vượt qua một thể hiện của event đến ```event``` helper. Helper sẽ gửi event tới tất cả listener đã đăng ký của mình. Vì ```event``` helper là toàn cục, bạn có thể gọi nó từ mọi nơi trong ứng dụng của bạn: ``` <?php namespace AppHttpControllers; use AppOrder; use AppEventsOrderShipped; use AppHttpControllersController; class OrderController extends Controller { /** * Ship the given order. * * @param int $orderId * @return Response */ public function ship($orderId) { $order = Order::findOrFail($orderId); // Order shipment logic... event(new OrderShipped($order)); } } ```
### Event Subscribers **Writing Event Subscribers** Event subscriber là các class có thể đăng ký nhiều event từ bên trong class, cho phép bạn xác định một số event handler trong một single class. Subscriber nên định nghĩa phương thức ```subscribe ```, sẽ được thông qua một thể hiện của event dispatcher. Bạn có thể gọi phương thức ```listen``` trên dispatcher đã cho để đăng ký event listener: ``` <?php namespace AppListeners; class UserEventSubscriber { /** * Handle user login events. */ public function onUserLogin($event) {} /** * Handle user logout events. */ public function onUserLogout($event) {} /** * Register the listeners for the subscriber. * * @param IlluminateEventsDispatcher $events */ public function subscribe($events) { $events->listen( 'IlluminateAuthEventsLogin', 'AppListenersUserEventSubscriber@onUserLogin' ); $events->listen( 'IlluminateAuthEventsLogout', 'AppListenersUserEventSubscriber@onUserLogout' ); } } ```
**Registering Event Subscribers**
Sau khi viết subscriber, bạn đã sẵn sàng để đăng ký với event dispatcher. Bạn có thể đăng ký subscribers sử dụng ```$subscribe``` property trên ```EventServiceProvider```. Ví dụ, hãy thêm ```UserEventSubScber``` vào danh sách: ``` <?php namespace AppProviders; use IlluminateFoundationSupportProvidersEventServiceProvider as ServiceProvider; class EventServiceProvider extends ServiceProvider { /** * The event listener mappings for the application. * * @var array */ protected $listen = [ // ]; /** * The subscriber classes to register. * * @var array */ protected $subscribe = [ 'AppListenersUserEventSubscriber', ]; } ```
0