docsa
docsa

Reputation: 61

Laravel 5.5 cannot make validator in a form Request class

I want to check if a form input 'departement' is filled only if two 'villes' have the same name.

within controller this code wokds perfectly :

 $rules=[  'nom' => 'required', 'ville'=> 'required|exists:villes,nom'];
 $messages = [
      'depart.required' => 'Deux villes portent le même nom, preciser le 
 département'];
  $validator = Validator::make($request->All(), $rules,$messages);
  $validator->sometimes('depart_id', 'required|exists:departs,id', function 
  ($input) {
      return Ville::where('nom',$input->ville)->count()>1;
  });
  if ($validator->fails()) {
    return redirect('admin/etab/create')
            ->withErrors($validator)
            ->withInput();
    }

I put the same code in a Form Request class:

public function rules()
{
  $rules=[  'nom' => 'required', 'ville'=> 'required|exists:villes,nom'];
  $messages = [
      'depart.required' => 'Deux villes portent le même nom, preciser le 
  département',
  ];
  $validator = Validator::make($this->All(), $rules,$messages);
  $validator->sometimes('depart_id', 'required|exists:departs,id', function 
  ($input) {
      return Ville::where('nom',$input->ville)->count()>1;
  });
  return $validator;
}

I get "Type error: Argument 2 passed to Illuminate\Validation\Factory::make() must be of the type array, object given," I think error message is inadequate but I cannot find why this way does not work

Thanks ......

Upvotes: 2

Views: 2235

Answers (2)

user320487
user320487

Reputation:

You don't put all the validation logic in the rules method like that. Only the rule definitions go there. All you need is this:

public function rules()
{
  return [
    'nom' => 'required', 
    'ville'=> 'required|exists:villes,nom',
  ];
}

Laravel will handle the validation from there on out. You don't need to manually create a Validator class when using FormRequests.

Customizing the message involves creating a messages method within the class like so:

public function messages()
{
    return [
        'depart.required' => 'Deux villes portent le même nom, preciser le départemen'
    ];
}

Update

As for the sometimes rule, I'd suggest creating a Rule object and customizing how you need to check for 2 vills having the same name.

Rule classes

Upvotes: 0

Robert
Robert

Reputation: 5973

You can check out the FormRequest class in vendor/laravel/framework/src/Illuminate/Foundation/Http/FormRequest.php and check what it does.

It contains these 2 method at the top:

/**
 * Get the validator instance for the request.
 *
 * @return \Illuminate\Contracts\Validation\Validator
 */
protected function getValidatorInstance()
{
    $factory = $this->container->make(ValidationFactory::class);

    if (method_exists($this, 'validator')) {
        $validator = $this->container->call([$this, 'validator'], compact('factory'));
    } else {
        $validator = $this->createDefaultValidator($factory);
    }

    if (method_exists($this, 'withValidator')) {
        $this->withValidator($validator);
    }

    return $validator;
}

/**
 * Create the default validator instance.
 *
 * @param  \Illuminate\Contracts\Validation\Factory  $factory
 * @return \Illuminate\Contracts\Validation\Validator
 */
protected function createDefaultValidator(ValidationFactory $factory)
{
    return $factory->make(
        $this->validationData(), $this->container->call([$this, 'rules']),
        $this->messages(), $this->attributes()
    );
}

So you can basically provide a validator method in your own FormRequest class to create a custom Validator object, that method will get the ValidatorFactory as param.

In your case you would not need to do this, because you just want to append the sometimes rule to a default validator. Looking at the code above, it checks for the existence of the withValidator method, if it exists, it is called:

    if (method_exists($this, 'withValidator')) {
        $this->withValidator($validator);
    }

You could create the FormRequest, make sure the rules, messages and authorize methods are properly used, e.g. rules and messages return arrays and authorize returns a bool.

Then create a withValidator method in which you attach the sometimes rule to the Validator.

/**
 * Do foo with Validator
 *
 * @param \Illuminate\Contracts\Validation\Validator $validator
 * @return void
 */
public function withValidator(Validator $validator)
{
    $validator->sometimes('depart_id', 'required|exists:departs,id', function {
        return Ville::where('nom', $this->input('ville'))->count() > 1;
    });
}

This way sometimes is attached to your validator before the validation is performed.

Upvotes: 1

Related Questions