Laravel 删除事件的一个问题

我在laravel中定义了一下事件代码文件用于捕获删除事件
App\Events\ActItemDeleting.php

<?php

namespace App\Events;

use App\ActItem;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

class ActItemDeleting
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $actItem;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct(ActItem $actItem)
    {
        $this->actItem = $actItem;
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new PrivateChannel('channel-name');
    }
}

但是我在后台删除数据的时候,调用失败,队列错误为“No query results for model [App\ActItem]”,然后我删除上面代码里use Dispatchable, InteractsWithSockets, SerializesModels;里的SerializesModels则可正常运行,这个SerializesModels到底是什么意思, 翻看文档里说

事件使用的 SerializesModels trait 将会优雅地序列化任何 Eloquent 模型

还是没太懂,去掉这个会有什么不良后果吗

codejam
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
最佳答案

你这个似乎是在队列里,队列里的任务如果携带有模型的话,会经过序列化和反序列化流程,所以需要这个 trait。

6个月前 评论
讨论数量: 9

PHP 的 serialize 函数了解一下。

SerializesModels 代码,一看就懂。

<?php

namespace Illuminate\Queue;

use ReflectionClass;
use ReflectionProperty;

trait SerializesModels
{
    use SerializesAndRestoresModelIdentifiers;

    /**
     * Prepare the instance for serialization.
     *
     * @return array
     */
    public function __sleep()
    {
        $properties = (new ReflectionClass($this))->getProperties();

        foreach ($properties as $property) {
            $property->setValue($this, $this->getSerializedPropertyValue(
                $this->getPropertyValue($property)
            ));
        }

        return array_values(array_filter(array_map(function ($p) {
            return $p->isStatic() ? null : $p->getName();
        }, $properties)));
    }

    /**
     * Restore the model after serialization.
     *
     * @return void
     */
    public function __wakeup()
    {
        foreach ((new ReflectionClass($this))->getProperties() as $property) {
            if ($property->isStatic()) {
                continue;
            }

            $property->setValue($this, $this->getRestoredPropertyValue(
                $this->getPropertyValue($property)
            ));
        }
    }

    /**
     * Get the property value for the given property.
     *
     * @param  \ReflectionProperty  $property
     * @return mixed
     */
    protected function getPropertyValue(ReflectionProperty $property)
    {
        $property->setAccessible(true);

        return $property->getValue($this);
    }
}
6个月前 评论
codejam

@Wi1dcard
还是没看懂这个实现了什么,有什么作用,求赐教

6个月前 评论

你可以先了解一下 serialize 函数以及 __sleep__wakeup 魔法函数对 serialize 的作用,然后了解下 Reflection(反射),以上代码呈现出来的大概作用就是:在模型被序列化和反序列化的时候(例如将模型存入缓存、从缓存中取出等),处理好模型类的所有属性。

6个月前 评论
codejam

@Wi1dcard 也就是我之前的没去掉的,模型已经从数据库删除了,所以会报错,但我去掉这个SerializesModels后,却也能获取到数据,不用经过这个序列化代码?

6个月前 评论

看报错(No query results for model [App\ActItem])应该跟 SerializesModels 无关。

从数据库读模型为什么要 serialize,建议你还是先了解一下序列化是什么概念吧。

6个月前 评论
codejam

@Wi1dcard 去掉SerializesModels后不报这个错,加了后删除后报这个错:No query results for model,不加可正常运行

6个月前 评论
codejam

@Wi1dcard 感谢花时间帮我解答问题,下面是队列错误表里的完整错误

Illuminate\Database\Eloquent\ModelNotFoundException: No query results for model [App\ActItem]. in /var/www/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php:414
Stack trace:
#0 /var/www/vendor/laravel/framework/src/Illuminate/Queue/SerializesAndRestoresModelIdentifiers.php(85): Illuminate\Database\Eloquent\Builder->firstOrFail()
#1 /var/www/vendor/laravel/framework/src/Illuminate/Queue/SerializesAndRestoresModelIdentifiers.php(55): App\Events\ActItemCreated->restoreModel(Object(Illuminate\Contracts\Database\ModelIdentifier))
#2 /var/www/vendor/laravel/framework/src/Illuminate/Queue/SerializesModels.php(45): App\Events\ActItemCreated->getRestoredPropertyValue(Object(Illuminate\Contracts\Database\ModelIdentifier))
#3 [internal function]: App\Events\ActItemCreated->__wakeup()
#4 /var/www/vendor/laravel/framework/src/Illuminate/Queue/CallQueuedHandler.php(42): unserialize('O:36:"Illuminat...')
#5 /var/www/vendor/laravel/framework/src/Illuminate/Queue/Jobs/Job.php(83): Illuminate\Queue\CallQueuedHandler->call(Object(Illuminate\Queue\Jobs\RedisJob), Array)
#6 /var/www/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(322): Illuminate\Queue\Jobs\Job->fire()
#7 /var/www/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(272): Illuminate\Queue\Worker->process('redis', Object(Illuminate\Queue\Jobs\RedisJob), Object(Illuminate\Queue\WorkerOptions))
#8 /var/www/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(118): Illuminate\Queue\Worker->runJob(Object(Illuminate\Queue\Jobs\RedisJob), 'redis', Object(Illuminate\Queue\WorkerOptions))
#9 /var/www/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(101): Illuminate\Queue\Worker->daemon('redis', 'default', Object(Illuminate\Queue\WorkerOptions))
#10 /var/www/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(85): Illuminate\Queue\Console\WorkCommand->runWorker('redis', 'default')
#11 [internal function]: Illuminate\Queue\Console\WorkCommand->handle()
#12 /var/www/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(29): call_user_func_array(Array, Array)
#13 /var/www/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(87): Illuminate\Container\BoundMethod::Illuminate\Container\{closure}()
#14 /var/www/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(31): Illuminate\Container\BoundMethod::callBoundMethod(Object(Illuminate\Foundation\Application), Array, Object(Closure))
#15 /var/www/vendor/laravel/framework/src/Illuminate/Container/Container.php(564): Illuminate\Container\BoundMethod::call(Object(Illuminate\Foundation\Application), Array, Array, NULL)
#16 /var/www/vendor/laravel/framework/src/Illuminate/Console/Command.php(184): Illuminate\Container\Container->call(Array)
#17 /var/www/vendor/symfony/console/Command/Command.php(251): Illuminate\Console\Command->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Illuminate\Console\OutputStyle))
#18 /var/www/vendor/laravel/framework/src/Illuminate/Console/Command.php(171): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Illuminate\Console\OutputStyle))
#19 /var/www/vendor/symfony/console/Application.php(886): Illuminate\Console\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#20 /var/www/vendor/symfony/console/Application.php(262): Symfony\Component\Console\Application->doRunCommand(Object(Laravel\Horizon\Console\WorkCommand), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#21 /var/www/vendor/symfony/console/Application.php(145): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#22 /var/www/vendor/laravel/framework/src/Illuminate/Console/Application.php(89): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#23 /var/www/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(122): Illuminate\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#24 /var/www/artisan(37): Illuminate\Foundation\Console\Kernel->handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#25 {main}
6个月前 评论
hoobn: 请问这个问题解决了吗?能请教下? 3周前
codejam: @hoobn 去掉SerializesModels 可以解决 1周前

你这个似乎是在队列里,队列里的任务如果携带有模型的话,会经过序列化和反序列化流程,所以需要这个 trait。

6个月前 评论

进队列实际上底层可以理解为进 Redis,和前面说的模型存入缓存一个道理。

6个月前 评论

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!

社区文档:

将托管在 packagist.org 和 github.com 的扩展包使用国内 CDN 加速
GitHub Laravel 扩展包 TOP 250
速查表方便快速查询框架功能,支持手机访问,支持中英文版本
Laravel 中文文档,由社区用户翻译和维护,将会保持一直更新
此文档的目的,就是为了提高技术团队的凝聚力、一致性和生产效率。
开发环境的部署,开发者工具的选择,适用于 Mac 和 Windows。
浓缩过后的精华
Laravel Nova 后台管理面板文档的中文翻译
Lumen 中文文档,由社区用户翻译和维护,将会保持一直更新
Laravel 下知名扩展包 Dingo API 的中文文档,Laravel API 开发必知必会