Tách rời Logic với Laravel Events và Listeners

· 3 min read

Hệ thống Event của Laravel cung cấp một triển khai observer đơn giản, cho phép bạn đăng ký và lắng nghe các event khác nhau trong ứng dụng. Điều này hoàn hảo để tách rời các khía cạnh khác nhau của logic ứng dụng.

Vấn đề: Tight Coupling

Hãy tưởng tượng một phương thức lưu trữ đăng ký người dùng:

public function store(Request $request) {
    $user = User::create($request->validated());

    // Gửi email
    Mail::to($user)->send(new WelcomeEmail($user));

    // Logging
    Log::info("User registered: " . $user->id);

    // Đăng ký newsletter
    Newsletter::subscribe($user->email);
    
    return redirect('/home');
}

Controller này xử lý quá nhiều trách nhiệm. Nếu việc gửi email thất bại, hoặc logic thay đổi, bạn phải sửa controller.

Giải pháp: Events

1. Tạo Event

php artisan make:event UserRegistered

Truyền dữ liệu (User) vào event:

class UserRegistered
{
    use Dispatchable, SerializesModels;

    public $user;

    public function __construct(User $user)
    {
        $this->user = $user;
    }
}

2. Tạo Listeners

Tạo listeners cho mỗi hành động riêng biệt:

php artisan make:listener SendWelcomeEmail --event=UserRegistered
php artisan make:listener SubscribeToNewsletter --event=UserRegistered

Ví dụ Listener SendWelcomeEmail:

public function handle(UserRegistered $event)
{
    Mail::to($event->user)->send(new WelcomeEmail($event->user));
}

3. Đăng ký Events & Listeners

Trong môi trường local, Laravel có thể tự động phát hiện listeners. Hoặc bạn có thể đăng ký rõ ràng trong EventServiceProvider (hoặc AppServiceProvider trong Laravel 11+):

Event::listen(
    UserRegistered::class,
    [SendWelcomeEmail::class, 'handle']
);
Event::listen(
    UserRegistered::class,
    [SubscribeToNewsletter::class, 'handle']
);

4. Phát Event

Bây giờ controller của bạn trở nên sạch sẽ:

public function store(Request $request) {
    $user = User::create($request->validated());

    UserRegistered::dispatch($user);
    
    return redirect('/home');
}

Queued Listeners

Nếu việc gửi email chậm, bạn có thể queue listener ngay lập tức bằng cách thêm interface ShouldQueue:

use Illuminate\Contracts\Queue\ShouldQueue;

class SendWelcomeEmail implements ShouldQueue
{
    public function handle(UserRegistered $event)
    {
        // Bây giờ nó sẽ chạy trong background worker!
    }
}

Events và Listeners làm cho ứng dụng của bạn dễ test, bảo trì và mở rộng hơn.

Bình luận