0

我目前正在使用 Laravel 的队列事件侦听器处理 Eloquent 模型的saving事件。在我的事件类上,我设置了一个包含我的模型的公共属性,然后我可以$event通过$event->myModel.

我的侦听器上的handle()方法将旧值与新值进行比较,因此我Illuminate\Queue\SerializesModels在事件类中删除了。这很好用,我现在可以比较新值中的旧值。

问题在于测试。我正在做一个测试,检查我在侦听器方法中得到的新旧值handle()是否不同。但是,$event->myModel->getOriginal()现在返回一个空数组。这仅在测试时发生。

这是一个错误吗?

我尝试public $originalModelProps在我的事件类上设置 a 但是,当调用我的侦听器上的 handle() 方法时它返回空。

我没有使用或在我的代码中Illuminate\Queue\SerializesModels命名的任何特征/类/接口。SerializesModels

事件/模型/MyModel/MyModelSavedEvent.php

<?php

namespace App\Events\Models\MyModel;

use App\Models\MyModel;
use Illuminate\Queue\SerializesModels;

class MyModelSavedEvent
{
    /**
     *
     * @var \App\Models\MyModel
     */
    public $myModel;

    public $originalAccessLevelProps;

    /**
     * Create a new event instance.
     * 
     * @param \App\Models\MyModel
     *
     * @return void
     */
    public function __construct(MyModel $myModel)
    {
        $this->myModel = $myModel;
        $this->originalAccessLevelProps = $this->myModel->getOriginal('level');
    }
}

Listeners/Models/MyModel/MyModelSavedEventListener.php

<?php

namespace App\Listeners\Models\MyModel;

use Log;
use App\Models\MyModel;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\Events\Models\MyModel\MyModelSavedEvent;

class MyModelSavedEventListener implements ShouldQueue
{
    /**
     * The queue connection that should handle the job.
     *
     * @var string
     */
    public $connection = 'sqs';

    /**
     * The number of times the job may be attempted.
     *
     * @var int
     */
    public $tries = 3;

    /**
     * The number of seconds the job can run before timing out.
     *
     * @var int
     */
    public $timeout = 60;

    public function __construct()
    {
        // ..
    }

    /**
     * This job should only be queued if the level of myModel
     * has been updated.
     *
     * @param  \App\Events\Models\MyModel\MyModelSavedEvent $event
     * 
     * @return bool
     */
    public function shouldQueue(MyModelSavedEvent $event)
    {
        $prevLevel = $event->myModel->getOriginal('level');
        $currLevel = $event->myModel->level;

        return $prevLevel !== $currLevel;
    }

    public function handle(MyModelSavedEvent $event): void
    {
        $prevLevel = $event->myModel->getOriginal('level');
        $currLevel = $event->myModel->level;

        Log::info([
            'Running handle!',
            $event->myModel->getOriginal(), // This returns an empty array
            $event->originalAccessLevelProps, // This is null
            $event->myModel->id, // This returns a string
            $prevLevel, // This returns null
            $currLevel // This contains the latest value
        ]);

        // ..
    }
}

测试/app/Listeners/Models/MyModel/MyModelSavedEventListener.php

<?php

public function testSample()
{
    Queue::fake();

    $myModel = MyModel::where(...)->first();

    Queue::assertNothingPushed();

    // This will trigger the event
    $myModel->level = 'new level';
    $myModel->save();

    Queue::assertPushedOn('sqs', MyModelSavedEventListener::class);
}

我期待类似于它在测试之外的工作方式,我将能够比较旧值和新值。

编辑: 事件是通过 MyModel 的$dispatchesEvents属性触发的:

/**
 * The event map for the model.
 *
 * @var array
 */
protected $dispatchesEvents = [
    'saved' => \App\Events\Models\MyModel\MyModelSavedEvent::class,
];

更新:发现我的模型确实没有被序列化。只是在侦听器的方法getOriginal()中调用时仍然返回一个空数组handle()

4

1 回答 1

0

SerializesModel用于在队列中存储作业时,通过序列化模型 ID 和一些元信息来节省空间。

当您将模型实例传递给不使用SerializesModel该实例的作业时,该实例仍会使用 PHP 进行序列化,serialize()并在调用侦听器时恢复。

所以也许尝试将您感兴趣的属性直接传递给MyModelSavedEvent::dispatch()

于 2019-08-26T18:45:22.800 回答