」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 如何以及何時在 Laravel 實用程式碼範例中使用事件監聽器

如何以及何時在 Laravel 實用程式碼範例中使用事件監聽器

發佈於2024-08-18
瀏覽:418

How & When To Use Event Listeners in Laravel  Practical Code Examples

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 接口,并定义了 broadcastOnbroadcastAs 方法,允许将此事件广播到 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]);
}

}`

在此示例中,我们将订单创建和事件分派包装在数据库事务中,以确保两者成功或根本不发生。

版本聲明 本文轉載於:https://dev.to/danish/how-when-to-use-event-listeners-in-laravel-11-practical-code-examples-29mn?1如有侵犯,請聯絡study_golang@163 .com刪除
最新教學 更多>
  • JavaScript中如何動態訪問全局變量?
    JavaScript中如何動態訪問全局變量?
    在JavaScript 一種方法是使用窗口對象存儲和檢索變量。通過引用全局範圍,可以使用其名稱動態訪問變量。 //一個腳本 var somevarname_10 = 20; //另一個腳本 window.all_vars = {}; window.all_vars ['somevarna...
    程式設計 發佈於2025-04-19
  • 為什麼我的CSS背景圖像出現?
    為什麼我的CSS背景圖像出現?
    故障排除:CSS背景圖像未出現 ,您的背景圖像儘管遵循教程說明,但您的背景圖像仍未加載。圖像和样式表位於相同的目錄中,但背景仍然是空白的白色帆布。 而不是不棄用的,您已經使用了CSS樣式: bockent {背景:封閉圖像文件名:背景圖:url(nickcage.jpg); 如果您的html,cs...
    程式設計 發佈於2025-04-19
  • Java靜態字段何時避免及原因
    Java靜態字段何時避免及原因
    Exploring the Nature and Nuances of Static Fields in JavaProblem:Developers often encounter the need to share data between instances of the same class...
    程式設計 發佈於2025-04-19
  • 如何在Java中正確顯示“ DD/MM/YYYY HH:MM:SS.SS”格式的當前日期和時間?
    如何在Java中正確顯示“ DD/MM/YYYY HH:MM:SS.SS”格式的當前日期和時間?
    如何在“ dd/mm/yyyy hh:mm:mm:ss.ss”格式“ gormat 解決方案:的,請訪問量很大,並應為procectiquiestate的,並在整個代碼上正確格式不多: java.text.simpledateformat; 導入java.util.calendar; 導入java...
    程式設計 發佈於2025-04-19
  • 如何在php中使用捲髮發送原始帖子請求?
    如何在php中使用捲髮發送原始帖子請求?
    如何使用php 創建請求來發送原始帖子請求,開始使用curl_init()開始初始化curl session。然後,配置以下選項: curlopt_url:請求 [要發送的原始數據指定內容類型,為原始的帖子請求指定身體的內容類型很重要。在這種情況下,它是文本/平原。要執行此操作,請使用包含以下標頭...
    程式設計 發佈於2025-04-19
  • 如何檢查對像是否具有Python中的特定屬性?
    如何檢查對像是否具有Python中的特定屬性?
    方法來確定對象屬性存在尋求一種方法來驗證對像中特定屬性的存在。考慮以下示例,其中嘗試訪問不確定屬性會引起錯誤: >>> a = someClass() >>> A.property Trackback(最近的最新電話): 文件“ ”,第1行, AttributeError: SomeClass...
    程式設計 發佈於2025-04-19
  • 如何使用Java.net.urlConnection和Multipart/form-data編碼使用其他參數上傳文件?
    如何使用Java.net.urlConnection和Multipart/form-data編碼使用其他參數上傳文件?
    使用http request 上傳文件上傳到http server,同時也提交其他參數,java.net.net.urlconnection and Multipart/form-data Encoding是普遍的。 Here's a breakdown of the process:Mu...
    程式設計 發佈於2025-04-19
  • 表單刷新後如何防止重複提交?
    表單刷新後如何防止重複提交?
    在Web開發中預防重複提交 在表格提交後刷新頁面時,遇到重複提交的問題是常見的。要解決這個問題,請考慮以下方法: 想像一下具有這樣的代碼段,看起來像這樣的代碼段:)){ //數據庫操作... 迴聲“操作完成”; 死(); } ? > ...
    程式設計 發佈於2025-04-19
  • 在細胞編輯後,如何維護自定義的JTable細胞渲染?
    在細胞編輯後,如何維護自定義的JTable細胞渲染?
    在JTable中維護jtable單元格渲染後,在JTable中,在JTable中實現自定義單元格渲染和編輯功能可以增強用戶體驗。但是,至關重要的是要確保即使在編輯操作後也保留所需的格式。 在設置用於格式化“價格”列的“價格”列,用戶遇到的數字格式丟失的“價格”列的“價格”之後,問題在設置自定義單元...
    程式設計 發佈於2025-04-19
  • 如何使用FormData()處理多個文件上傳?
    如何使用FormData()處理多個文件上傳?
    )處理多個文件輸入時,通常需要處理多個文件上傳時,通常是必要的。 The fd.append("fileToUpload[]", files[x]); method can be used for this purpose, allowing you to send multi...
    程式設計 發佈於2025-04-19
  • 如何在GO編譯器中自定義編譯優化?
    如何在GO編譯器中自定義編譯優化?
    在GO編譯器中自定義編譯優化 GO中的默認編譯過程遵循特定的優化策略。 However, users may need to adjust these optimizations for specific requirements.Optimization Control in Go Compi...
    程式設計 發佈於2025-04-19
  • 如何從Google API中檢索最新的jQuery庫?
    如何從Google API中檢索最新的jQuery庫?
    從Google APIS 問題中提供的jQuery URL是版本1.2.6。對於檢索最新版本,以前有一種使用特定版本編號的替代方法,它是使用以下語法:獲取最新版本:未壓縮)While these legacy URLs still remain in use, it is recommended ...
    程式設計 發佈於2025-04-19
  • Java字符串非空且非null的有效檢查方法
    Java字符串非空且非null的有效檢查方法
    檢查字符串是否不是null而不是空的 if(str!= null && str.isementy())二手: if(str!= null && str.length()== 0) option 3:trim()。 isement(Isement() trim whitespace whites...
    程式設計 發佈於2025-04-19
  • CSS強類型語言解析
    CSS強類型語言解析
    您可以通过其强度或弱输入的方式对编程语言进行分类的方式之一。在这里,“键入”意味着是否在编译时已知变量。一个例子是一个场景,将整数(1)添加到包含整数(“ 1”)的字符串: result = 1 "1";包含整数的字符串可能是由带有许多运动部件的复杂逻辑套件无意间生成的。它也可以是故意从单个真理...
    程式設計 發佈於2025-04-19

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3