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

Overview

Laravel Unique Translation

IMPORTANT: March 2022

Support Ukraine

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.


GitHub release Laravel License Build Status Code Coverage 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.

This package also supports spatie/nova-translatable in case you are using Laravel Nova.

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

☑️ Laravel Nova

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}}');

🖥 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

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).

🚧 Testing

vendor/bin/phpunit

☕️ Credits

🔓 Security

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

📑 Changelog

A complete list of all notable changes to this package can be found on the releases page.

📜 License

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

Comments
  • regarding the error msg

    regarding the error msg

    atm to get the error you will use name.code but is there a way to pass an option that make the error msg unified whether am using a code or not ?

    ex.

    // form
    <input name="slug[en]" value="abc">
    <input name="slug[nl]" value="abc">
    
    // validate
    $attributes = request()->validate([
        'slug.*' => ["unique_translation:posts,slug,{$post->id}"],
    ]);
    
    // error
    @if($errors->has('slug'))
        {{ $errors->first('slug') }}
    @endif
    

    this way , either i use a single input or array, the error condition doesnt change.

    atm, here is how i do the validation

    foreach ($locales as $code) {
        $v = Validator::make($request->all(), ["slug.$code" => "unique:pages,slug->$code," . $id ?: '']);
    
        if ($v->fails()) {
            $validator->errors()->add('slug', 'this slug is already taken');
        }
    }
    

    on a side note

    also is it possible to use the validation rule with | pipe rules or do i have to use the array instead ?

    enhancement 
    opened by ctf0 8
  • JSON_EXTRACT() function not exist issue with MySQL lower versions (to 5.6)

    JSON_EXTRACT() function not exist issue with MySQL lower versions (to 5.6)

    My hosting provider does not support MySQL version 5.7. Maximum supported version is 5.6.46. So I'm facing JSON_EXTRACT and JSON_UNQUOTE function does not exist error.

    Is there any fix on that?

    opened by AjithLalps 5
  • Too many messages

    Too many messages

    Hi Thanks for your extension.

    I have some trouble.

    Example

    <input type="text" name="post_name[de]">
    <input type="text" name="post_name[en]">
    
    class MyRequest extends FormRequest{
      public function rules(): array
        {
            return [
                'post_name.*' => [
                    UniqueTranslationRule::for('posts', 'name')
                ]
            ];
    }}
    

    When i put exists values and submit form, i got a lot of messages: screenshot

    Is there any way to generate only one message for each language?

    Best regards

    opened by cugrif 5
  • Ignore deleted_at soft deteled field

    Ignore deleted_at soft deteled field

    How can I ignore soft deleted records?

    'FIELD_NAME.*' => [
    UniqueTranslationRule::for('TABLE_NAME', 'FIELD_NAME')->ignore(!0, 'deleted_at') -> NO WORKS
    UniqueTranslationRule::for('TABLE_NAME', 'FIELD_NAME')->ignore(!NULL, 'deleted_at') -> NO WORKS
    UniqueTranslationRule::for('TABLE_NAME', 'FIELD_NAME')->whereNull('deleted_at') -> NO WORKS
    ]
    
    opened by cubiczx 5
  • unique validation error while updating using form request

    unique validation error while updating using form request

    I form for saving the category. The name field is unique. I'm using FormRequest for validating the form. Create works fine. but while updating getting error showing The name.en has already been taken.

    form fields

                    <input class="form-control" name="name[en]" type="text" id="name-en" value="{{ old('name[en]', optional($serviceCategory)->getTranslation('name','en')) }}" minlength="1" maxlength="255" placeholder="{{ __('preferencesCategory.name_en__placeholder') }}">
                    <input class="form-control" name="name[ar]" type="text" id="name-ar" value="{{ old('name[ar]', optional($serviceCategory)->getTranslation('name','ar')) }}" minlength="1" maxlength="255" placeholder="{{ __('preferencesCategory.name_ar__placeholder') }}">
    

    FormRequest.php

      public function rules()
        {
            return [
                'code' => 'string|min:1|nullable',
                'name.*' => 'required|string|min:1|max:255|unique_translation:service_categories,name,{$this->serviceCategory->id}',
                'status' => 'string|min:1|nullable',
            ];
    

    web.php (route file)

    Route::put('service_category/{serviceCategory}', 'ServiceCategoriesController@update')
                ->name('service_categories.service_category.update')->where('id', '[0-9]+');
    

    controller.php

    public function update(ServiceCategory $serviceCategory, ServiceCategoriesFormRequest $request)
        {
            try {
                $data = $request->getData();
                $data['updated_by'] = \Auth::guard('admin')->user()->id;
    
                $serviceCategory->update($data);
    
                return redirect()->route('service_categories.service_category.index')
                    ->with('success_message', 'Service Category was successfully updated.');
            } catch (Exception $exception) {
                return back()->withInput()
                    ->withErrors(['unexpected_error' => 'Unexpected error occurred while trying to process your request.']);
            }
        }
    
    opened by AjithLalps 4
  • UniqueTranslationRule is ignored - Laravel 8

    UniqueTranslationRule is ignored - Laravel 8

    Hello @ivanvermeyen!

    First, thanks for developing this great package. I'm trying to use it on a Laravel 8 project I started recently, but I can't get it to work. I'm pretty sure I forgot something stupid, but I've been looking for a week and even showed it to a colleague, but we can't find an error. Maybe you can help me?

    When I try to update a post with the same slug as another (or create once with the same slug as another), the UniqueTranslationRule rule doesn't detect it. My form request App\Http\Requests\Admin\PostRequest has this rules function :

    public function rules()
        {
            return [
                'post.title' => 'required|string',
                'post.slug' => ['required', 'max:2000', UniqueTranslationRule::for('posts', 'slug'), 'regex:/^([a-z0-9\-\/]*)$/'],
                'post.category_id' => ['nullable', 'numeric', Rule::exists('categories', 'id')
                    ->where('deleted_at', NULL)->where('type', Category::TYPE_POST)],
            ];
        }
    

    Things I checked :

    • Spatie\laravel-translatable is working (all data are saved in JSON in the database)
    • I call use CodeZero\UniqueTranslation\UniqueTranslationRule; at the beginning of the file
    • I remove and resinstalled the package with composer require codezero/laravel-unique-translation

    Thanks in advance ! 🙏

    opened by benjaminhaeberli 2
  • How to validate a single value?

    How to validate a single value?

    In this case:

    {
      "en":"unique_title", //scoped for en
      "lt":"unique_title", //scoped for lt
    }
    
    <input name="title_en" value="unique_title" />
    <input name="title_lt" value="some other title"/>
    

    I want to have different validation for each input like:

    $attributes = request()->validate([
        'title_lt' => 'required|unique_translation:posts:title',
        'title_en' => 'unique_translation:posts:title',
    ]);
    

    how would i check against a specific value? Or this will just work?

    opened by Neophen 2
  • Unique comparison is case sensitive

    Unique comparison is case sensitive

    It seems that the where clause in the unique_translation rule is case sensitive.

    https://github.com/codezero-be/laravel-unique-translation/blob/1eb3d56b1f4af36b4985730619838bb124436b81/src/UniqueTranslationValidator.php#L161-L164

    According to my Google searches, MySQL is supposed to be case insensitive when using a collation that ends in _ci (I'm using utf8mb4_unicode_ci). But that's not what my tests are saying...

    Is anyone else having this issue?

    opened by ivanvermeyen 2
  • an issue with spatie/laravel-tags

    an issue with spatie/laravel-tags

    am not sure if its an issue with the https://github.com/spatie/laravel-tags package or something is missing from the validation package,

    but here is what i have

    $request->validate([
        'name.*' => 'unique_translation:tags,name,' . $id
    ]);
    

    the db name column i will update is

    {"en": "black"}
    

    and will be replaced with

    {
      "en": "test",
      "fr": null
    }
    

    but i keep getting the error that the item already exists in the db, so maybe u can help me with this one

    opened by ctf0 2
  • MariaDB / PostgreSQL compatibility

    MariaDB / PostgreSQL compatibility

    Hello, I'm using this package with MariaDB 10.6.9, Laravel 9, PHP 8.1 and Spatie Laravel Translatable v6, but it is not working. Is it compatible with this environment or only compatible only with MySQL? Thanks.

    opened by mahfoudfx 1
  • Error during test Undefined array key

    Error during test Undefined array key "collation"

    Hi! Fantastic package. Works great during browser usage, but I get a really weird error when testing the form I want to validate. Basics: I am using Laravel-translatable from Spatie and want to check that the title is unique in a JSON column for a specific locale. My form is really simple:

    <label>TítuloES</label><br>
    <input class="border" type="text" name="title[es]"><br>
    <label>TítuloEN</label><br>
    <input class="border" type="text" name="title[en]"><br>
    

    My validation looks like this:

     $attributes = request()->validate([
                'title.*' => 'required|max:255|unique_translation:posts,title',
                'summary.*' => 'required',
                'content.*' => 'required',
                'imagetitle' => [
                    'sometimes', 
                    'mimes:jpeg,jpg,png'
                    ]
            ]);
    

    When I use the web, it works, but when I test it, I get a super long error, but the most important part seems this one:

    The following exception occurred during the last request:
    
    ErrorException: Undefined array key "collation" in E:\Programas\laragon\www\webtronica\vendor\codezero\laravel-unique-translation\src\UniqueTranslationValidator.php:238
    Stack trace:
    #0 E:\Programas\laragon\www\myapp\vendor\laravel\framework\src\Illuminate\Foundation\Bootstrap\HandleExceptions.php(259): Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(2, 'Undefined array...', 'E:\\Programas\\la...', 238)
    #1 E:\Programas\laragon\www\myapp\vendor\codezero\laravel-unique-translation\src\UniqueTranslationValidator.php(238): Illuminate\Foundation\Bootstrap\HandleExceptions->Illuminate\Foundation\Bootstrap\{closure}(2, 'Undefined array...', 'E:\\Programas\\la...', 238)
    #2 E:\Programas\laragon\www\myapp\vendor\laravel\framework\src\Illuminate\Database\Query\Builder.php(1551): CodeZero\UniqueTranslation\UniqueTranslationValidator->CodeZero\UniqueTranslation\{closure}(Object(Illuminate\Database\Query\Builder))
    

    I guess the package is trying to get some info from the DB, but it is not getting it. Then, everything breaks. So, I have 2 questions: Should I somehow modify configuration of PHP unit? Now it looks like this:

      <php>
        <server name="APP_ENV" value="testing"/>
        <server name="BCRYPT_ROUNDS" value="4"/>
        <server name="CACHE_DRIVER" value="array"/>
        <server name="DB_CONNECTION" value="sqlite"/>
        <server name="DB_DATABASE" value=":memory:"/>
        <server name="MAIL_DRIVER" value="array"/>
        <server name="QUEUE_CONNECTION" value="sync"/>
        <server name="SESSION_DRIVER" value="array"/>
        <env name="DB_CONNECTION" value="sqlite"/>
        <env name="RECAPTCHA_KEY" value="6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"/>
        <env name="RECAPTCHA_SECRET" value="6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe"/>
      </php>
    </phpunit>
    

    Question number 2: when using browser and submitting the form, no error is seen and the post is created with success. The collation fields of my database are empty, so I don't understand how its working: imagen

    Many thanks!!!

    opened by mperezsc 5
Releases(4.0.0)
Owner
CodeZero
Programming Enthusiasts
CodeZero
PHP library to collect and manipulate gettext (.po, .mo, .php, .json, etc)

Gettext Note: this is the documentation of the new 5.x version. Go to 4.x branch if you're looking for the old 4.x version Created by Oscar Otero http

Gettext 651 Dec 29, 2022
Brings localization feature to tightenco/jigsaw using JSON files

Jigsaw localization Brings localization feature to tightenco/jigsaw using JSON files. Get started Setup Bring jigsaw-localization to your Jigsaw proje

Elaborate Code 6 Nov 1, 2022
Simple user settings facade for Hyperf. Settings are stored as JSON in a single database column, so you can easily add it to an existing table.

hyperf-user-settings Simple user settings util for hyperf Settings are stored as JSON in a single database column, so you can easily add it to an exis

lysice 1 Oct 15, 2021
JSONFinder - a library that can find json values in a mixed text or html documents, can filter and search the json tree, and converts php objects to json without 'ext-json' extension.

JSONFinder - a library that can find json values in a mixed text or html documents, can filter and search the json tree, and converts php objects to json without 'ext-json' extension.

Eboubaker Eboubaker 2 Jul 31, 2022
YCOM Impersonate. Login as selected YCOM user 🧙‍♂️in frontend.

YCOM Impersonate Login as selected YCOM user in frontend. Features: Backend users with admin rights or YCOM[] rights, can be automatically logged in v

Friends Of REDAXO 17 Sep 12, 2022
Value Object that represents a monetary value (using a currency's smallest unit).

This project has been abandoned. It was only ever intended to be used as an example for PHPUnit features etc. and not for usage in production. I am so

Sebastian Bergmann 735 Dec 30, 2022
Share value objects that contain the same primitive value as a singleton

sharable-value-objects Share value objects that contain the same primitive value as a singleton. Singletons are kept under WeakReference objects. Inst

mpyw 5 Nov 14, 2021
Check a project's code coverage, optionally enforcing a minimum value

coverage-check Display the code coverage for a project using a clover.xml file, optionally enforcing a minimum code coverage percentage. This package

Permafrost Software 15 Aug 9, 2022
This tool check syntax of PHP files faster than serial check with fancier output.

PHP Parallel Lint This application checks syntax of PHP files in parallel. It can output in plain text, colored text, json and checksyntax formats. Ad

PHP Parallel lint 202 Dec 22, 2022
CRUD php application to check in and check out employees and show daily building occupation

CRUD php application to check in and check out employees and show daily building occupation. Employees are required to self check their temperature and tick a checkbox to specify whether their temperature is below 38°C else they are invited to stay home. (Implemented in php with bootstrap4 for styling and datatable jquery plugin for table formatting and additional features).

null 2 Feb 20, 2022
PHP Parallel Lint - This tool check syntax of PHP files faster than serial check with fancier output

PHP Parallel Lint This application checks syntax of PHP files in parallel. It can output in plain text, colored text, json and checksyntax formats. Ad

PHP Parallel lint 156 Apr 24, 2022
🔍 Generates database queries based on one unique string

?? Laravel Search String Generates database queries based on one unique string using a simple and customizable syntax. Introduction Laravel Search Str

Loris Leiva 735 Dec 30, 2022
Stores the customer_user for WooCommerce orders and subscriptions in the post_author column of posts table.

Post Author Optimization for WooCommerce Requires PHP: 7.0 WP requires at least: 5.7 WP tested up to: 5.7 WC requires at least: 5.6.0 WC tested up to:

Devin Price 9 Apr 2, 2022
A laravel package to generate model hashid based on model id column.

Laravel Model Hashid A package to generate model hash id from the model auto increment id for laravel models Installation Require the package using co

Touhidur Rahman 13 Jan 20, 2022
Reset UI Bookmarks allows admin users to reset their own UI bookmarks such as state of filters, column positions and applied sorting ( e.g Sales > Orders ).

Reset Ui Bookmarks Reset UI Bookmarks becomes an invaluable tool while working daily in the admin panel, especially on Magento® instances with a large

Magenizr 23 Oct 19, 2022
Add a progress bar column to your Filament tables.

Add a progress bar column to your Filament tables. This package provides a ProgessColumn that can be used to display a progress bar in a Filament tabl

Ryan Chandler 22 Nov 12, 2022
Column sorting with Laravel 8 & 9 - Eloquent sortable

Column sorting for Laravel - Sortable - Sort by Larasort : Column sorting for Laravel - Sort easily Introduction - Larasort package This package allow

Stephen Damian - Laravel Developer 11 Sep 20, 2022
⚙️Simple key/value typed settings for your Laravel app with synchronized json export

Simple key/value typed settings for your Laravel app Create, store and use key/value settings, typed from numbers over dates to array, cached for quic

elipZis 8 Jan 7, 2023
Provides JSON pointer as a value object

json-pointer Provides JSON pointer as a value object. Installation Run composer require ergebnis/json-pointer Usage ReferenceToken You can create a Re

null 3 Dec 15, 2022
A small CLI tool to check missing dependency declarations in the composer.json and module.xml

Integrity checker Package allows to run static analysis on Magento 2 Module Packages to provide an integrity check of package. Supported tools: Compos

run_as_root GmbH 13 Dec 19, 2022