Laravel 的事件系统在处理 Web 应用程序中的复杂数据时非常出色,因为它是构建解耦且绝对复杂的应用程序的基石。本指南讲述了有关事件监听的实现和使用的极其详细的要点,尤其是在 2024 年,通过 Laravel 11 中最广泛的内容和详细的代码示例事件监听器提供了全新的视角。
*(A) 理解事件和监听器背后的核心
*
那么,让我们来分解一下,Laravel 中的事件确实代表了应用程序内的特定事件。侦听器是响应所有此类应用程序事件的类。这种模式不断促进关注点分离,并允许更多模块化和可测试的代码。
*(B) 创建事件
*
让我们首先创建一个复杂的事件,我们将使用 Artisan 命令来更好地解释我们强烈建议您也这样做
php artisan make:事件 OrderPlaced
此命令将在 app/Events 目录中生成一个新的事件类。让我们检查更详细的事件类
`命名空间 App\Events;
使用 App\Models\Order;
使用应用程序\模型\用户;
使用 Illuminate\Foundation\Events\Dispatchable;
使用 Illuminate\Queue\SerializesModels;
使用 Illuminate\Broadcasting\InteractsWithSockets;
使用 Illuminate\Broadcasting\PrivateChannel;
使用 Illuminate\Contracts\Broadcasting\ShouldBroadcast;
类 OrderPlaced 实现 ShouldBroadcast
{
使用 Dispatchable、InteractsWithSockets、SerializesModels;
public $order; public $user; /** * Create a new event instance. * * @param \App\Models\Order $order * @param \App\Models\User $user * @return void */ public function __construct(Order $order, User $user) { $this->order = $order; $this->user = $user; } /** * Get the channels the event should broadcast on. * * @return \Illuminate\Broadcasting\Channel|array */ public function broadcastOn() { return new PrivateChannel('orders.'.$this->user->id); } /** * The event's broadcast name. * * @return string */ public function broadcastAs() { return 'order.placed'; }
}`
在这个扩展示例中,我们同时包含了 Order 和 User 模型。 SerializesModels 特征一直确保当事件传递给排队的侦听器时,我们的 Eloquent 模型能够正确序列化和反序列化。我们还实现了 ShouldBroadcast 接口,并定义了 broadcastOn 和 broadcastAs 方法,允许将此事件广播到 websockets 进行实时更新。
*创建多个监听器
*
对于单个事件,我们可能需要多个侦听器。让我们为 OrderPlaced 事件创建两个侦听器,以进一步扩展示例。我只是希望你们能确保掌握一切的要点。因此,请参阅下面的代码示例
php artisan make:listener SendOrderConfirmation --event=OrderPlaced
php artisan make:listener UpdateInventory --event=OrderPlaced
现在你应该明白这个命令行会在我们的 app/Listeners 目录中为我们提供几个新的监听器类。现在的问题是,在下面,我们将检查 SendOrderConfirmation 监听器,看看它如何进一步进展
`命名空间 App\Listeners;
使用 App\Events\OrderPlaced;
使用App\Mail\OrderConfirmation;
使用 Illuminate\Contracts\Queue\ShouldQueue;
使用 Illuminate\Queue\InteractsWithQueue;
使用 Illuminate\Support\Facades\Mail;
使用 Illuminate\Support\Facades\Log;
SendOrderConfirmation 类实现 ShouldQueue
{
使用 InteractsWithQueue;
/** * The number of times the job may be attempted. * * @var int */ public $tries = 3; /** * Handle the event. * * @param \App\Events\OrderPlaced $event * @return void */ public function handle(OrderPlaced $event) { $order = $event->order; $user = $event->user; try { Mail::to($user->email)->send(new OrderConfirmation($order)); Log::info('Order confirmation email sent', ['order_id' => $order->id, 'user_id' => $user->id]); } catch (\Exception $e) { Log::error('Failed to send order confirmation email', ['order_id' => $order->id, 'user_id' => $user->id, 'error' => $e->getMessage()]); $this->fail($e); } } /** * Handle a job failure. * * @param \App\Events\OrderPlaced $event * @param \Throwable $exception * @return void */ public function failed(OrderPlaced $event, $exception) { Log::error('Order confirmation listener failed', ['order_id' => $event->order->id, 'user_id' => $event->user->id, 'error' => $exception->getMessage()]); }
}`
这个监听器已经实现了ShouldQueue接口,表明它应该排队。我们添加了错误处理、日志记录,并定义了失败方法来处理失败。 $tries 属性将设置为允许在失败时进行多次尝试。
现在,让我们看看 UpdateInventory 监听器
`命名空间 App\Listeners;
使用 App\Events\OrderPlaced;
使用 Illuminate\Contracts\Queue\ShouldQueue;
使用 Illuminate\Queue\InteractsWithQueue;
使用 Illuminate\Support\Facades\DB;
使用 Illuminate\Support\Facades\Log;
类 UpdateInventory 实现 ShouldQueue
{
使用 InteractsWithQueue;
/** * Handle the event. * * @param \App\Events\OrderPlaced $event * @return void */ public function handle(OrderPlaced $event) { $order = $event->order; DB::transaction(function () use ($order) { foreach ($order->items as $item) { $product = $item->product; if ($product->stock quantity) { throw new \Exception("Insufficient stock for product: {$product->id}"); } $product->decrement('stock', $item->quantity); Log::info("Inventory updated", ['product_id' => $product->id, 'quantity' => $item->quantity]); } }); } /** * Handle a job failure. * * @param \App\Events\OrderPlaced $event * @param \Throwable $exception * @return void */ public function failed(OrderPlaced $event, $exception) { Log::error('Failed to update inventory', ['order_id' => $event->order->id, 'error' => $exception->getMessage()]); }
}`
现在,您应该明白,这个侦听器的存在是出于一些原因,例如根据订单项目升级库存等。我们已将库存更新包装在数据库事务中以确保数据一致性。我们还添加了错误检查以防止负库存,并包括成功更新和失败的日志记录。
*注册事件和监听器
*
我们将在 EventServiceProvider
`使用 App\Events\OrderPlaced;
使用 App\Listeners\SendOrderConfirmation;
使用 App\Listeners\UpdateInventory;
类 EventServiceProvider 扩展了 ServiceProvider
{
/**
* 应用程序的事件侦听器映射。
*
* @var 数组
*/
受保护的 $listen = [
订单放置::类 => [
SendOrderConfirmation::class,
更新库存::类,
],
];
/** * Register any events for your application. * * @return void */ public function boot() { parent::boot(); // }
}`
调度事件:
我们可以从控制器或服务类调度事件
`使用 App\Events\OrderPlaced;
使用应用\模型\订单;
使用 Illuminate\Http\Request;
使用 Illuminate\Support\Facades\DB;
类 OrderController 扩展了 Controller
{
/**
* 下新订单。
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
公共函数 placeOrder(请求 $request)
{
$user = auth()->user();
DB::transaction(function () use ($request, $user) { $order = Order::create($request->all()); $order->user()->associate($user); $order->save(); event(new OrderPlaced($order, $user)); }); return response()->json(['message' => 'Order placed successfully', 'order_id' => $order->id]); }
}`
在此示例中,我们将订单创建和事件分派包装在数据库事务中,以确保两者成功或根本不发生。
免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。
Copyright© 2022 湘ICP备2022001581号-3