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