Um dos recursos mais interessantes do Laravel é a possibilidade de implementação de “soft delete” com extrema facilidade nos sistemas, só que com isso surgem alguns problemas.
Para manter a integridade dos relacionamentos na base de dados, a utilização de “foreign keys” não é suficiente quando se usa “sof delete”, e seria necessário a criação de inúmeras “triggers” para executar as ações em cascata originadas pela “exclusão” de um registro, “exclusão” entre aspas porque usando “soft delete” nenhum registro é excluído fisicamente. Mas mesmo implementando o “soft delete” por padrão no sistema, haverão casos de tabelas que não será necessário ficar mantendo um histórico de registros, e que uma exclusão física seria recomendado para não ficar sobrecarregando o banco de dados com registros desnecessários, principalmente se uma rotina de backups é executada.
Foi então que após pesquisar bastante, e ver inumeras sugestões, como reescrever funções nativas do framework e tantas outras absurdas, que resolvi criar minha própria solução.
Vamos lá.
Todos os modelos em um projeto padrão utilizando Laravel estendem do ORM Eloquent, então a primeira coisa é criar um modelo base, de onde todos os outros modelos do sistema passarão a estender.
<?php namespace App; use Eloquent; use Illuminate\Database\Eloquent\SoftDeletes; /** * Class Model * @package App */ class Model extends Eloquent { use SoftDeletes; /** * Enable Table Timestamps * * @var bool */ public $timestamps = true; /** * Execute Actions On Boot * * @return void */ public static function boot() { parent::boot(); static::deleting(function($model) { // CASCADE SOFT DELETE if (isset($model->cascadeDelete)) { collect($model->cascadeDelete)->each(function ($class, $method) use ($model) { if (method_exists($model, $method)) { collect($model->$method($class)->get())->each(function ($model) { $model->delete(); }); $model->$method($class)->delete(); } }); } // CASCADE PERMANENTLY DELETE if (isset($model->cascadeForceDelete)) { collect($model->cascadeForceDelete)->each(function ($class, $method) use ($model) { if (method_exists($model, $method)) { collect($model->$method($class)->get())->each(function ($model) { $model->forceDelete(); }); $model->$method($class)->forceDelete(); } }); } }); } } ?>
Agora, todo modelo que estender de “Model”, vai usar “soft delete” por padrão, e para que uma exclusão em cascata ocorra, ou seja, todos os relacionamentos que por ventura devam ser excluídos também sejam, você precisa definir a lista de métodos e classes que devem ser excluídos.
<?php namespace App; use App\Model; /** * Class Example * @package App */ class Example extends Model { /** * Table name * * @var string */ public $table = 'example'; /** * Relations that should be soft deleted * * @var array */ public $cascadeDelete = [ 'hasMany' => \App\Relation::class, ]; /** * Relations that should be permanently deleted * * @var array */ public $cascadeForceDelete = [ 'hasMany' => \App\Relation::class, ]; /** * @return \Illuminate\Database\Eloquent\Relations\HasMany **/ public function Relations() { return $this->hasMany(\App\Relation::class); } } ?>
Essa solução tem funcionado muito bem até então, e tem sido adotada como padrão em todos os sistemas que desenvolvo usando Laravel.
Espero ter ajudado.