Laravel 的事件系统在处理 Web 应用程序中的复杂数据方面非常出色,因为它是构建解耦且绝对复杂的应用程序的基石。本指南讲述了有关事件监听的实现和利用的极其详细的要点,尤其是在 2024 年,通过 Laravel 11 中最广泛的内容和详细的代码示例事件监听器提供了全新的视角。
*(A) 理解事件和监听器背后的核心
*
那么,让我们来分解一下,Laravel 中的事件确实代表了应用程序内的特定事件。侦听器是响应所有此类应用程序事件的类。这种模式不断促进关注点分离,并允许更多模块化和可测试的代码。
*(B) 创建活动
*
让我们首先创建一个复杂的事件,我们将使用 Artisan 命令来更好地解释我们强烈建议您也这样做
php artisan make:event OrderPlaced
此命令将在 app/Events 目录中生成一个新的事件类。让我们看一下更详细的事件类
`命名空间 AppEvents;
使用AppModelsOrder;
使用 AppModelsUser;
使用 IlluminateFoundationEventsDispatchable;
使用 IlluminateQueueSerializesModels;
使用 IlluminateBroadcastingInteractsWithSockets;
使用 IlluminateBroadcastingPrivateChannel;
使用 IlluminateContractsBroadcastingShouldBroadcast;
类 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 侦听器,看看它如何进一步进行
`命名空间 AppListeners;
使用AppEventsOrderPlaced;
使用AppMailOrderConfirmation;
使用 IlluminateContractsQueueShouldQueue;
使用 IlluminateQueueInteractsWithQueue;
使用 IlluminateSupportFacadesMail;
使用 IlluminateSupportFacadesLog;
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 监听器
`命名空间 AppListeners;
使用AppEventsOrderPlaced;
使用 IlluminateContractsQueueShouldQueue;
使用 IlluminateQueueInteractsWithQueue;
使用 IlluminateSupportFacadesDB;
使用 IlluminateSupportFacadesLog;
类 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 < $item->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
`使用 AppEventsOrderPlaced;
使用 AppListenersSendOrderConfirmation;
使用 AppListenersUpdateInventory;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
OrderPlaced::class => [
SendOrderConfirmation::class,
UpdateInventory::class,
],
];
/** * Register any events for your application. * * @return void */ public function boot() { parent::boot(); // }
}`
Dispatching Events:
We can dispatch the event from a controller or service class
`use App\Events\OrderPlaced;
use App\Models\Order;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class OrderController extends Controller
{
/**
* Place a new order.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function placeOrder(Request $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]); }
}`
In this example, we have wrapped the order creation and event dispatching in a database transaction to ensure that both occur successfully or not at all.
以上是如何以及何时在 Laravel 实用代码示例中使用事件监听器的详细内容。更多信息请关注PHP中文网其他相关文章!