1

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

4
  • If your slug is always based on the name, there's no need for the slug comparison. And if this is the case, laravel comes with a unique validation rule that can be applied on the name field and the rule comes with the ability to ignore an id if required (for example when updating). laravel.com/docs/9.x/validation#rule-unique Commented Feb 17, 2022 at 3:09
  • If you are going to use this validation logic in multiple use cases I suggest you create a customer rule: laravel.com/docs/9.x/validation#custom-validation-rules instead of defining it here within a closure. Commented Feb 17, 2022 at 3:23
  • Have look at laravel.com/docs/9.x/validation#rule-unique . This may answer your question. 'email' => Rule::unique('users')->where(function ($query) { return $query->where('account_id', 1); }) Commented Feb 17, 2022 at 3:32
  • Instead of fetching the rows and checking if slug or lowercased name exists, you can use orWhere condition on the query and instead of getting the rows with get() you can simply use exists. The downside is the error message customization. Commented Feb 17, 2022 at 4:42

1 Answer 1

2

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

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.