Delete related models in Laravel 6/7

时光总嘲笑我的痴心妄想 提交于 2021-01-27 21:00:17

问题


There are many related questions but unfortunately I can't find working solution

I have Laravel model and when this model is deleted I want to

  1. delete some related models
  2. run custom SQL query when deleting model

My Laravel's model class looks like (as you can see models can have different relation types)

class ModelA extends Model
{
  public functions modelsB() {
    return $this->hasMany(ModelB:class);
  }

  public functions modelsC() {
    return $this->belongsToMany(ModelC:class);
  }

  // other related models
 
  // place where I am expecting actual deleting is happening
  public static function boot() {
        parent::boot();

        self::deleting(function($modelA) { 

          $modelA->modelsB()->get()->each->delete(); 
         
          foreach($modelA->modelsC as $modelC){
            $modelC->delete();
          }
    });
  }
}

ModelA is deleted but all related data stays, and I am not sure that it is even being called. Maybe I missed something? Should I extend some class for my ModelA? Or this boot function should be placed somewhere else?


回答1:


What about https://laravel.com/docs/7.x/eloquent#events-using-closures? Something like

class ModelA extends Model
{
    public functions modelsB()
    {
        return $this->hasMany(ModelB::class);
    }

    /**
     * The "booted" method of the model.
     *
     * @return void
     */
    protected static function booted()
    {
        static::deleted(function ($modelA) {
            $modelA->modelsB()->delete();
            // ...
        });
    }
}



回答2:


Did you cascade it in your migration file of your ModelB like so:

$table->foreignId('modelA_id')
    ->onDelete('cascade');
    ->constrained()

The `onDelete('cascade') is the important part, mind you this is a shorthand for:

$table->unsignedBigInteger('modelA_id');

$table->foreign('modelA_id')->references('id')
    ->on('modelA')->onDelete('cascade');

This should do most of the heavy lifting for you and you can find more info at Laravel Docs Migrations

If you don't like this approach and would prefer an event-based approach then try doing this in your ModelA class:

protected static function booted()
{
    static::deleted(function ($modelA) {
        $modelA->modelsB()->delete();
        // ...
    });
}



回答3:


Did you try use static instead of self

In the documentation, Laravel recommends to using static keyword when binding event or observer




回答4:


If you are trying to delete the related model from within the model itself. You only need to call $this->reletedModel()->delete(); There is really no need of foreach() loop.

Given you have a function defining a relation with following declaration.

public function relatedModel()
{
    return $this->hasOne(RelatedModel::class);
    //OR
    //return $this->hasMany(RelatedModel::class);
}

/** Function to delete related models */
public function deleteRelatedModels()
{
    return $this->relatedModel()->delete();
}



回答5:


I would suggest using Observers to listen for ModelA deleted event.

  1. run php artisan make:observer ModelAObserver --model=ModelA
  2. in AppServiceProvider in boot() metohd add ModelA::observe(ModelAObserver::class);
  3. now in your ModelAObserver in deleted() method you will delete associated models and perform your custom SQL queries.
/**
 * Handle the ModelA "deleted" event.
 *
 * @param  \App\ModelA  $modelA
 * @return void
 */
public function deleted(ModelA $modelA)
{
    // delete associated models
    
    $modelA->modelsB()->delete();
    $modelA->modelsC()->delete()

    ... 

    // perform custom SQL queries

    ... 
}

you also, need to add a database transaction wherever you call delete on ModelA to make sure that action is completely done or not.

DB::transaction(function () use ($modelA) {
   $modelA->delete();
});


来源:https://stackoverflow.com/questions/63545995/delete-related-models-in-laravel-6-7

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!