Laravel 的模型之一未调用已删除的方法

Posted

技术标签:

【中文标题】Laravel 的模型之一未调用已删除的方法【英文标题】:Deleted method is not called on one of Laravel's models 【发布时间】:2021-12-04 21:08:21 【问题描述】:

我正在使用带有 Voyager 管理面板的 Laravel 6。

我有两个不同的 Laravel 模型,我正在从 Voyager 管理面板中删除它们的项目,删除对两个模型的项目都很有效。

我想在模型删除时添加一些操作,因此我将此代码添加到两个模型中。 它适用于模型 A 但不适用于模型 B,我不知道为什么以及如何调试和修复它。

    public static function boot() 
      parent::boot();
    
      static::deleted(function($model) 
        someaction();
      );
    

我发现的模型之间仅有的两个区别

    模型 B 在其数据库迁移中具有级联删除 Model B 扩展了 \TCG\Voyager\Models\User

【问题讨论】:

请在您的问题中添加minimal reproducible example,包括有关相关模型、数据库结构以及最重要的您认为应该触发此事件的操作的信息. 【参考方案1】:

我建议使用 laravel 的观察者来触发事件的某些代码,包括创建、更新、删除...

您可以在此处查看参考:https://laravel.com/docs/8.x/eloquent#observers

创建观察者后,将此代码添加到模型中:

    public static function boot()
    
        parent::boot();
        MyModel::observe(MyModelObserver::class);
    

【讨论】:

【参考方案2】:

您提到模型 B 在迁移时具有级联删除功能。这很可能是原因。删除事件不会被触发,因为删除发生在数据库级别而不是通过 Laravel。如果您仍然需要此事件,您可以通过应用程序处理删除,而不是级联删除。另一种方法是观察外键模型上的删除事件,然后处理您的函数。 Here's a related question 这可能会有所帮助。 要进一步确认是否是级联删除的原因,请尝试通过应用 (ModelB::find(1)->delete()) 从 Model B 中手动删除某些内容。

除此之外,如果你是deleting records through query (ModelB::where('something', 1)->delete()),它也不会被解雇。

【讨论】:

【参考方案3】:

你必须创建一个事件绑定类:

<?php

namespace App\Events;

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;
use App\Item;
use Log;

class ItemEvent

    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct()
    

    

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function itemDeleted(Item $item)
    
        Log::info("Item Deleted Event Fire: ".$item);
    

在事件提供者上注册:

class EventServiceProvider extends ServiceProvider


    /**
     * The event listener mappings for the application.
     *
     * @var array
     */

    protected $listen = [

        'App\Events\Event' => [
            'App\Listeners\EventListener',
        ],
        'item.deleted' => [
            'App\Events\ItemEvent@itemDeleted',
        ]
    ];

    /**
     * Register any events for your application.
     *
     * @return void
     */

    public function boot()
    
        parent::boot();
    

你可以像这样在启动模型上测试它:

class Item extends Model


    protected $fillable = ['name', 'price'];

    public static function boot() 

        parent::boot();

        static::deleted(function($item) 
            \Log::info('Item Deleted Event:'.$item);
        );
        static::deleting(function($item) 
            \Log::info('Item Deleting Event:'.$item);
        );
        
    

【讨论】:

你能解释一下为什么这应该有效吗?我所拥有的模型之间有什么区别? 不同的是你必须创建一个事件来处理模型触发事件并注册它们,所以不需要在启动方法上处理它,我这里只是为了记录并保证事件项删除正在触发

以上是关于Laravel 的模型之一未调用已删除的方法的主要内容,如果未能解决你的问题,请参考以下文章

从模型的访问器抛出自定义Laravel异常时未调用方法render()

Laravel - ORM - 调用未定义的方法

调用未定义的方法 App\Models\Car::setCreatedAt() - Laravel - 5.8.16

在 Laravel JetStream 中删除 Bootstrap 并安装 TailwindCSS 的正确方法

Laravel Eloquent 保存项目

最小角回归 LARS算法包的用法以及模型参数的选择