Skip to content

Instantly share code, notes, and snippets.

@niallobrien
Last active December 14, 2015 13:08
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save niallobrien/5091363 to your computer and use it in GitHub Desktop.
Save niallobrien/5091363 to your computer and use it in GitHub Desktop.
Cascading deletes in Laravel 4.
<?php
// I have Groups. A group can have many discussions. A single discussion can have many posts.
// models/Group.php
public function delete()
{
// Check for discussions belonging to the group first
if ($this->discussions) {
foreach ($this->discussions as $discussion) {
$discussion->delete();
}
}
// Remove entry in group_user pivot table
$this->users()->delete();
// Now delete the group
return parent::delete();
}
// models/Discussion.php
function delete()
{
// Check for posts to discussion first
if ($this->posts) {
foreach ($this->posts as $post) {
$post->delete();
}
}
// Now delete the discussion
return parent::delete();
}
// The Post model does pretty much the same as the Discussion model.
@niallobrien
Copy link
Author

First, I wrote the delete method for the last child of the cascade (Post model). Then worked my way up the chain and they each called the child deletes. So the Group model loops through all discussions on that group, calls the delete method on each discussion and that calls the delete method on each post within that discussion. Finally it then deletes the group.

@JonoB
Copy link

JonoB commented Mar 6, 2013

I think that this can be improved significantly. Instead of deleting each line individually, rather gather all the ID's for deletion, and pass through one delete:

$ids = array();
if ($this->discussions) {
  foreach ($this->discussions as $discussion) {
    $ids[] = $discussion->id;
  }
}
if (count($ids) > 0) {
  Discussion::whereIn($ids)->delete();
}

Always be aware of the number of queries hitting your db.

@niallobrien
Copy link
Author

Awesome improvement, thanks!

@niallobrien
Copy link
Author

If you're using the new soft-delete feature in L4, and want to cascade hard-delete models, including models already soft-deleted, modify your foreach loop to include withTrashed() models.

foreach ($this->discussions()->withTrashed()->get() as $discussion) {
    $discussion->forceDelete();
}

@asmerkin
Copy link

Thank you very much for this gist. It's been very helpful. Thanks!

@vandevelde-jacob
Copy link

Teaching myself Laravel and new here. But there are two things I'd like to point out to JonoB (Please correct me if I'm wrong!)

"Discussion::whereIn($ids)->delete();" is missing a parameter in the whereIn() clause. (Field name)
i.e. "Discussion::whereIn('id', $ids)->delete();"

and

Using your method to bulk delete in one query does not cascade down to other models delete() method on related objects.

i.e. If Discussion also contains cascade deletes in the model they will not execute.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment