> LOADING ARTICLE...
28 Jul 2025 Desenvolvimento

Como usar Soft Deletes com Eloquent nos Models do Laravel

Como usar Soft Deletes com Eloquent nos Models do Laravel

soft deletes laravel

O Laravel disponibiliza funcionalidades espetaculares para trabalhar com registos nas bases de dados e os Soft Delete é mais uma dessas funcionalidades.

Neste post, vou tentar explicar como podemos utilizar os Soft Deletes na prática. Antes de mergulharmos neste tópico vou só explicar que raio são afinal os Soft Deletes no Laravel.

Basicamente podemos dizer que Soft Delete é uma operação que marca um registo como inutilizado sem ser necessário eliminá-lo definitivamente da base de dados.

A definição anterior é simples o suficiente para percebermos que quando os Models são “Soft Deleted” ou eliminados de forma suave na tradução ipsis verbis, eles não são verdadeiramente eliminados da base de dados, em vez disso, é criado um atributo deleted_at no Model e inserido na base de dados. Desta forma, qualquer registo “Soft Deleted” terá um atributo deleted_at com um valor “not null” do tipo datetime, o que fará com que esse registo seja considerado “soft deleted”.

Vamos então pôr as mãos na massa.

Criar um projecto Laravel

Como exemplo vamos criar uma nova aplicação Laravel. Nesta instalação vamos utilizar o Composer. Abre então a tua linha de comandos na pasta onde queres criar o projecto e corre o seguinte comando:

composer create-project laravel/laravel SoftDeleteApp

Uma vez finalizada a instalação e criada uma base de dados no phpMyAdmin ou em qualquer aplicação cliente de MySql vamos ao ficheiro .env e inserir as configurações de base de dados. Vamos assumir que este passo é basico para ti, por isso não vamos perder tempo com isto e vamos continuar.

Criar Model e Migrations

A primeira coisa que pensamos em fazer quando criamos uma nova aplicação (obviamente depois de levantamento de requisitos e um planeamento bem feito) é criar os Models e as Migrations. Para este exemplo criei o model Post.

Abre o teu terminal e executa o seguinte comando

php artisan make:model Post -mf

As flags -mf servem para criar a respetiva migration e a factory para o model Post.

Uma vez criado o Model, a Migration e a Factory vamos abrir o ficheiro da migration. Como deves saber podes encontrar este ficheiro em database/migrations e edita com o seguinte código:

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');
    }
}

Esta é uma migration basica com o campo name e o content. Iremos adicionar também o campo deleted_at usando $this->softDeletes().

Agora, já sabes; No terminal executa php artisan migrate para criares a tabela posts.

Antes de seguirmos em frente vamos só editar o model Post. Abre o ficheiro app\Post.php e edita com as seguintes linhas:

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'];
}

No exemplo anterior incluímos o trait SoftDeletes disponibilizado pelo Laravel.

Seeding de dados de teste

Já com o nosso Model completo, vamos abrir a nossa factory (Factories) para o model Post que criámos juntamente com o Model e a Migration. O ficheiro PostFactory.php está localizado na pasta database/factories e vamos adicionar nele o seguinte códifo:

use App\Post;
use Faker\Generator as Faker;

$factory->define(Post::class, function (Faker $faker) {
    return [
        'name'  =>  $faker->sentence,
        'content'   =>  $faker->realText(50)
    ];
});

Usando Laravel Tinker

Em vez de criarmos algumas Rotas com um Controller, eu usei o Laravel Tinker para criar este tutorial porque o nosso objectivo é “brincarmos” à volta de alguns dados.

Abre o teu terminal e digita:

php artisan tinker

Depois de executarmos o anterior comando entraremos num ambiente baseado em linhas de comando onde podemos executar código Laravel. (Não é porreiro???)

Agora simplesmente digita a seguinte linha de código:

factory('App\Post',4)->create();

Já executaste??? Vai então à tua base de dados e poderás verificar que foram criados 4 registos na tabela posts e receberás o seguinte retorno.

>>> 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,
       },
     ],
   }
>>>

Agora digita o seguinte código e receberás o número total de registos.

>>> App\Post::count();
=> 4

Podes praticar e brincar com esta consola à tua vontade. Antes de prosseguirmos, no entanto deixa alguns registos na tabela para continuares a fazer esye tutorial.

Vamos assumir agora que já estás familiarizado com esta funcionalidade e vamos seguir em frente para vermos como podemos usar os soft deletes no teu model Post.

Operações Query para conseguirmos registos Soft Deleted

Como já falámos, quando fizermos delete de um registo, ele será “soft-deleted” porque estamos a usar o trait SoftDeletes. Vamos então eliminar um registo e ver o retorno:

>>> $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: "2021-05-01 14:32:52",
   }
>>>

Como podes ver, primeiro fizemos find do post com o id 2 e depois executámos o método delete() o qual retornou true. Quando fizermos print deste post, podemos ver que foi feito update no campo deleted_at com a data/hora que foi eliminado.

Agora, se contarmos o número de registos na tabela posts o retorno será somente 3 porque um dos registos foi eliminado mas ele continua a existir na nossa base de dados.

>>> App\Post::count();
=> 3

Pesquisa incluindo os registos “Soft-Deleted”

Podemos incluir os models eliminados de “forma suave” se usarmos o metodo scope withTrashed() que é disponibilizado pelo Eloquent do Laravel

>>> 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: "2021-05-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,
       },
     ],
   }
>>>

Como podes ver o id 2 está incluído na anterior pesquisa e é o unico registo onde o campo deleted_at não é null.

Pesquisa de registos Soft Deleted

No tópico anterior incluímos os registos soft deleted na pesquisa. Agora vamos pesquisar unicamente os registos eliminados. Para isso usamos o método scope onlyTrashed().

>>> 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: "2021-05-01 14:32:52",
       },
     ],
   }
>>>

Pesquisa de registo não eliminados

Como não podia deixar de ser, podemos também pesquisar unicamente os models não eliminados. Para isso usamos o método withoutTrashed().

>>> 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,
       },
     ],
   }
>>>

Podes encadear todos os métodos Eloquent a seguir aos métodos SofDelete

Recuperar models soft-deleted

Sim, também é possível recuperar registos eliminados se usares o trait SoftDelete. Vê o seguinte exemplo onde usamos o método restore():

>>> $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,
       },
     ],
   }
>>>

Eliminar permanentemente os models

Agora iremos realmente eliminar um registo de forma permanente. Para esse fim usamos o método forceDelete().

Antes vamos eliminar novamente o id 2 como viste anteriormente. Executa rapidamente este comando:

>>> App\Post::find(2)->delete();

Sim, dá assim mesmo. Então eu não te disse antes que podes encadear métodos com o Eloquent???

Vamos retornar todos os registos. Digita:

>>> 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: "2021-05-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();

Pesquisa agora por todos os registos: usa 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,
       },
     ],
   }
>>>

Como podes ver, o retorno são apenas três registos e os post com o id 2 foi realmente eliminado de forma permanente e já não é possível recuperá-lo nem com o método restore(). Para conseguirmos usámos o método forceDelete() como concerteza já reparaste.

Conclusão

Neste post aprendemos como utilizar os Soft Deletes do Laravel de uma forma bem simples. Para integrares na tua aplicação basta criares as rotas que pretenderes e adicionares as funcionalidades que aprendeste neste post nos métodos do controller.
Alguma dúvida não hesites em comentar abaixo ou contactar-me através dos contactos disponibilizados neste site. Terei todo o gosto em ajudar-te.

About Post Author

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *