0

I am trying to update a row in the pages table.

The slug must be unique in the pages table on the slug and app_id field combined. i.e. there can be multiple slugs entitled 'this-is-my-slug' but they must have unique app_id.

Therefore I have found that formula for the unique rule is: unique:table,column,except,idColumn,extraColumn,extraColumnValue

I have an update method and getValidationRules method.

public function update($resource,$id,$request){
    $app_id=22;
    $request->validate(
      $this->getValidationRules($id,$app_id)
    );    
    // ...store
}  

When I test for just a unique slug the following works:

public function getValidationRules($id,$app_id){
    return [
        'title'=> 'required',
        'slug'=> 'required|unique:pages,slug,'.$id
    ];
}

However, when I try and add the app_id into the validation rules it returns server error.

public function getValidationRules($id,$app_id){
    return [
        'title'=> 'required',
        'slug'=> 'required|unique:pages,slug,'.$id.',app_id,'.$app_id
    ];
}

I have also tried to use the Rule facade, but that also returns server error. Infact I can't even get that working for just the ignore id!

public function getValidationRules($id,$app_id){
    return [
        'title'=> 'required',
        'slug'=> [Rule::unique('pages','slug')->where('app_id',$app_id)->ignore($id)]
    ];
}

Any help is much appreciated :)

jon
  • 1,429
  • 1
  • 23
  • 40

2 Answers2

0

I recommend you to add your own custom rule.

First run artisan make:rule SlugWithUniqueAppIdRule
This will create new file/class inside App\Rules called SlugWIthUniqueAppRule.php.

Next inside, lets add your custom rule and message when error occured.

public function passes($attribute, $value)
{
    // I assume you use model Page for table pages
    $app_id = request()->id;
    
    $pageExists = Page::query()
        ->where('slug', $slug)
        ->where('app_id', $app_id)
        ->exists();

    return !$pageExists;
}

public function message()
{
    return 'The slug must have unique app id.';
}

Than you can use it inside your validation.

return [
      'title'=> 'required|string',
     'slug' => new SlugWithUniqueAppIdRule(),
];

You can try it again and adjust this custom rule according to your needs.

Bonus:
I recommend to move your form request into separate class.
Run artisan make:request UpdateSlugAppRequest
And check this newly made file in App\Http\Requests.

This request class by default will consists of 2 public methods : authorize() and rules().
Change authorize to return true, or otherwise this route can not be accessed.
Move your rules array from controller into rules().

public function rules()
{
     return [
          'title'=> 'required|string',
         'slug' => new SlugWithUniqueAppIdRule(),
    ];
}

To use it inside your controller:

public function update(UpdateSlugAppRequest $request, $resource, $id){
    // this will return validated inputs in array format
    $validated = $request->validated();

    // ...store process , move to a ServiceClass
} 

This will make your controller a lot slimmer.

  • Thanks @dummy.learn , I've found what my problem was but I will take a look at your answer as a possible better approach. – jon Feb 10 '23 at 03:51
  • can you share your founded solution as answer here? I would like to know it as well. You can also accept it (yours) as best answer ^_^ – dummy.learn Feb 10 '23 at 03:55
  • Just writing it now :) – jon Feb 10 '23 at 03:56
0

Thanks for the respsonses. It turned out a couple of things were wrong. Firstly if you want to use the Rule facade for the validation rules, make sure you've included it:

use Illuminate\Validation\Rule; 

The other method for defining the validation rule seems to be limited to the following pattern:

unique:table,column,except,idColumn

The blog post that I read that showed you could add additional columns was for laravel 7, so i guess that is no longer the case for laravel 9.

Thanks for your responses and help in the chat!

jon
  • 1,429
  • 1
  • 23
  • 40