Using Soft Delete in Laravel Eloquent Models
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 SoftDeleteApp
Once 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 -mf
The -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 tinker
Once 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(); => 4
Now, 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(); => 3
Including 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.