Laravel听众听多个事件

Par*_*Lai 14 events laravel laravel-5

因此,根据laravel事件文档,在定义侦听器时,它可以在其handle方法中接收事件实例并执行任何必要的逻辑:

public function handle(FoodWasPurchased $event)
Run Code Online (Sandbox Code Playgroud)

因此,如果我的FoodWasPurchased事件定义如下(假设设置了EventServiceProvider):

public function __construct(Food $food)
{
    $this->food = $food;
}
Run Code Online (Sandbox Code Playgroud)

我可以通过以下方式从听众那里获取$ food

$event->food->doSomething();
Run Code Online (Sandbox Code Playgroud)

但现在我的问题是如果听众听多个事件怎么办?

Event FoodWasPurchased -> Listener Bill
Event DrinksWasPurchased -> Listener Bill
Run Code Online (Sandbox Code Playgroud)

我现在做的是我没有在监听器句柄方法中指定事件实例:

public function handle($event)
Run Code Online (Sandbox Code Playgroud)

我可以在以后使用if条件来检查$ event中收到的内容:

if (isset($event->food)) {

    // Do something...

} elseif (isset($event->drinks)) {

    // Do something else...

}
Run Code Online (Sandbox Code Playgroud)

我相信有更好的方法.

或者最佳做法是确保一个监听器只监听一个事件?

jag*_*ruz 20

您可以使用放置在Listeners文件夹中但能够侦听多个事件的事件订阅者来侦听多个事件.

<?php

namespace App\Listeners;

class UserEventListener{
    /**
     * Handle user login events.
     */
    public function onUserLogin($event) {}

    /**
     * Handle user logout events.
     */
    public function onUserLogout($event) {}

    /**
     * Register the listeners for the subscriber.
     *
     * @param  Illuminate\Events\Dispatcher  $events
     * @return array
     */
    public function subscribe($events){
        $events->listen(
            'App\Events\UserLoggedIn',
            'App\Listeners\UserEventListener@onUserLogin'
        );

        $events->listen(
            'App\Events\UserLoggedOut',
            'App\Listeners\UserEventListener@onUserLogout'
        );
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 引发相应事件时将触发EventListeners。因此,您必须在控制器内触发事件。 (2认同)

小智 8

如果您的事件符合合同或界面,您似乎可以将任意数量的事件传递给听众......

class MyEventOne extends Event implements MyEventInterface
Run Code Online (Sandbox Code Playgroud)

然后在EventServiceProvider中,您将事件和侦听器连接起来......

protected $listen = [
    'App\Events\MyEventOne' => [
        'App\Listeners\MyListener',
    ],
    'App\Events\MyEventTwo' => [
        'App\Listeners\MyListener',
    ],
];
Run Code Online (Sandbox Code Playgroud)

最后在你的监听器中输入提示你的处理程序接受基于契约/接口的事件对象...

public function handle(MyEventInterface $event)
Run Code Online (Sandbox Code Playgroud)

我对它进行了单元测试,它可能不适合每种情况,但似乎有效.我希望它有所帮助.


The*_*pha 6

您也可以尝试以下操作:

// Instead of Food or Drink use parent Type
use Illuminate\Database\Eloquent\Model;

class DrinWasPurchased extends Event
{
    // Instead of Food or Drink typehint Model        
    public function __construct(Model $model)
    {
        // Instead of $this->food or $this->drink use a generic name
        $this->item = $model;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在handle侦听器的方法中尝试如下所示:

public function handle(\App\Events\Event $event)
{
    if($event->item instanceof \App\Food)
    {
        $item->eat(); // Just an example
    }

    if($event->item instanceof \App\Drink)
    {
        $item->drink(); // Just an example
    }
}
Run Code Online (Sandbox Code Playgroud)


Vas*_*sov 6

如果您使用 PHP 8,则可以利用联合类型。

class BillListener
    {
    /**
     * Handle the event.
     *
     * @param FoodWasPurchased|DrinksWasPurchased $event
     * @return void
     */
    public function handle(FoodWasPurchased|DrinksWasPurchased $event): void
    {
        // Listener code goes here...
    }
}
Run Code Online (Sandbox Code Playgroud)