Laravel 事件与监听器

下面是一个完整的用户注册事件和监听器的实现示例,包含事件、监听器、注册、触发等完整流程。

一、软件版本

  • php: 8.2.20
  • laravel: 11
  • mysql: 8.0.29

二、完整实现过程

1.创建事件

1.1 首先创建用户注册事件

bash 复制代码
php artisan make:event UserRegistered

1.2 编辑app/Events/UserRegistered.php

php 复制代码
<?php
namespace App\Events;

use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class UserRegistered
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * 创建一个新的事件实例
     */
    public function __construct(public User $user)
    {
    
    }
}

2. 创建监听器

2.1 创建两个监听器:发送欢迎邮件 和记录注册日志。

bash 复制代码
php artisan make:listener SendWelcomeEmail --event=UserRegistered
php artisan make:listener LogUserRegistration --event=UserRegistered

2.2 编辑 app/Listeners/SendWelcomeEmail.php

php 复制代码
<?php

namespace App\Listeners;

use App\Events\UserRegistered;
use App\Mail\WelcomeEmail;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\Mail;

class SendWelcomeEmail implements ShouldQueue
{
    /**
     * 处理事件
     *
     * @param UserRegistered $event
     * @return void
     */
    public function handle(UserRegistered $event)
    {
        Mail::to($event->user->email)
            ->send(new WelcomeEmail($event->user));
    }

    /**
     * 处理失败的任务
     *
     * @param UserRegistered $event
     * @param \Throwable $exception
     * @return void
     */
    public function failed(UserRegistered $event, $exception)
    {
        // 发送失败通知给管理员
    }
}

2.3 编辑 app/Listeners/LogUserRegistration.php

php 复制代码
<?php

namespace App\Listeners;

use App\Events\UserRegistered;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Log;

class LogUserRegistration
{
    /**
     * Create the event listener.
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     */
    public function handle(UserRegistered $event): void
    {
        Log::info('新用户注册完成: '.$event->user->email);
    }
}

3. 注册事件和监听器

3.1 创建 app/Providers/EventServiceProvider.php

bash 复制代码
php artisan make:provider EventServiceProvider

3.2 编辑 app/Providers/EventServiceProvider.php

php 复制代码
<?php

namespace App\Providers;

use App\Events\UserRegistered;
use App\Listeners\LogUserRegistration;
use App\Listeners\SendWelcomeEmail;
use Illuminate\Support\ServiceProvider;

class EventServiceProvider extends ServiceProvider
{
    /**
     * 事件与监听器的映射关系
     */
    protected $listen = [
        UserRegistered::class => [
            SendWelcomeEmail::class,
            LogUserRegistration::class
        ],
    ];

    /**
     * Register services.
     */
    public function register(): void
    {
        //
    }

    /**
     * Bootstrap services.
     * 注册任何其他事件
     */
    public function boot(): void
    {
        //
    }
}

4. 创建邮件类

4.1 创建欢迎邮件模板

bash 复制代码
php artisan make:mail WelcomeEmail --markdown=emails.welcome

4.2 编辑 app/Mail/WelcomeEmail.php

php 复制代码
<?php

namespace App\Mail;

use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class WelcomeEmail extends Mailable
{
    use Queueable, SerializesModels;

    /**
     * 创建一个新的消息实例
     *
     * @param User $user
     */
    public function __construct(public User $user)
    {

    }

    /**
     * 构建消息
     *
     * @return $this
     */
    public function build()
    {
        return $this->markdown('emails.welcome')
                    ->subject('欢迎加入我们的平台');
    }
}

4.2 编辑 resources/views/emails/welcome.blade.php

html 复制代码
@component('mail::message')
    # 欢迎, {{ $user->name }}!

    感谢您注册我们的平台。您的账户已经成功创建。

    @component('mail::button', ['url' => url('/dashboard')])
        访问仪表盘
    @endcomponent

    谢谢,
    {{ config('app.name') }}
@endcomponent

4.3 邮件配置 .env

bash 复制代码
MAIL_MAILER=smtp
MAIL_SCHEME=null
MAIL_HOST=smtp.163.com
MAIL_PORT=465
MAIL_ENCRYPTION=ssl
MAIL_USERNAME=xxx@163.com
MAIL_PASSWORD=GTkCEsxxxxxxx
MAIL_FROM_ADDRESS="xxxx@163.com"
MAIL_FROM_NAME="${APP_NAME}"

5. 测试事件

5.1 创建测试

bash 复制代码
php artisan make:test UserRegistrationTest

5.2 编辑 tests/Feature/UserRegistrationTest.php

php 复制代码
<?php

namespace Tests\Feature;

use App\Events\UserRegistered;
use App\Mail\WelcomeEmail;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Mail;
use Tests\TestCase;

class UserRegistrationTest extends TestCase
{
    use RefreshDatabase;

    public function test_user_registration_dispatches_event()
    {
        Event::fake();

        $user = User::factory()->create();

        event(new UserRegistered($user));

        Event::assertDispatched(UserRegistered::class, function ($event) use ($user) {
            return $event->user->id === $user->id;
        });
    }

    public function test_welcome_email_is_sent()
    {
        Mail::fake();

        $user = User::factory()->create();

        event(new UserRegistered($user));

        Mail::assertSent(WelcomeEmail::class, function ($mail) use ($user) {
            return $mail->user->id === $user->id;
        });
    }
}

5.3 测试结果

6. 在控制器中触发事件

6.1 编辑 app/Http/Controllers/Auth/RegisterController.php

php 复制代码
<?php

namespace App\Http\Controllers\Auth;

use App\Events\UserRegistered;
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Support\Facades\Hash;

class RegisterController extends Controller
{
    public function register()
    {
        // 验证逻辑...
        
        $user = User::create([
            'name' => request('name'),
            'email' => request('email'),
            'password' => Hash::make(request('password')),
        ]);

        // 触发用户注册事件
        event(new UserRegistered($user));
        
        // 或者使用静态方法
        // UserRegistered::dispatch($user);

        return redirect('/home')->with('success', '注册成功!');
    }
}

7. 访问控制器后

7.1 laravel日志中显示

7.2 目标邮箱收到邮件

相关推荐
damoluomu5 天前
挑 PHP CMS 之前,先学会看它的协议
php
子非鱼a6 天前
【WEB】Online ToolWEB
php
PHP实战开发录6 天前
Nginx上传大文件为什么报413
nginx·php·开发
damoluomu6 天前
国产企业级 PHP CMS:哪些能免费商用
php
郑州光合科技余经理6 天前
同城外卖小程序开发:下单成功后,后台导出能不能对上用户端状态
开发语言·前端·git·后端·uni-app·php·ai编程
MyFreeIT6 天前
Android PHP Manual
php
aixingpan6 天前
aixingpan.cn API开发文档:api_docs_trichart_natal_progression_sec_transit2接口指南
前端·php
sbjdhjd7 天前
从日志包含到临时文件竞争:文件包含进阶复盘中的 Docker、Windows 与 Session 限制
网络·安全·web安全·网络安全·数据挖掘·php·rce
daxiangxm7 天前
【趣味休息】“围住小猫在线玩”-“困住小猫”,又回来了
数据结构·人工智能·vscode·github·php
星光开发者7 天前
基于Spring Boot的充电桩管理系统的设计与实现-计算机毕设【课程设计】57105
vue.js·spring boot·vscode·mysql·django·php·express