Laravel Validation using DatabaseRule
The Laravel database validation rules are more powerful and flexible than I realised at first.
Looking at the Available Validation Rules we can see that Exists and Unique both have the suffix (Database)
This is because the both implement the DatabaseRule trait which offers more power than might be expected.
While the Laravel documentation does hint at this functionality with a couple of examples it is well worth reading the Laravel API docs for this trait and even reviewing the source code.
These database rules are constructed with arguments providing the table and column names.
Once constructed we can chain on a number of additional constraints
where : Set a “where” constraint on the query
whereNot : Set a “where not” constraint on the query
whereNull : Set a “where null” constraint on the query
whereNotNull : Set a “where not null” constraint on the query
whereIn : Set a “where in” constraint on the query
whereNotIn : Set a “where not in” constraint on the query
withoutTrashed : Ignore soft deleted models during the existence check
onlyTrashed : Only include soft deleted models during the existence check
The best place to understand how to call these is the source code
In my case I have a multisite project where each article has a slug that has to be unique - but only for that site.
Each article has a site_id field which specifies the site the article is for.
My Validation rules
$request->validate([
'slug' => ['required', 'string', 'max:255',
Rule::unique('articles')
->where('site_id', $article->site_id)
->ignore($article->id),
],
'title' => 'required|string|max:255',
'synopsis' => 'required|string|max:1000',
'published_at' => 'nullable|date',
]);
The where parameters can take a number of forms but to me the most readable option is just column name and column value.
The ingore section seems to me to be something that should be the default - it just says allow the new value to be the same as the old value for the same article.