In this tutorial let's dig into how we can gracefully delete data that belongs to one to many relationship in Laravel.

For this let's consider an example of a relationship between Category and Post. Category can have many posts.

If you delete the category without handling the associated posts then it will cause problems in the application, since you have post data in your database which is still associated with a category that does not exist.

In this solution, once we delete the category, we will assign the associated posts to an Uncategorized category.

Here is how Category Model looks like

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Category extends Model
{

    protected $guarded = [];

    public function posts(){
        return $this->hasMany('App\Post');
    }

}

Here is how the destroy method of CategoryController is

public function destroy(Category $category)
{
   $category->delete();

   return redirect('/admin/categories')->with('success', 'Category Deleted !');
}

Now before deleting the Category, we want to assign the associated posts to an Uncategorized Category.

Create a boot method in your Category model with below code.

public static function boot() {
        parent::boot();

        static::deleting(function($category) { // before delete() method call this
            $uncategorized = Category::firstOrCreate(['name' => 'Uncategorized', 'slug' => 
                             'uncategorized', 'description' => 'uncategorized']);
            Post::where('category_id', $category->id)->update(
                             ['category_id' => $uncategorized->id]);
        });
}

We are executing our custom code on deleting event of the Category model. This code will be executed just before the delete action is called on Category model.

In the code we get the id of Category with name 'Uncategorized', if the category does not exist in the database then we create it by using firstOrCreate eloquent method.

After that, we assign the Post which belongs to the Category being deleted to UnCategorized category.

That's It. Here is a Feature test to go along with this feature.

/** @test */
public function when_category_deleted_associated_post_assigned_to_uncategorized_category(){
    //Given that we have a signed in user
    $this->actingAs($this->user);
    //And given that we have a category
    $category = factory('App\Category')->create();
    //And a post associated with the category
    $post = factory('App\Post')->create(['category_id' => $category->id]);

    //When we delete the category the post should be assigned to uncategorized category
    $this->delete("/categories/{$category->id}");
            
    $category_id = Category::where('name', 'Uncategorized')->first()->id;

    $post = $post->fresh();

    $this->assertEquals($category_id, $post->category_id);

}
Comments