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是监听器,所以我们将添加我们自己的监听器。
<?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()
{
//
}
}
我们添加了一个名为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
],
];
步骤二:生成事件和监听器
之前,我们在 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');
}
}
从上面的代码可以看出,该事件接收 $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;
}
另外,请记住在类之前调用 Carbon和DB facade 。
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
我们的监听器现在看起来像这样: 我们试图通过监听器将名称、电子邮件、创建时间和更新时间添加到login_history表中,也就是说,当任何用户登录时,它将获取该信息并将其存储在表中。
第四步:创建表并迁移
我不会详细解释这一步,我有一些文章对此进行了解释,可以从我的个人资料
中查看。 创建迁移文件, 将列添加到迁移文件中, 然后进行迁移。 现在我们的表已经存在于数据库中了。



步骤 5:调度事件
这是最后一步,我们需要在 LoginController 中调用事件。如果您使用的是 Laravel 7 或更低版本,可以在 LoginController.php 中创建一个方法,如下所示。
protected function authenticated() {
$user = Auth::user();
event(new LoginHistory($user));
}
但本文使用的是 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());
}
我只添加了`$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

