Laravel - Listen to Event in Package Development

Laravel – Tìm hiểu và đi sâu vào Event Handling

Bonjour mina-san,

Nay lại là 1 bài về Laravel nè, một cái stuff rất là hay dành cho hệ thống của chúng ta và giúp hệ thống chúng ta dynamic hơn.

Main documentation: https://laravel.com/docs/5.8/events

1/ Giới thiệu qua ngôn ngữ tiếng Việt

Event (hay còn dc biết đến là Hook) là 1 phương thức để các bạn inject 1 specific-code nào đó vào 1 luồng chạy trong business logic của bạn.

Điều này khiến cho cái flow của bạn nó dynamic hơn cũng như là tuân thủ nhẹ cái rule trong SOLID.

Cuộc sống không Event

Ví dụ cụ thể, mình có 1 flow là Update User, basically nó như vậy ở version 1:

  • Update
  • Return result

Trong tương lai, ở version 2, bỗng nhưng dc request là khi User update thì cũng phải update cái Audit Log để track lại. Theo cách thông thường thì ta sẽ:

  • Update (code cũ)
  • Audit Log (code mới)
  • Return result (code cũ)

Trong tương lai, nếu lại update thêm actions nữa thì ta lại append thêm code => vi phạm Rule O của SOLID cũng như là khiến controller nó như củ chuối. Mà nếu ko muốn vi phạm Rule Solid thì fải tạo lại 1 Controller mới và extend từ cái cũ về, override lại cái method edit,… blah blah blah. Oh shit 😰

Cuộc sống có Event

Nếu xài Event thì nó sẽ như sau:

  • Update
  • Fire Event
    • Run Listener(s) that mapped to the current Event
  • Result result

Và mỗi lần update, ta chỉ cần tạo thêm Listener và bind vào Event đó. Khiến ta ko vi phạm Rule của SOLID mà lại đẹp code, flow hoàn hảo hơn.

Các khi Event dc fired, các Listeners sẽ dc chạy tuần tự từ trên xuống dưới (0 => n). Oh la la.

Và ngoài ra nó lại dc support tận răng, dễ debug,…

Đại loại dễ hiểu lã vậy 😘

2/ Laravel Event Handling – Core Concepts

Event

Event là sự kiện, dc tạo ra và chạy tại một thời điểm nào đó trong business flow. Mỗi Event khác nhau sẽ có những data khác nhau để truyền vào (tùy theo business của bạn :D).

Event sẽ không làm gì ngoài nhận vào data nhé. No LOGIC HERE ❌.

Listener

Listener là nơi xử lý (process) cái event của bạn khi mà event của bạn dc dispatch.

Nơi mà bạn sẽ define những logic cần thiết để application của bạn hoạt động theo đúng yêu cầu. INPUT LOGIC HERE ✔.

Queued Listener

Như trên, có điều listener này là dc chạy qua Laravel Queue (background task) hay gửi Message Queue đi nơi khác cho microservice nào đó xử lý thay vì phải xử lý trực tiếp tại thread hiện tại 😜.

Dispatching Event

Là tại 1 thời điểm nào đó ở luồng chạy business của chúng ta, với Event đã dc tạo ra, ta sẽ dispatch (run) Event này và truyền vào những data nhất định cho Event đó.

Khi dispatched thì Laravel nó sẽ tự tìm tới những Listeners đã dc mapping với Event và sẽ chạy những Listener(s) đó.

Ví dụ: User đăng ký xong => chạy event Registered.

Event Subscriber

Cũng là một phương thức để lắng nghe (listen) một Event, có điều là nó có thể listen nhiều Events chỉ trong 1 class và ta sẽ define thông qua property subscribe trong ServiceProvider class.

Event Discovery

Cũng giống như Service Provider discovery, Laravel’s engine sẽ tự Discover những Events trong package của bạn.

Cụ thể là bạn mở file composer.json trong project Laravel lên xem, nó có object script về “post-autoload-dump”. Nên cứ “composer dump-autoload” là nó sẽ chạy và discover sau đó cache lại vào thư mục bootstrap (Giải thích cho newbie vì mình chưa hề nói vụ này trong blog =)) )

Mặc định Laravel sẽ ko tự discover events.

Tính năng này chỉ có ở Laravel 5.8 trở lên nhé 😀

3/ Laravel Event Handling – Khởi tạo Service Provider

Sử dụng artisan sẽ giúp ta hoàn thành điều này với câu lệnh sau: “php artisan event:generate”

Chạy xong vào app/Providers

Thấy ngay cái class này liền hoho

<?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 = [
        //
    ];
}

Tất cả EventsListeners sẽ dc mapping vào cái property $listen, demo như sau (demo của Laravel  😜):

protected $listen = [
        Registered::class => [ // event là đã đăng ký
            SendEmailVerificationNotification::class, // listener là gửi email verification
        ],
     [...]
   ];

4/ Tạo Event đầu tiên cho App của bạn

Vào app/Events để tạo thêm Event cho mình nha, folder này chưa có thì các bạn tạo nha.

Mình sẽ tạo 1 cái event mới là: UserUpdated

Sau đó mình sẽ tiếp tục define đầu vào cho Event luôn, tại constructor, final code đây:

<?php

namespace App\Events;


use Illuminate\Queue\SerializesModels;
use App\User;

/**
 * Class UserUpdated
 * This Event will be run after an user account has been updated (by someone, admin,...???)
 */
class UserUpdated
{
	use SerializesModels;

	public $user;

	/**
	 * Constructor
	 * @param User $model
	 */
	public function __construct(User $model)
	{
		$this->user = $model;
	}
}

5/ Tạo Listener đầu tiên cho App của bạn

Vâng, như đề bài ở trên, mình cần AuditLog lại là ai Edit User này, blah blah blah. Giờ mình sẽ tạo Listener để Handle cho mình cái Logic này.

Vào app\Listensers (chưa có thư mục thì tạo nha), để tạo Listener nè. Mình đặt tên nó là AuditLogUserListener. Final code đây

Lưu ý là method handle cần fải dc public ra ngoài và nhận vào tham số đầu tiên luôn luôn là Event của bạn nhé 😉

<?php

namespace App\Listeners;


use App\Events\UserUpdated;

class AuditLogUserListener
{
	/**
	* Add Audit Log after user has been updated
	* @param UserUpdated $event
	*/
	public function handle(UserUpdated $event)
	{
		// get user model
		$model = $event->user;
		
		// audit log process
		....
		
		
		// done
	}
}

Có Listener rồi, bây giờ ta lại quay về EventServiceProvider để mapping Event với Listener nhé:

protected $listen = [
		//...
        'App\Events\UserUpdated' => [
            'App\Listeners\AuditLogUserListener',
        ],
    ];

Xong nè 😊

6/ Dispatch Event nào

Giờ lại chui vào cái UserController nè, tìm tới chỗ mà đã update User xong sẽ dispatch cái Event này là chuẩn bài.

Chúng ta sẽ dùng hàm event mà Laravel đã provide, ngắn gọn đơn giản. Chỉ đơn giản là tạo instance từ cái class Event và pass data vào cho nó thoy 😜. Code example here:

<?php

use App\Events\UserUpdated;

public function update($id) {
	$user = User::find($id);
	
	// .. update process
	
	$user->save();
	
	// RUN EVENT HERE
	event(new UserUpdated($user));
	
	// return....
}

Và kể từ giờ, mỗi khi ai đó Edit User => Event sẽ chạy => Listener sẽ chạy và thực hiện AuditLog cho mình 💖

Tương lai mình cần extend thêm thì chỉ cần tạo thêm Listener thoy 😉

7/ Kết luận

Với Event, nó có thể giúp cho application của bạn Flexible hơn nữa và ta có thể đạt dc rất là nhiều mục đích như là:

  • Không bị vi phạm Rule SOLID
  • Extendable
  • Flexible hơn khi handle về Business
  • (Dành cho package management) Giúp package của bạn flexible hơn để developers có thể handle specific cases.
  • Đẹp code hơn, bớt dài dòng vì đã tách ra dc rất nhiều.
  • Chuẩn gu Laravel dễ đi chém gió.

Merci các bạn đã quan tâm theo dõi nghen ❤

facebook
Seth Phát

Seth Phát

Mình là Phát - biệt danh Seth Phát. Hiện đang là một Sr. Full-Stack Engineer. Mình là một người yêu thích và đam mê lập trình và hiện tại đang theo về phần Web là chủ yếu. Mạnh Back-end và khá Front-end, vẫn đang theo đều cả 2 :v. Còn gì bằng khi được làm những thứ mà mình yêu thích, đam mê ;)

3 thoughts on “Laravel – Tìm hiểu và đi sâu vào Event Handling

Leave a Reply

Your email address will not be published. Required fields are marked *

Bình luận qua Facebook