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

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

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

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

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

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

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

【问题讨论】:

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

标签: laravel eloquent laravel-6 voyager


【解决方案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);
              });
              
          }
      }
      

      【讨论】:

      • 你能解释一下为什么这应该有效吗?我所拥有的模型之间有什么区别?
      • 不同的是你必须创建一个事件来处理模型触发事件并注册它们,所以不需要在启动方法上处理它,我这里只是为了记录并保证事件项删除正在触发
      猜你喜欢
      • 2018-12-16
      • 1970-01-01
      • 1970-01-01
      • 2014-05-13
      • 1970-01-01
      • 2015-07-18
      • 2012-12-24
      • 1970-01-01
      • 2015-12-07
      相关资源
      最近更新 更多