Events

Giới thiệu

Events của Laravel cung cấp một triển khai observer đơn giản, cho phép bạn subscribe và listen tới các events trong ứng dụng. Các event class về cơ bản được lưu trong thư mụcapp/Events, còn các listener lại được lưu trong app/Listeners. Đừng lo lắng nếu bạn không nhìn thấy thư mục đó trong ứng dụng, vì chúng sẽ được tạo khi bạn tạo events và listeners bằng Artisan console commands.

Events làm cho việc tách các khía cạnh khác nhau của ứng dụng thật là đơn giản, vì một event có thể có nhiều listeners nó không phụ thuộc vào nhâu. Ví dụ, bạn muốn gửi Slack notification cho user mỗi khi có sử chuyển file. Thay vì ghép xử lý code vào Slack notification code, bạn chỉ cần một event OrderShipped, mà listener có thể nhận và biến đổi thành thông Slack notification.

Đăng ký Events & Listeners

EventServiceProvider đi kèm trong Laravel cung cấp một vị trí tiện ích cho việc đăng kí tất cả các event listener. Thuộc tính listen hứa một mảng tất cả các events (khoá) và listeners của chúng (values). Dĩ nhiên, bạn có thể thêm vào bao nhiêu events tuỳ ý trong mảng này nếu như ứng dụng yêu cầu. Ví dụ, hãy cùng thêm vào event OrderShipped:

/**
 * The event listener mappings for the application.
 *
 * @var  array
 */
protected $listen = [
    'App\Events\OrderShipped' => [
        'App\Listeners\SendShipmentNotification',
    ],
];

Tạo Events & Listeners

Việc tạo file thủ công cho từng event và listener khá là vướng víu. Vì thế, bạn có thể thêm event với listener vào trong EventServiceProvider và sử dụng lệnh event:generate. Nó sẽ tạo ra bất kỳ events hoặc listeners trong EventServiceProvider. Tất nhiên, events và listeners nào đã tồn tại trước đó rồi thì sẽ được để nguyên:

php artisan event:generate

Đăng ký Events thủ công

Về cơ bản, event cần được đăng kí vào trong EventServiceProvider $listen mảng; tuy nhiên, bạn có thể đăng ký Closure based events thủ công trong hàm boot trong EventServiceProvider:

/**
 * Register any other events for your application.
 *
 * @return  void
 */
public function boot()
{
    parent::boot();

    Event::listen('event.name', function ($foo, $bar) {
        //
    });
}

Wildcard Event Listeners

YBạn có thể đăng kí các listener sử dụng dấu wildcard * cho phép bạn bắt nhiều event trong cùng một listener. Wildcard listener nhận toàn bộ mảng dữ liueej trong một đối số truyền vào:

Event::listen('event.*', function (array $data) {
    //
});

Định nghĩa Events

Một event class đơn giản chỉ là một data container chứa thông tin liên quan tới event. Ví dụ, giả dụ chúng ta có tạo ra event OrderShipped và nhận vào một Eloquent ORM:

<?php

namespace App\Events;

use App\Order;
use App\Events\Event;
use Illuminate\Queue\SerializesModels;

class OrderShipped extends Event
{
    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, event class này không có chứa logic nào. Nó đơn giản chỉ là một container cho đối tượng Order instance được mua. Trait SerializesModels sử dụng bởi event sẽ thực hiện serialize bất cứ Eloquent model nào nếu như đối tượng event được serialize sử dụng hàm serialize của PHP.

Định nghĩa Listeners

Tiếp thep, hãy xem một listener cho event sau. Event listeners nhận event instance trong hàm handle. Lệnh event:generate sẽ tự động import class event thích hợp type-hint event trong hàm handle. Bên trong hàm handle bạn có thể thực hiện bất kỳ actions cần thiết đê respond cho event:

<?php

namespace App\Listeners;

use App\Events\OrderShipped;

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

event listeners ngoài ra có thể type-hint bất kỳ dependencies họ cần trong hàm constructors. Tất cả event listeners được giải quyết bởi Laravel service container, vì vậy dependencies sẽ được injected tự động.

Dừng thông báo của một Event

Thỉnh thoảng, bạn muốn dừng các thông bảo của một event đến listeners. bạn có thể làm bằng cách trả về false từ hàm handle của listener.

Queued Event Listeners

Queueing listeners sẽ rất tiện lợi nếu listener của bạn thực hiện một task tốn nhiều thời gian như gửi e-mail hoặc tạo một HTTP request. Trước khi bắt đầu với queued listeners, đảm bảo rằng configure your queue và bắt đầu một queue listener trên server hoặc local.

Để chỉ định listener nên được queued, thêm ShouldQueue interface vào class listener. Listeners tạo bởi lệnh event:generate Artisan đã có interface imported vào namespace hiện tại, bạn có thể sử dụng nó trực tiếp:

<?php

namespace App\Listeners;

use App\Events\OrderShipped;
use Illuminate\Contracts\Queue\ShouldQueue;

class SendShipmentNotification implements ShouldQueue
{
    //
}

OK! Bây giờ, khi listener được gọi từ event, nó sẽ tự động queued bởi event dispatcher using Laravel's queue system. Nếu không có exeption ném ra khi listener được thực thi bởi queue, queued job sẽ tự động xóa sau khi hoàn thành.

Truy xuất vào Queue thủ công

Nếu bạn cần truy xuất vào queue qua hai hàm deleterelease, bạn có thể sử dụng trait Illuminate\Queue\InteractsWithQueue. Nó đã được import sẵn, và bạn có thể sử dụng hai hàm này:

<?php

namespace App\Listeners;

use App\Events\OrderShipped;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

class SendShipmentNotification implements ShouldQueue
{
    use InteractsWithQueue;

    public function handle(OrderShipped $event)
    {
        if (true) {
            $this->release(30);
        }
    }
}

Firing Events

Để bắn event, bạn có thể sử dụng event helper. Hàm helper này sẽ dispatch event cho tất cả các listeners được đăng ký. Vì event helper là toàn cục, bạn có thể gọi nó ở bất cứ đâu trong ứng dụng:

<?php

namespace App\Http\Controllers;

use App\Order;
use App\Events\OrderShipped;
use App\Http\Controllers\Controller;

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));
    }
}

Khi testing, sẽ rất hữ ích nếu khẳng định events được bắn fired mà không có sự trigger của listeners. Laravel's built-in testing helpers đã có sẵn.

Event Subscribers

Viết Event Subscribers

Event subscribers là các classes mà có hteer subscribe nhiều events từ chính nó, cho phép bạn định nghĩa vào event handlers trong một class. Subscribers nên được định nghĩa một hàm subscribe, và truyền vào một event dispatcher instance. bạn có thể gọi hàm listen trong dispatcher để đăng ký event listeners:

<?php

namespace App\Listeners;

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    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'
        );
    }

}

Đăng ký Event Subscribers

Sau khi viết subscriber, bạn đã sẵn sàng đăng ký nó với event dispatcher. Bạn có thể đăng ký subscribers bằng cách dùng thuộc tính $subscribe trong EventServiceProvider. Ví dụ, hãy thêm UserEventSubscriber vào danh sách:

<?php

namespace App\Providers;

use Illuminate\Foundation\Support\Providers\EventServiceProvider 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 = [
        'App\Listeners\UserEventSubscriber',
    ];
}
Nguồn: https://laravel.com/docs/5.3/events