将一个模型传递一个到事件监听器里,为什么模型的getChanges、isDirty、isClean 、 wasChanged都为空?

1. 运行环境

1). 当前使用的 Laravel 版本?

Laravel Framework 10.31.0

2). 当前使用的 php/php-fpm 版本?

PHP 版本:PHP 8.1.21

php-fpm 版本:PHP 8.1.21

3). 当前系统

Ubuntu 22.04

4). 业务环境

开发环境

2. 问题描述?

下面是代码片段,运行php artisan debug

<?php
// 第一次dump
namespace App\Console\Commands;

use App\Models\Device\AlmDevice;

use Illuminate\Console\Command;


class Debug extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'debug';

    public function handle()
    {
        $almDevice = AlmDevice::find(1);
        $almDevice->update(['memo' => '12345021q6070']);
        dump($almDevice->getChanges());
        event(new \App\Events\Device\Alm\UpdatedEvent($almDevice));
    }
}
<?php
// 第二次dump
namespace App\Events\Device\Alm;

use App\Events\BaseEvent;
use App\Models\Device\AlmDevice;

class UpdatedEvent extends BaseEvent
{
    public AlmDevice $almDevice;

    /**
     * Create a new event instance.
     */
    public function __construct(AlmDevice $almDevice)
    {
        parent::__construct();
        $this->almDevice = $almDevice;
        dump($almDevice->getChanges());
    }
}
<?php

namespace App\Providers;

use App\Listeners\Device\AlmSyncSubscribe;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event to listener mappings for the application.
     *
     * @var array<class-string, array<int, class-string>>
     */
    protected $listen = [
        \App\Events\Device\Alm\UpdatedEvent::class => [
            [AlmSyncSubscribe::class, 'onDeviceUpdated'],
        ]
    ];

    /**
     * Register any events for your application.
     */
    public function boot(): void
    {
        //
    }

    /**
     * Determine if events and listeners should be automatically discovered.
     */
    public function shouldDiscoverEvents(): bool
    {
        return false;
    }
}
<?php
// 第三次dump
namespace App\Listeners\Device;

use App\Events\Device\Alm\UpdatedEvent;

class AlmSyncSubscribe extends ShouldQueue
{
    public function onDeviceUpdated(UpdatedEvent $event)
    {
        $almDevice = $event->almDevice;
        dump($almDevice->getChanges());
    }
}

3. 您期望得到的结果?

我期望是在第三次dump可以输出模型变更的属性

4. 您实际得到的结果?

array:2 [
  "update_time" => "2023-11-20 17:24:22"
  "memo" => "123450213q61070"
] // app/Console/Commands/Debug.php:26
array:2 [
  "update_time" => "2023-11-20 17:24:22"
  "memo" => "123450213q61070"
] // app/Events/Device/Alm/UpdatedEvent.php:19
[] // app/Listeners/Device/AlmSyncSubscribe.php:12
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
最佳答案

因为你的模型在派发任务时会因为 SerializesModels 这个 Trait 进行序列化,最后在消费的时候,再重新获取模型

If your queued job accepts an Eloquent model in its constructor, only the identifier for the model will be serialized onto the queue. When the job is actually handled, the queue system will automatically re-retrieve the full model instance and its loaded relationships from the database. This approach to model serialization allows for much smaller job payloads to be sent to your queue driver.

所以,其实你后面 AlmSyncSubscribe 里面其实是新查询到的一个模型,自然不存在这些变化。如果你需要这些变化,那你就要在派发的时候,单独取出来组装进去。

另外这也有一个值得思考的就是,在队列处理到这一行数据的时候,很可能它已经发生过变化了。

5个月前 评论
讨论数量: 3

因为你的模型在派发任务时会因为 SerializesModels 这个 Trait 进行序列化,最后在消费的时候,再重新获取模型

If your queued job accepts an Eloquent model in its constructor, only the identifier for the model will be serialized onto the queue. When the job is actually handled, the queue system will automatically re-retrieve the full model instance and its loaded relationships from the database. This approach to model serialization allows for much smaller job payloads to be sent to your queue driver.

所以,其实你后面 AlmSyncSubscribe 里面其实是新查询到的一个模型,自然不存在这些变化。如果你需要这些变化,那你就要在派发的时候,单独取出来组装进去。

另外这也有一个值得思考的就是,在队列处理到这一行数据的时候,很可能它已经发生过变化了。

5个月前 评论

如果是从队列取出来的话这是正常的, 毕竟它要先序列化到队列服务,如果没有实现对应的方法可能就无法保存变更的属性

5个月前 评论

update方法走的是sql更新并不是模型的更新,试试用save方法,给属性赋值后再save看看

5个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!