Reputation: 8470
I have this values in my db:
id - name - created_at - updated_at - deleted_at
------------------------------------------------
1 - John - 2018-11-11 - 2018-11-11 - (NULL)
2 - John - 2018-11-11 - 2018-11-11 - 2018-11-11
If I search for "John" with my Datatable (Yajra) I only see the John with id=1
because I'm using softdeletes. My model is this:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class MyModel extends Model
{
use SoftDeletes;
protected $fillable = ['name'];
protected $dates = ['deleted_at'];
}
When I delete (destroy) a registry it puts a date at deleted_at
which is correct. But when I want to edit (update) John
the Validator is giving me the error that that value is already in use. My update method is this:
public function update(Request $request, $id)
{
$rules = array(
'name' => 'unique:my_table'
);
$validator = Validator::make($request->all(), $rules);
if ($validator->passes()) {
MyModel::find($id)->update($request->input());
return redirect()->route('myroute')->withFlashSuccess('Ok!');
} else {
return redirect()->back()->withInput()->withErrors($validator);
}
}
What I'm doing wrong?
Upvotes: 1
Views: 2153
Reputation: 6544
The problem has nothing to do with the SoftDeletes
, it is a validation issue. The unique
validation rule is very special, because in case of an update it needs to know which entry it may ignore when performing the validation. In the background, the rule is performing an SQL query like
IF EXISTS (
SELECT id
FROM my_table
WHERE name = 'some value'
)
SELECT 1
ELSE
SELECT 0
(it may not be the exact query, but similar).
As you can see, the query does not take into account if you perform an update or not. Because your entity already exists, it will return 1
and therefore fail the validation because it thinks that the value under validation is not unique.
But there is actually a way to make the validation work for updates. You simply have to add the id
of the existing entity (which is being validated) as third parameter to the validation rule. So your rules should look something like this:
$rules = [
'name' => 'unique:my_table,name,'.$id
];
Please be aware that there is also a second parameter for the unique
validation rule - the column of the database table you want to search in.
Edit:
In case the unique constraint does only relate to not deleted entries, meaning that a unique value may be reused if other occurences of the same value are flagged as deleted, then it may be necessary to add an additional where()
clause to the unique
validation rule. For this, the fourth parameter needs to be set to the identifier
column name and then we can add the additional where
clauses as pairs of two parameters.
$rules = [
'name' => 'unique:my_table,name,'.$id.',id,deleted_at,NULL'
];
This will add where('deleted_at', 'NULL')
(or whereNull('deleted_at')
) to the query.
Upvotes: 1
Reputation: 606
This person has written a blog post that looks like it would solve your problem:
https://wisdmlabs.com/blog/laravel-soft-delete-unique-validations/
I'm not 100% sure you want to do this though as you may later wish to use the restore() method to bring the soft-deleted data back. At which point, you'll have a collision.
Upvotes: 2