Reputation: 21091
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
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?
Upvotes: 3
Views: 2625
Reputation: 510
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();
// ...
});
}
Upvotes: 3
Reputation: 2545
I would suggest using Observers to listen for ModelA
deleted event.
php artisan make:observer ModelAObserver --model=ModelA
AppServiceProvider
in boot()
metohd add ModelA::observe(ModelAObserver::class);
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();
});
Upvotes: 2
Reputation: 922
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();
}
Upvotes: 2
Reputation: 1835
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();
// ...
});
}
}
Upvotes: 4
Reputation: 121
Did you try use static
instead of self
In the documentation, Laravel recommends to using static
keyword when binding event or observer
Upvotes: 2