laravelvalidationruleslaravel-formrequest

Laravel unique validation for combined multiple fields by custom logic


I am currently using Laravel 9 for my project.

Here is my validation rules

public function rules()
{
    $parent_id = $this->parent_id != 0 ? $this->parent_id : null;

    return [
        'name' => [
            'required', 'string', 'min:2', 'max:50', function ($attribute, $value, $fail) use ($parent_id) {

                $categories = Category::select(['id', 'parent_id', 'name'])
                    ->where('parent_id', $parent_id)
                    ->where('id', '<>', $this->route('category')?->id) // for update
                    ->get();

                foreach ($categories as $row) {

                    if (str($row->name)->lower() == str($value)->lower()) {

                        $fail('The ' . $attribute . ' has already been taken.');

                    } elseif (str($row->name)->slug() == str($value)->slug()) {

                        $fail('The ' . $attribute .  ' slug matches another.');

                    }
                }
            }
        ],

        // more..
    ];
 }

Is there a short way to do this using Laravel Validation Rules.
https://laravel.com/docs/9.x/validation#available-validation-rules


Solution

  • As you are asking sort hand of unique rule. The (undocumented) format for the unique rule is:

    table[,column[,ignore value[,ignore column[,where column,where value]...]]]

    Note:: Multiple "where" conditions can be specified, but only equality can be checked. A closure (as in the accepted answer) is needed for any other comparisons.

    But not recommended. Rather use closure for better options and readability.

    Rule::unique('categories')
          ->where('parent_id', $parent_id)
          ->where(function ($sql) use ($request) {
              $sql->where('name', $request->name)
                  ->orWhere('slug', $request->name);
           })
    

    And separately handle the error messages

    As far as I understand you are trying to handle the uniqueness of possible any slug->name, slug->slug, name->slug, name->name conversation, in that case, I would recommend using uid/UUID with a slug to prevent duplication.

    Hope the answer helps