发布于 2026-01-06 2 阅读
0

Laravel 8 事件和监听器及实用示例 DEV's Worldwide Show and Tell Challenge Presented by Mux: Pitch Your Projects!

Laravel 8 事件和监听器及实际示例

由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!

大家好,今天我想聊聊 Laravel 中的事件和监听器。在编程中,为了编写可扩展、可重用且简洁的代码,你需要遵循一些编程原则,其中之一就是SOLID 原则。今天我不会深入讲解 SOLID 原则,只会重点介绍其中的一点,即S ,它代表单一职责原则(Single Responsibility Principle )。该原则指出:

一个类应该只有一个改变的理由,也就是说,一个类应该只有一个功能。

这意味着一个类应该只执行一项任务。很多时候,我们总是给类添加很多功能,所以如果类发生变化,应用程序的很多部分都会崩溃,这不是一个好的做法。
因此,我将引入事件和监听器来帮助我们的类只执行一项任务。

点击我的个人资料即可关注我,获取更多最新动态。

什么是事件?

事件是我们接入应用程序活动的方式,它只是观察活动的一种方式,例如登录,可以创建一个类来监视登录活动,当用户登录时,事件类可以执行一些函数。

什么是倾听者?

监听器(Listener)是一个监听与其映射的事件并执行相应任务的类,也就是说,它们负责为特定事件执行特定任务。
举例来说,您可能希望向应用程序的新用户发送欢迎邮件,并根据用户注册时提供的信息为其分配角色等等。您不会希望在 RegisterController 中执行所有这些操作,因为这违反了 SOLID 原则的第一条——控制器不应执行多个任务。RegisterController 只需执行新用户的注册操作即可。因此,需要在注册过程中执行一个事件,而分配角色、发送电子邮件等操作则由该事件下的各个监听器分别负责。
在本文中,我将在一个事件中编写一个监听器,该监听器会将应用程序中每个用户的登录信息存储在一个表中。这只是一个示例,旨在向您展示其工作原理。
如果你已经有一个带有身份验证功能的 Laravel 项目,你可以直接按照以下步骤操作;或者你可以参考我的文章《使用 Laravel Breeze 进行 Laravel 基本登录和注册》,我将使用我系统上的文章项目。

步骤 1:在 EventServiceProvider 中注册事件和监听器

为了使我们的事件和监听器正常工作,我们必须在EventServiceProvider类中注册它们。该类在安装 Laravel 项目时已经预先设置好了。因此,请转到app/Providers/EventServiceProvider.php 文件,然后点击 “注册”。事件和监听器以键值对的形式注册在受保护的 $listen中。从上图可以看出,事件和监听器已经注册。Registered ::class是事件,而SendEmailVerificationNotification::class是监听器,所以我们将添加我们自己的监听器。
EventServiceProvider.php



<?php

namespace App\Providers;

use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
use App\Events\LoginHistory;
use App\Listeners\storeUserLoginHistory;

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [
        Registered::class => [
            SendEmailVerificationNotification::class,
        ],
        LoginHistory::class => [
            StoreUserLoginHistory::class,
        ]
    ];

    /**
     * Register any events for your application.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}


Enter fullscreen mode Exit fullscreen mode

我们添加了一个名为LoginHistory 的事件类和一个名为StoreUserLoginHistory的监听器。请注意,我们在这里是这样调用该类的:` use App\Events\LoginHistory;``use App\Listeners\storeUserLoginHistory;`。别担心,我知道您可能会疑惑该类在我们的应用程序中并不存在,我们将在下一步中生成它。您可以像这样添加任意数量的事件和监听器,甚至更多。



 protected $listen = [
        Event1::class => [
            Listener1::class,
            Listener2::class
        ],
        Event2::class => [
            Listener5::class,
            Listener7::class
        ],
        Event3::class => [
            Listener4::class,
            Listener7::class,
            Listener9::class
        ],
 ];


Enter fullscreen mode Exit fullscreen mode

步骤二:生成事件和监听器

之前,我们在 EventServiceProvider 中编写事件类和监听器,所以为了一次性生成它们,我们运行以下命令。

php artisan event:generate

生成事件
该命令将自动生成事件提供程序中找到的所有事件和监听器。
文件结构

步骤 3:编写事件和监听器类

记住,我们的目标是将应用程序的所有登录信息存储在一个表格中,所以请点击app/Events/LoginHistory.php并按如下方式编辑。



class LoginHistory
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $user;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct($user)
    {
        $this->user = $user;
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new PrivateChannel('channel-name');
    }
}


Enter fullscreen mode Exit fullscreen mode

从上面的代码可以看出,该事件接收 $user 参数(即用户信息),并将其传递给监听器。
点击app/Listeners/storeUserLoginHistory.php文件,我们将在这里编写存储登录历史记录的主要逻辑。在 handle 方法中,添加以下代码。



    public function handle(LoginHistory $event)
    {
        $current_timestamp = Carbon::now()->toDateTimeString();

        $userinfo = $event->user;

        $saveHistory = DB::table('login_history')->insert(
            ['name' => $userinfo->name, 'email' => $userinfo->email, 'created_at' => $current_timestamp, 'updated_at' => $current_timestamp]
        );
        return $saveHistory;
    }


Enter fullscreen mode Exit fullscreen mode

另外,请记住在类之前调用​​ CarbonDB facade 。



use Illuminate\Support\Facades\DB;
use Carbon\Carbon;


Enter fullscreen mode Exit fullscreen mode

我们的监听器现在看起来像这样: 我们试图通过监听器将名称、电子邮件、创建时间和更新时间添加到login_history表中,也就是说,当任何用户登录时,它将获取该信息并将其存储在表中。
听众

第四步:创建表并迁移

我不会详细解释这一步,我有一些文章对此进行了解释,可以从我的个人资料
中查看。 创建迁移文件 将列添加到迁移文件中, 然后进行迁移。 现在我们的表已经存在于数据库中了。
创建迁移文件

迁移文件

迁移

数据库

步骤 5:调度事件

这是最后一步,我们需要在 LoginController 中调用事件。如果您使用的是 Laravel 7 或更低版本,可以在 LoginController.php 中创建一个方法,如下所示。



    protected function authenticated() {

        $user = Auth::user();

        event(new LoginHistory($user));
    }


Enter fullscreen mode Exit fullscreen mode

但本文使用的是 Laravel Breeze,这是一个 16 天前发布的简单 UI 框架。因此,我将打开位于app/Http/Requests/Auth/LoginRequest.php的LoginRequest.php 文件,并在authenticate()方法中调用我的事件并将 $user 传递给该类。



  public function authenticate()
    {
        $this->ensureIsNotRateLimited();

        if (! Auth::attempt($this->only('email', 'password'), $this->filled('remember'))) {
            RateLimiter::hit($this->throttleKey());

            throw ValidationException::withMessages([
                'email' => __('auth.failed'),
            ]);
        }

        $user = Auth::user();

        event(new LoginHistory($user));

        RateLimiter::clear($this->throttleKey());
    }


Enter fullscreen mode Exit fullscreen mode

我只添加了`$user = Auth::user();``event(new LoginHistory($user));`,注意我是如何分发事件的,你可以使用 ` EventClass::dispatch(); ` 或 `event(new LoginHistory($user));` ,但我们使用的是`event(new LoginHistory($user));`
所以当用户尝试登录时,如果用户已通过身份验证,事件就会被触发,监听器会保存登录历史记录。
这是我两次登录后的结果。
数据库

关注我,阅读更多文章,欢迎留言、提出建议和分享感受。
我目前正在寻找 PHP 后端工程师的职位,尤其擅长 Laravel 框架。

点击链接查看我的个人资料并关注我

感谢您抽出时间

文章来源:https://dev.to/kingsconsult/laravel-8-events-and-listeners-with-practical-example-9m7