codezero/laravel-unique-translation

2.0.0 2019-10-11 16:56 UTC

README

GitHub release License Build Status Code Coverage Scrutinizer Code Quality Total Downloads

ko-fi

Check if a translated value in a JSON column is unique in the database.

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.

✅ Requirements

📦 Installation

Require the package via Composer:

composer require codezero/laravel-unique-translation

Laravel will automatically register the ServiceProvider.

🛠 Usage

For the following examples, I will use a slug in a posts table as the subject of our validation.

☑️ Validate a Single Translation

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')],
]);

☑️ Validate an Array of Translations

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'),
]);

☑️ Specify a Column

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'),
]);

☑️ Specify a Database Connection

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'),
]);

☑️ Ignore a Record with ID

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),
]);

☑️ Ignore Records with a Specific Column and Value

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'),
]);

☑️ Use Additional Where Clauses

You can add 4 types of where clauses to the rule.

where

$attributes = request()->validate([
    'slug.*' => "unique_translation:posts,slug,null,null,column,value",
    // or...
    'slug.*' => UniqueTranslationRule::for('posts')->where('column', 'value'),
]);

whereNot

$attributes = request()->validate([
    'slug.*' => "unique_translation:posts,slug,null,null,column,!value",
    // or...
    'slug.*' => UniqueTranslationRule::for('posts')->whereNot('column', 'value'),
]);

whereNull

$attributes = request()->validate([
    'slug.*' => "unique_translation:posts,slug,null,null,column,NULL",
    // or...
    'slug.*' => UniqueTranslationRule::for('posts')->whereNull('column'),
]);

whereNotNull

$attributes = request()->validate([
    'slug.*' => "unique_translation:posts,slug,null,null,column,NOT_NULL",
    // or...
    'slug.*' => UniqueTranslationRule::for('posts')->whereNotNull('column'),
]);

🖥 Example

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.

⚠️ Error Messages

Whether you are validating a single translation ('slug') or an array of translations ('slug.*'), if validation fails, you will find an error for both the single and the localized key:

$errors->first('slug');
$errors->first('slug.en');

You can pass your own error message with any of the following keys. The first one found will be used.

$attributes = request()->validate([
    'slug.*' => 'unique_translation:posts',
], [
    'slug.unique_translation' => 'Your custom :attribute error.',
    'slug.*.unique_translation' => 'Your custom :attribute error.',
    'slug.en.unique_translation' => 'Your custom :attribute error.',
]);

🚧 Testing

vendor/bin/phpunit

☕️ Credits

🔓 Security

If you discover any security related issues, please e-mail me instead of using the issue tracker.

📑 Changelog

See a list of important changes in the changelog.

📜 License

The MIT License (MIT). Please see License File for more information.