”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 如何以及何时在 Laravel 实用代码示例中使用事件监听器

如何以及何时在 Laravel 实用代码示例中使用事件监听器

发布于2024-08-18
浏览:691

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如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 在GO中构造SQL查询时,如何安全地加入文本和值?
    在GO中构造SQL查询时,如何安全地加入文本和值?
    在go中构造文本sql查询时,在go sql queries 中,在使用conting and contement和contement consem per时,尤其是在使用integer per当per当per时,per per per当per. [&​​&&&&&&&&&&&&&&&默元组方法在...
    编程 发布于2025-04-03
  • 为什么使用固定定位时,为什么具有100%网格板柱的网格超越身体?
    为什么使用固定定位时,为什么具有100%网格板柱的网格超越身体?
    网格超过身体,用100%grid-template-columns 为什么在grid-template-colms中具有100%的显示器,当位置设置为设置的位置时,grid-template-colly修复了?问题: 考虑以下CSS和html: class =“ snippet-code”> g...
    编程 发布于2025-04-03
  • 如何在鼠标单击时编程选择DIV中的所有文本?
    如何在鼠标单击时编程选择DIV中的所有文本?
    在鼠标上选择div文本单击带有文本内容,用户如何使用单个鼠标单击单击div中的整个文本?这允许用户轻松拖放所选的文本或直接复制它。 在单个鼠标上单击的div元素中选择文本,您可以使用以下Javascript函数: function selecttext(canduterid){ if(do...
    编程 发布于2025-04-03
  • 如何将MySQL数据库添加到Visual Studio 2012中的数据源对话框中?
    如何将MySQL数据库添加到Visual Studio 2012中的数据源对话框中?
    在Visual Studio 2012 尽管已安装了MySQL Connector v.6.5.4,但无法将MySQL数据库添加到实体框架的“ DataSource对话框”中。为了解决这一问题,至关重要的是要了解MySQL连接器v.6.5.5及以后的6.6.x版本将提供MySQL的官方Visual...
    编程 发布于2025-04-03
  • PHP阵列键值异常:了解07和08的好奇情况
    PHP阵列键值异常:了解07和08的好奇情况
    PHP数组键值问题,使用07&08 在给定数月的数组中,键值07和08呈现令人困惑的行为时,就会出现一个不寻常的问题。运行print_r($月)返回意外结果:键“ 07”丢失,而键“ 08”分配给了9月的值。此问题源于PHP对领先零的解释。当一个数字带有0(例如07或08)的前缀时,PHP将其...
    编程 发布于2025-04-03
  • 如何从PHP中的数组中提取随机元素?
    如何从PHP中的数组中提取随机元素?
    从阵列中的随机选择,可以轻松从数组中获取随机项目。考虑以下数组:; 从此数组中,使用array_rand( array_rand()函数从数组返回一个随机键。通过将$项目数组索引使用此键,我们可以从数组中访问一个随机元素。这种方法为选择随机项目提供了一种直接且可靠的方法。
    编程 发布于2025-04-03
  • 为什么我在Silverlight Linq查询中获得“无法找到查询模式的实现”错误?
    为什么我在Silverlight Linq查询中获得“无法找到查询模式的实现”错误?
    查询模式实现缺失:解决“无法找到”错误在银光应用程序中,尝试使用LINQ建立错误的数据库连接的尝试,无法找到以查询模式的实现。”当省略LINQ名称空间或查询类型缺少IEnumerable 实现时,通常会发生此错误。 解决问题来验证该类型的质量是至关重要的。在此特定实例中,tblpersoon可能需...
    编程 发布于2025-04-03
  • 如何将PANDAS DataFrame列转换为DateTime格式并按日期过滤?
    如何将PANDAS DataFrame列转换为DateTime格式并按日期过滤?
    Transform Pandas DataFrame Column to DateTime FormatScenario:Data within a Pandas DataFrame often exists in various formats, including strings.使用时间数据时...
    编程 发布于2025-04-03
  • 如何使用Depimal.parse()中的指数表示法中的数字?
    如何使用Depimal.parse()中的指数表示法中的数字?
    在尝试使用Decimal.parse(“ 1.2345e-02”中的指数符号表示法表示的字符串时,您可能会遇到错误。这是因为默认解析方法无法识别指数符号。 成功解析这样的字符串,您需要明确指定它代表浮点数。您可以使用numbersTyles.Float样式进行此操作,如下所示:[&& && && ...
    编程 发布于2025-04-03
  • 如何使用Python理解有效地创建字典?
    如何使用Python理解有效地创建字典?
    在python中,词典综合提供了一种生成新词典的简洁方法。尽管它们与列表综合相似,但存在一些显着差异。与问题所暗示的不同,您无法为钥匙创建字典理解。您必须明确指定键和值。 For example:d = {n: n**2 for n in range(5)}This creates a dicti...
    编程 发布于2025-04-03
  • 在细胞编辑后,如何维护自定义的JTable细胞渲染?
    在细胞编辑后,如何维护自定义的JTable细胞渲染?
    在JTable中维护jtable单元格渲染后,在JTable中,在JTable中实现自定义单元格渲染和编辑功能可以增强用户体验。但是,至关重要的是要确保即使在编辑操作后也保留所需的格式。在设置用于格式化“价格”列的“价格”列,用户遇到的数字格式丢失的“价格”列的“价格”之后,问题在设置自定义单元格...
    编程 发布于2025-04-03
  • 如何实时捕获和流媒体以进行聊天机器人命令执行?
    如何实时捕获和流媒体以进行聊天机器人命令执行?
    在开发能够执行命令的chatbots的领域中,实时从命令执行实时捕获Stdout,一个常见的需求是能够检索和显示标准输出(stdout)在cath cath cant cant cant cant cant cant cant cant interfaces in Chate cant inter...
    编程 发布于2025-04-03
  • 对象拟合:IE和Edge中的封面失败,如何修复?
    对象拟合:IE和Edge中的封面失败,如何修复?
    To resolve this issue, we employ a clever CSS solution that solves the problem:position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%)...
    编程 发布于2025-04-03
  • 为什么Microsoft Visual C ++无法正确实现两台模板的实例?
    为什么Microsoft Visual C ++无法正确实现两台模板的实例?
    The Mystery of "Broken" Two-Phase Template Instantiation in Microsoft Visual C Problem Statement:Users commonly express concerns that Micro...
    编程 发布于2025-04-03
  • 哪种在JavaScript中声明多个变量的方法更可维护?
    哪种在JavaScript中声明多个变量的方法更可维护?
    在JavaScript中声明多个变量:探索两个方法在JavaScript中,开发人员经常遇到需要声明多个变量的需要。对此的两种常见方法是:在单独的行上声明每个变量: 当涉及性能时,这两种方法本质上都是等效的。但是,可维护性可能会有所不同。 第一个方法被认为更易于维护。每个声明都是其自己的语句,使其...
    编程 发布于2025-04-03

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3