It's horrible to see what is happening now in Ukraine, as Russian army is bombarding houses, hospitals and kindergartens.
Please check out supportukrainenow.org for the ways how you can help people there. Spread the word.
And if you are from Russia and you are against this war, please express your protest in some way. I know you can get punished for this, but you are one of the hopes of those innocent people.
Imagine you want store a slug
for a Post
model in different languages.
The amazing spatie/laravel-translatable
package makes this a cinch!
But then you want to make sure each translation is unique for its language.
That's where this package comes in to play.
This package also supports spatie/nova-translatable
in case you are using Laravel Nova and filamentphp/spatie-laravel-translatable-plugin
in case you are using Filament.
- PHP ^7.2 or PHP ^8.0
- MySQL >= 5.7
- Laravel >= 6
- spatie/laravel-translatable ^4.4|^5.0|^6.0
- spatie/nova-translatable ^3.0
- filamentphp/spatie-laravel-translatable-plugin ^3.0
Require the package via Composer:
composer require codezero/laravel-unique-translation
Laravel will automatically register the ServiceProvider.
For the following examples, I will use a slug
in a posts
table as the subject of our validation.
Your form can submit a single slug:
<input name="slug">
We can then check if it is unique in the current locale:
$attributes = request()->validate([
'slug' => 'required|unique_translation:posts',
]);
You could also use the Rule instance:
use CodeZero\UniqueTranslation\UniqueTranslationRule;
$attributes = request()->validate([
'slug' => ['required', UniqueTranslationRule::for('posts')],
]);
Your form can also submit an array of slugs.
<input name="slug[en]">
<input name="slug[nl]">
We need to validate the entire array in this case. Mind the slug.*
key.
$attributes = request()->validate([
'slug.*' => 'unique_translation:posts',
// or...
'slug.*' => UniqueTranslationRule::for('posts'),
]);
Maybe your form field has a name of post_slug
and your database field slug
:
$attributes = request()->validate([
'post_slug.*' => 'unique_translation:posts,slug',
// or...
'post_slug.*' => UniqueTranslationRule::for('posts', 'slug'),
]);
If you are using multiple database connections, you can specify which one to use by prepending it to the table name, separated by a dot:
$attributes = request()->validate([
'slug.*' => 'unique_translation:db_connection.posts',
// or...
'slug.*' => UniqueTranslationRule::for('db_connection.posts'),
]);
If you're updating a record, you may want to ignore the post itself from the unique check.
$attributes = request()->validate([
'slug.*' => "unique_translation:posts,slug,{$post->id}",
// or...
'slug.*' => UniqueTranslationRule::for('posts')->ignore($post->id),
]);
If your ID column has a different name, or you just want to use another column:
$attributes = request()->validate([
'slug.*' => 'unique_translation:posts,slug,ignore_value,ignore_column',
// or...
'slug.*' => UniqueTranslationRule::for('posts')->ignore('ignore_value', 'ignore_column'),
]);
You can add 4 types of where clauses to the rule.
$attributes = request()->validate([
'slug.*' => "unique_translation:posts,slug,null,null,column,value",
// or...
'slug.*' => UniqueTranslationRule::for('posts')->where('column', 'value'),
]);
$attributes = request()->validate([
'slug.*' => "unique_translation:posts,slug,null,null,column,!value",
// or...
'slug.*' => UniqueTranslationRule::for('posts')->whereNot('column', 'value'),
]);
$attributes = request()->validate([
'slug.*' => "unique_translation:posts,slug,null,null,column,NULL",
// or...
'slug.*' => UniqueTranslationRule::for('posts')->whereNull('column'),
]);
$attributes = request()->validate([
'slug.*' => "unique_translation:posts,slug,null,null,column,NOT_NULL",
// or...
'slug.*' => UniqueTranslationRule::for('posts')->whereNotNull('column'),
]);
If you are using Laravel Nova in combination with spatie/nova-translatable
, then you can add the validation rule like this:
Text::make(__('Slug'), 'slug')
->creationRules('unique_translation:posts,slug')
->updateRules('unique_translation:posts,slug,{{resourceId}}');
If you are using Filament in combination with filamentphp/spatie-laravel-translatable-plugin
, then you can add the validation rule like this:
TextInput::make('slug')
->title(__('Slug'))
->rules([
UniqueTranslationRule::for('posts', 'slug')
])
TextInput::make('slug')
->title(__('Slug'))
->rules([
fn (Get $get) => UniqueTranslationRule::for('posts', 'slug')->ignore($get('id'))
])
Your existing slug
column (JSON) in a posts
table:
{
"en":"not-abc",
"nl":"abc"
}
Your form input to create a new record:
<input name="slug[en]" value="abc">
<input name="slug[nl]" value="abc">
Your validation logic:
$attributes = request()->validate([
'slug.*' => 'unique_translation:posts',
]);
The result is that slug[en]
is valid, since the only en
value in the database is not-abc
.
And slug[nl]
would fail, because there already is a nl
value of abc
.
You can pass your own error messages as normal.
When validating a single form field:
<input name="slug">
$attributes = request()->validate([
'slug' => 'unique_translation:posts',
], [
'slug.unique_translation' => 'Your custom :attribute error.',
]);
In your view you can then get the error with $errors->first('slug')
.
Or when validation an array:
<input name="slug[en]">
$attributes = request()->validate([
'slug.*' => 'unique_translation:posts',
], [
'slug.*.unique_translation' => 'Your custom :attribute error.',
]);
In your view you can then get the error with $errors->first('slug.en')
(en
being your array key).
vendor/bin/phpunit
If you discover any security related issues, please e-mail me instead of using the issue tracker.
A complete list of all notable changes to this package can be found on the releases page.
The MIT License (MIT). Please see License File for more information.