问题
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
- delete some related models
- 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.
- run
php artisan make:observer ModelAObserver --model=ModelA
- in
AppServiceProvider
inboot()
metohd addModelA::observe(ModelAObserver::class);
- now in your
ModelAObserver
indeleted()
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