Nhảy tới nội dung

Events

Hệ thống Event cho phép các phần khác nhau của ứng dụng giao tiếp với nhau một cách loose coupling.

Định nghĩa Event

Event Class

<?php

namespace App\Events;

class UserRegistered
{
public function __construct(
public readonly int $userId,
public readonly string $email,
) {}
}

Event với Trait Dispatchable

<?php

namespace App\Events;

use Vietiso\Core\Event\Dispatchable;

class OrderCreated
{
use Dispatchable;

public function __construct(
public readonly int $orderId,
public readonly float $total,
) {}
}

Đăng ký Listeners

Trong Service Provider

<?php

namespace App\Providers;

use Vietiso\Core\Event\EventServiceProvider as ServiceProvider;

class EventServiceProvider extends ServiceProvider
{
protected function register(): void
{
$this->listen(UserRegistered::class, SendWelcomeEmail::class);
$this->listen(UserRegistered::class, CreateUserProfile::class);

$this->listen(OrderCreated::class, [
SendOrderConfirmation::class,
UpdateInventory::class,
NotifyAdmin::class,
]);
}
}

Đăng ký Runtime

use Vietiso\Core\Event\Facade\Event;

// Listener là class
Event::listen(UserRegistered::class, SendWelcomeEmail::class);

// Listener là closure
Event::listen(UserRegistered::class, function (UserRegistered $event) {
// Handle event
Log::info("User registered: {$event->email}");
});

// Listener là array [class, method]
Event::listen(UserRegistered::class, [NotificationService::class, 'onUserRegistered']);

Dispatch Events

Sử dụng Facade

use Vietiso\Core\Event\Facade\Event;

// Dispatch event class
Event::dispatch(new UserRegistered($user->id, $user->email));

// Dispatch event name với payload
Event::dispatch('user.registered', ['user' => $user]);

Sử dụng Trait Dispatchable

// Event class có trait Dispatchable
OrderCreated::dispatch($order->id, $order->total);

Tạo Listeners

Listener Class

<?php

namespace App\Listeners;

use App\Events\UserRegistered;
use Vietiso\Core\Mail\Facade\Mail;

class SendWelcomeEmail
{
public function __invoke(UserRegistered $event): void
{
Mail::to($event->email)->send(new WelcomeMail());
}
}

Listener với Handle Method

<?php

namespace App\Listeners;

use App\Events\OrderCreated;

class UpdateInventory
{
public function handle(OrderCreated $event): void
{
$order = Order::find($event->orderId);

foreach ($order->items as $item) {
Product::where('id', $item->product_id)
->decrement('stock', $item->quantity);
}
}
}

Event Subscribers

Subscribers cho phép đăng ký nhiều listeners trong một class:

<?php

namespace App\Subscribers;

use Vietiso\Core\Event\EventSubscriberInterface;

class UserEventSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
UserRegistered::class => 'onUserRegistered',
UserLoggedIn::class => ['onUserLoggedIn', 'updateLastLogin'],
UserLoggedOut::class => 'onUserLoggedOut',
];
}

public function onUserRegistered(UserRegistered $event): void
{
// Handle registration
}

public function onUserLoggedIn(UserLoggedIn $event): void
{
// Handle login
}

public function updateLastLogin(UserLoggedIn $event): void
{
User::where('id', $event->userId)
->update(['last_login_at' => now()]);
}

public function onUserLoggedOut(UserLoggedOut $event): void
{
// Handle logout
}
}

Đăng ký Subscriber

Event::subscriber(UserEventSubscriber::class);

Wildcard Events

Lắng nghe nhiều events với pattern:

// Lắng nghe tất cả events bắt đầu với 'user.'
Event::listen('user.*', function (string $eventName, array $data) {
Log::info("User event: {$eventName}", $data);
});

// Lắng nghe tất cả order events
Event::listen('order.*', OrderEventLogger::class);

Dừng Event Propagation

Trả về false để dừng propagation đến các listeners tiếp theo:

Event::listen(OrderCreated::class, function (OrderCreated $event) {
if ($event->total > 10000) {
// Cần review manual, dừng các listeners khác
return false;
}
});

Clear Listeners

// Xóa tất cả listeners của một event
Event::clearListeners(UserRegistered::class);

Ví dụ thực tế

Order Processing

// Events
class OrderCreated { ... }
class OrderPaid { ... }
class OrderShipped { ... }

// Listeners
class SendOrderConfirmation
{
public function __invoke(OrderCreated $event): void
{
$order = Order::find($event->orderId);
Mail::to($order->user->email)
->send(new OrderConfirmationMail($order));
}
}

class ProcessPayment
{
public function __invoke(OrderPaid $event): void
{
// Process payment logic
}
}

// Dispatch
OrderCreated::dispatch($order->id, $order->total);

Logging & Analytics

Event::listen('*', function (string $event, array $payload) {
Log::channel('events')->info($event, $payload);
});