
Laravel SoftDelete Avoid Unique Constraint Problem
When models are soft deleted, they are not actually removed from your database. Laravel use deleted_at field to indicate the visibility of the data when retrieved. If a model has a non-null deleted_at value, the model has been soft deleted and not showing.
But, since its not deleted from database, the unique constraint issue came out. Let’s say, User table must have unique email field and you want to soft delete 1 data. Then, you want to insert the same email address and error occurred because of its already exist.
So, there is a solution for it.
1. Create an observer
class UniqueSoftDeleteObserver
{
private const DELIMITER = '--';
public function restoring(Model $model)
{
if (!$model->trashed()) {
return;
} foreach ($model->getDuplicateAvoidColumns() as $column) {
if ($value = (explode(self::DELIMITER, $model->{$column})[1] ?? null)) {
$model->{$column} = $value;
}
}
}
public function deleted(Model $model)
{
foreach ($model->getDuplicateAvoidColumns() as $column) {
$newValue = time().self::DELIMITER.$model->{$column};
$model->{$column} = $newValue;
}
$model->save();
}
}After deleted, the selected fields will be prepend by timestamp and separated by delimiter.
[email protected] => [email protected]
If the data want to be restore, restoring event will trigger and remove the delimiter
2. Create a trait and use it in any of your model that use
trait AvoidDuplicateConstraintSoftDelete
{
public static function bootAvoidDuplicateConstraintSoftDelete()
{
static::observe(app(UniqueSoftDeleteObserver::class));
} public function getDuplicateAvoidColumns() : array
{
return [];
}
}3. Lets implement it,
class User
{
use SoftDeletes, AvoidDuplicateConstraintSoftDelete; ...
... public function getDuplicateAvoidColumns() : array
{
return [
'email'
];
}}
4. Done!
Incase, your database table don’t use unique constraint, you can validate like below,
return [
'email' => [
'required',
Rule::unique('users', 'email')->ignore($email)->withTrashed(),
//'unique:user,email,NULL,NULL,deleted_at,NULL'
]
]That’s it 😄
Thanks for your time….






