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.