Skip to content

Laravel - 事件处理

Laravel - 事件和监听器 (Events and Listeners)

Section titled “Laravel - 事件和监听器 (Events and Listeners)”

Laravel 的事件(events)提供了简单的观察者模式(observer pattern)实现,允许您订阅和监听应用程序中发生的各种事件。事件是解耦应用程序各个方面的绝佳方式,因为单个事件可以有多个相互独立的监听器(listeners)。

通常的工作流程包括以下步骤:

  1. 定义事件类(Event Class): 创建一个表示事件的类。这个类通常包含与事件相关的数据。
  2. 定义监听器类(Listener Class(es)): 创建一个或多个监听器类,它们将在事件被调度(dispatched)后处理该事件。
  3. 注册事件和监听器: 在 EventServiceProvider 中将事件映射到其对应的监听器。
  4. 调度事件(Dispatch an Event): 在您的应用程序代码中的某个地方触发该事件。

您可以使用 Artisan CLI 命令生成一个新的事件类:

php artisan make:event PodcastProcessed

此命令将创建一个新文件,例如 app/Events/PodcastProcessed.php。事件类通常是一个简单的数据容器。例如,我们的 PodcastProcessed 事件可能包含已处理的播客的 Eloquent 模型:

app/Events/PodcastProcessed.php
namespace App\Events;
use App\Models\Podcast; // 假设您有一个 Podcast 模型
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class PodcastProcessed
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public Podcast $podcast;
/**
* 创建一个新的事件实例。
*
* @param \App\Models\Podcast $podcast
* @return void
*/
public function __construct(Podcast $podcast)
{
$this->podcast = $podcast;
}
}

注意:SerializesModels trait 将优雅地序列化(serialize)任何 Eloquent 模型,如果事件对象被序列化的话,例如在使用队列监听器(queued listeners)时。Dispatchable trait 允许轻松调度事件。

接下来,您需要一个或多个监听器来处理该事件。您可以使用 Artisan 命令生成一个监听器:

php artisan make:listener SendPodcastNotification --event=PodcastProcessed

这将创建 app/Listeners/SendPodcastNotification.php。--event 选项将在监听器的 handle 方法中对 PodcastProcessed 事件进行类型提示(type-hint)。在 handle 方法内部,您可以执行对事件做出响应的操作。

app/Listeners/SendPodcastNotification.php
namespace App\Listeners;
use App\Events\PodcastProcessed;
use Illuminate\Contracts\Queue\ShouldQueue; // 可选:用于队列监听器
use Illuminate\Queue\InteractsWithQueue; // 可选:用于队列监听器
// use Illuminate\Support\Facades\Mail; // 示例用法
class SendPodcastNotification // implements ShouldQueue // 可选
{
// use InteractsWithQueue; // 可选
/**
* 创建事件监听器。
*
* @return void
*/
public function __construct()
{
//
}
/**
* 处理事件。
*
* @param \App\Events\PodcastProcessed $event
* @return void
*/
public function handle(PodcastProcessed $event)
{
// 访问事件中的播客: $event->podcast
// 例如,发送电子邮件通知:
// Mail::to($event->podcast->user_email)->send(new PodcastReadyNotification($event->podcast));
logger('Podcast processed: ' . $event->podcast->title);
}
}

监听器也可以通过实现 ShouldQueue 接口来排队。这对于可以在后台执行的任务很有用。

EventServiceProvider(位于 app/Providers/EventServiceProvider.php)是您注册事件监听器的地方。它包含一个 $listen 数组属性,用于将事件映射到其监听器。

app/Providers/EventServiceProvider.php
namespace App\Providers;
use App\Events\PodcastProcessed;
use App\Listeners\SendPodcastNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
// use Illuminate\Support\Facades\Event; // 简单使用 $listen 数组时不需要
class EventServiceProvider extends ServiceProvider
{
/**
* 应用程序的事件到监听器的映射。
*
* @var array<class-string, array<int, class-string>>
*/
protected $listen = [
PodcastProcessed::class => [
SendPodcastNotification::class,
// 您可以在此处为同一事件添加更多监听器
// 例如: App\Listeners\UpdatePodcastAnalytics::class,
],
// 其他事件及其监听器...
];
/**
* 为您的应用程序注册任何事件。
*
* @return void
*/
public function boot()
{
//
}
/**
* 确定是否应自动发现事件和监听器。
*
* @return bool
*/
public function shouldDiscoverEvents()
{
return false; // 如果偏好自动发现,设置为 true
}
}

如果您使用 --event 选项生成了监听器,Laravel 可能已经为您添加了此映射。否则,将您的事件及其监听器添加到 $listen 数组中。

要调度(dispatch)事件,您可以使用 event 辅助函数或 Event Facade 的 dispatch 方法。通常,您会在某个操作完成后调度事件。

// 控制器或服务中的示例
use App\Events\PodcastProcessed;
use App\Models\Podcast; // 假设您有一个 Podcast 模型
// ... 在您的代码中,在播客处理后 ...
$podcast = Podcast::find(1);
if ($podcast) {
// 使用 event 辅助函数
event(new PodcastProcessed($podcast));
// 或者,如果您的事件类使用了 Dispatchable trait:
// PodcastProcessed::dispatch($podcast);
}

当事件被调度时,Laravel 将调用该事件所有注册监听器的 handle 方法,并将事件实例传递给它们。

让我们考虑一个常见的场景:当新用户注册时发送欢迎邮件。

  1. 事件(Event): UserRegistered(例如:php artisan make:event UserRegistered)。此事件将携带 User 模型。

    app/Events/UserRegistered.php
    namespace App\Events;
    use App\Models\User;
    use Illuminate\Foundation\Events\Dispatchable;
    use Illuminate\Queue\SerializesModels;
    class UserRegistered
    {
    use Dispatchable, SerializesModels;
    public User $user;
    public function __construct(User $user) { $this->user = $user; }
    }
  2. 监听器(Listener): SendWelcomeEmail(例如:php artisan make:listener SendWelcomeEmail --event=UserRegistered)。此监听器将使用 Laravel 的 Mail 功能。

    app/Listeners/SendWelcomeEmail.php
    namespace App\Listeners;
    use App\Events\UserRegistered;
    use Illuminate\Support\Facades\Mail;
    use App\Mail\WelcomeMail; // 假设您创建了一个 Mailable: php artisan make:mail WelcomeMail
    class SendWelcomeEmail
    {
    public function handle(UserRegistered $event)
    {
    Mail::to($event->user->email)->send(new WelcomeMail($event->user));
    }
    }
  3. 注册: 将 UserRegistered::class => [SendWelcomeEmail::class] 添加到 EventServiceProvider.php 中的 $listen。

  4. 调度: 在您的用户注册控制器中,成功创建用户后:

    // 在您的 Auth Controller 或 Registration Service 中
    use App\Events\UserRegistered;
    use App\Models\User;
    // ...
    $user = User::create($validatedData);
    event(new UserRegistered($user));
    // 或者 UserRegistered::dispatch($user);
    // ...

此设置确保无论何时注册新用户并调度 UserRegistered 事件,SendWelcomeEmail 监听器都会自动被调用以发送欢迎邮件。这将发送邮件的逻辑与注册过程本身解耦。

事件和监听器是构建健壮、可维护和可扩展的 Laravel 应用程序的强大工具。有关更高级的主题,例如事件订阅者(event subscribers)、队列监听器和广播事件(broadcasting events),请查阅官方 Laravel 文档。