Using Soft Delete in Laravel Eloquent Models
Laravel provides amazing features to deal with your database records and soft delete is one of them.

Laravel provides amazing features to deal with your database records and soft delete is one of them.
Today, we will be exploring how we can practically use the soft delete functionality. Before diving into this topic, let me explain what the heck is soft delete.
According to Wikipedia:
An operation in which a flag is used to mark data as unusable, without erasing the data itself from the database.
Above definition is simple enough to understand that when models are soft deleted, they are not actually removed from your database. Instead, a deleted_at attribute is set on the model and inserted into the database. When you will look into the database table. So any model has a non-null deleted_at value will be considered as soft deleted model.
Creating Laravel Application
For the purpose of some practical examples, let's create a new Laravel application using composer. Open your command line terminal and run the below command.
composer create-project laravel/laravel SoftDeleteAppOnce the application installation finish, create a new database in your phpMyAdmin or any MySQL client you are using. Now update the database credentials in the .env file and you are ready to go.
Creating Models and Migration
The first thing we will do in this newly created application, create a model and migration. For this example I will be creating a Post model.
Open the terminal and run the below command.
php artisan make:model Post -mfThe -mf flag will create a migration and factory for the Post model.
Once the model, migration, and factory are generated, open the migration file from the database/migrations folder and update with the below one.
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreatePostsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->text('content');
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('posts');
}
}This is a very basic migration file, with a post name and content fields. One more thing we will be adding is the deleted_at field using the $this->softDeletes().
Now, open the terminal again and run php artisan migrate command to create the posts table.
Before jumping to the next section, let's update the Post model. Open the app\Post.php file and update with the below ones.
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Post extends Model
{
use SoftDeletes;
protected $fillable = ['name', 'content'];
protected $dates = ['deleted_at'];
protected $hidden = ['created_at', 'updated_at'];
}In the above example, we have included the SoftDeletes trait provided by the Laravel and added to our model.
Seeding Dummy Data
Now we have our model file updated, let's open the Laravel Model Factory for Post model which we created alongside the migration and model.
Open the PostFactory.php file from database/factories folder and update with the below ones.
use App\Post;
use Faker\Generator as Faker;
$factory->define(Post::class, function (Faker $faker) {
return [
'name' => $faker->sentence,
'content' => $faker->realText(50)
];
});Using Laravel Tinker
Instead of creating some routes with a controller, I will be using the Laravel Tinker in this post because we just want to play around with some data.
Open your command line terminal and run the below command.
php artisan tinkerOnce you run the above command you will be entered into a terminal-based shell environment where we can run Laravel code.
Type the below one line of code in this terminal and hit enter.
factory('App\Post',4)->create();Once you run the above code, Laravel's model factory will create 4 database records for the posts table and return output something like below.
>>> factory('App\Post',4)->create();
=> Illuminate\Database\Eloquent\Collection {#2989
all: [
App\Post {#2985
name: "Debitis tempora nihil aut repellat cupiditate aut dolorum.",
content: "Dormouse went on, looking anxiously round to see.",
id: 5,
},
App\Post {#2983
name: "Laudantium aliquid voluptas laborum quis doloremque aut.",
content: "Alice's first thought was that you think you're.",
id: 6,
},
App\Post {#2982
name: "Deleniti repudiandae dolores impedit deserunt sit.",
content: "WOULD not remember ever having seen in her face.",
id: 7,
},
App\Post {#2984
name: "Dolor harum ad hic aut et veniam.",
content: "The Dormouse had closed its eyes by this time.",
id: 8,
},
],
}
>>>Now type below code and you will be presented with the total number of records.
>>> App\Post::count();
=> 4Now, I assume you will be familiar with this command-line utility, let's move ahead a see how we can use the soft delete on our Post model.
Soft Deleted Models Query Operations
As we know that when we will delete a model record, it will be soft-deleted as we have used the SoftDeletes trait in our model. So let's try to delete a record and see the output.
>>> $post = App\Post::find(2);
=> App\Post {#3003
id: 2,
name: "Pariatur ut id voluptatem explicabo.",
content: "CAN I have to ask his neighbour to tell its age.",
deleted_at: null,
}
>>> $post->delete();
=> true
>>> $post
=> App\Post {#3003
id: 2,
name: "Pariatur ut id voluptatem explicabo.",
content: "CAN I have to ask his neighbour to tell its age.",
deleted_at: "2019-08-01 14:32:52",
}
>>>As you can see we firstly find the post with id 2 and then perform the delete() method on it which returned as true. When we will print this post, we can see that deleted_at field has been updated with the time when we deleted this post.
Now, if we count the number of records for our posts table, it will return the 3 records as one record is soft deleted but still exists in our database.
>>> App\Post::count();
=> 3Including Soft Deleted Models
We can include the soft deleted models forcefully using the withTrashed() scope provided by the Laravel's Eloquent.
>>> App\Post::withTrashed()->get();
=> Illuminate\Database\Eloquent\Collection {#2986
all: [
App\Post {#3004
id: 1,
name: "Aut harum voluptatum ipsam dolor velit fugit.",
content: "Queen's hedgehog just now, only it ran away when.",
deleted_at: null,
},
App\Post {#3007
id: 2,
name: "Pariatur ut id voluptatem explicabo.",
content: "CAN I have to ask his neighbour to tell its age.",
deleted_at: "2019-08-01 14:32:52",
},
App\Post {#3008
id: 3,
name: "Praesentium et quia expedita cum dicta dolorem.",
content: "The hedgehog was engaged in a solemn tone, only.",
deleted_at: null,
},
App\Post {#3009
id: 4,
name: "Veniam non est culpa.",
content: "ONE respectable person!' Soon her eye fell upon.",
deleted_at: null,
},
],
}
>>>Including Only Soft Deleted Models
We can also query only the soft deleted models using onlyTrashed() method.
>>> App\Post::onlyTrashed()->get();
=> Illuminate\Database\Eloquent\Collection {#2954
all: [
App\Post {#2983
id: 2,
name: "Pariatur ut id voluptatem explicabo.",
content: "CAN I have to ask his neighbour to tell its age.",
deleted_at: "2019-08-01 14:32:52",
},
],
}
>>>Including Non Soft Deleted Models
We can also fetch the records without soft deleted ones using withoutTrashed() scope.
>>> App\Post::withoutTrashed()->get();
=> Illuminate\Database\Eloquent\Collection {#2984
all: [
App\Post {#2996
id: 1,
name: "Aut harum voluptatum ipsam dolor velit fugit.",
content: "Queen's hedgehog just now, only it ran away when.",
deleted_at: null,
},
App\Post {#2990
id: 3,
name: "Praesentium et quia expedita cum dicta dolorem.",
content: "The hedgehog was engaged in a solemn tone, only.",
deleted_at: null,
},
App\Post {#2995
id: 4,
name: "Veniam non est culpa.",
content: "ONE respectable person!' Soon her eye fell upon.",
deleted_at: null,
},
],
}
>>>Restoring Soft Deleted Models
We can also bring the soft deleted records into original state using the restore() method.
>>> $post = App\Post::withTrashed()->whereId(2)->restore();
=> 1
>>> App\Post::all();
=> Illuminate\Database\Eloquent\Collection {#2984
all: [
App\Post {#3011
id: 1,
name: "Aut harum voluptatum ipsam dolor velit fugit.",
content: "Queen's hedgehog just now, only it ran away when.",
deleted_at: null,
},
App\Post {#3010
id: 2,
name: "Pariatur ut id voluptatem explicabo.",
content: "CAN I have to ask his neighbour to tell its age.",
deleted_at: null,
},
App\Post {#3024
id: 3,
name: "Praesentium et quia expedita cum dicta dolorem.",
content: "The hedgehog was engaged in a solemn tone, only.",
deleted_at: null,
},
App\Post {#3027
id: 4,
name: "Veniam non est culpa.",
content: "ONE respectable person!' Soon her eye fell upon.",
deleted_at: null,
},
],
}
>>>Permanently Deleting Models
Now we will look at how we can delete a record permanently using the forceDelete() method.
>>> App\Post::withTrashed()->get();
=> Illuminate\Database\Eloquent\Collection {#2990
all: [
App\Post {#3022
id: 1,
name: "Aut harum voluptatum ipsam dolor velit fugit.",
content: "Queen's hedgehog just now, only it ran away when.",
deleted_at: null,
},
App\Post {#3028
id: 2,
name: "Pariatur ut id voluptatem explicabo.",
content: "CAN I have to ask his neighbour to tell its age.",
deleted_at: "2019-08-01 14:49:41",
},
App\Post {#3029
id: 3,
name: "Praesentium et quia expedita cum dicta dolorem.",
content: "The hedgehog was engaged in a solemn tone, only.",
deleted_at: null,
},
App\Post {#3030
id: 4,
name: "Veniam non est culpa.",
content: "ONE respectable person!' Soon her eye fell upon.",
deleted_at: null,
},
],
}
>>> App\Post::onlyTrashed()->forceDelete();Now we will query the all records like ::all().
>>> App\Post::all();
=> Illuminate\Database\Eloquent\Collection {#3031
all: [
App\Post {#3032
id: 1,
name: "Aut harum voluptatum ipsam dolor velit fugit.",
content: "Queen's hedgehog just now, only it ran away when.",
deleted_at: null,
},
App\Post {#3033
id: 3,
name: "Praesentium et quia expedita cum dicta dolorem.",
content: "The hedgehog was engaged in a solemn tone, only.",
deleted_at: null,
},
App\Post {#3034
id: 4,
name: "Veniam non est culpa.",
content: "ONE respectable person!' Soon her eye fell upon.",
deleted_at: null,
},
],
}
>>>As you can see, only three records left in the database as the post with id 2 deleted permanently using the forceDelete() method.
Conclusion
In this post, we learned how we can soft delete records and query them easily. If you have any question or comments, please let us know.