required_if validation rule with array values.

Published 6 months ago by ravasaurio

I have a form for my admin to create new users. This is where the data is validated:

public function rules()
    {
      return [
            'first_name'     => 'required|max:191',
            'last_name'  => 'required|max:191',
            'email'    => ['required', 'email', 'max:191', Rule::unique('users')],
            'timezone' => 'required|max:191',
            'password' => 'required|min:6|confirmed',
            'roles' => 'required|array',
        ];
    }

In my form, there are some switches you may turn on/off to select the roles you want to assign the new user. roleswill be an array containing the role names you have selected. This is how the array looks like on the logs with more than one role selected:

array ( 

0 => 'administrator',
1 => 'executive',
2 => 'user',
)

What I need is to have some extra fields required, only if the user role was selected:

public function rules()
    {
      return [
            'first_name'     => 'required|max:191',
            'last_name'  => 'required|max:191',
            'email'    => ['required', 'email', 'max:191', Rule::unique('users')],
            'timezone' => 'required|max:191',
            'password' => 'required|min:6|confirmed',
            'roles' => 'required|array',
        'extra_field_1' => 'required_if:',//<--'user' role was selected? then this field will be required
        ];
    }

I have tried something like this:

'extra_field_1' => 'nullable|required_if:roles,User',

'extra_field_1' => 'required_if:roles,==,User',

'extra_field_1' => 'nullable|required_if:roles,user',

'extra_field_1' => 'required_if:roles,==,user',

Testing those, I selected the 'user' role and then left the extra fields empty to see if the validation fails and it doesn`t. Instead I get an SQLexception from trying to insert null data on not null columns (When I send the form, if the users role was selected the value of those extra fields will be inserted on a table which is different from the users table). If I am not mixing concepts, if validation fails the function that stores the user and gets me the SQLexception should not be executed right?

How can I get that required_if working? Thanks.

Best Answer (As Selected By ravasaurio)
ravasaurio

Hello, I found a way to do it and I will post it here in case someone finds it helpful.

I changed this:

public function rules()
    {
      return [
            'first_name'     => 'required|max:191',
            'last_name'  => 'required|max:191',
            'email'    => ['required', 'email', 'max:191', Rule::unique('users')],
            'timezone' => 'required|max:191',
            'password' => 'required|min:6|confirmed',
            'roles' => 'required|array',
        ];
    }

To this:

public function rules()
    {
      $rules = [
        'first_name'    => 'required|max:191',
        'last_name'     => 'required|max:191',
        'email'         => ['required', 'email', 'max:191', Rule::unique('users')],
        'timezone'      => 'required|max:191',
        'password'    => 'required|min:6|confirmed',
        'roles'         => 'required|array',
      ];

      if(isset(request()->roles))
      {
        if(in_array('commerce',request()->roles))
        {
          $additionalRules = [
            'extra_field_1' =>  'required|alpha',
            'extra_field_2' =>  'required|numeric',
            //etc
          ];
          $rules = $rules+$additionalRules;
        }
      }

      \Log::debug($rules);
      return $rules;
    }

So instead of directly returning the set of rules, I store them on the rulesvariable. Then I check if the rolesarray is present and if it is there, I look for the userstring inside. If userrole was selected, then I create an additional set of rules and combine it with the original one.

This is how ruleslooks like on the logs:

Without userrole selected:

'first_name' => 'required|max:191',
'last_name' => 'required|max:191',
'email' => 
array (
0 => 'required',
1 => 'email',
2 => 'max:191',
3 => 
Illuminate\Validation\Rules\Unique::__set_state(array(
'ignore' => NULL,
'idColumn' => 'id',
'table' => 'users',
'column' => 'NULL',
'wheres' => 
array (
),
'using' => 
array (
),
)),
),
'timezone' => 'required|max:191',
'password'    => 'required|min:6|confirmed',
'roles' => 'required|array',
)

With userrole selected:

'first_name' => 'required|max:191',
'last_name' => 'required|max:191',
'email' => 
array (
0 => 'required',
1 => 'email',
2 => 'max:191',
3 => 
Illuminate\Validation\Rules\Unique::__set_state(array(
'ignore' => NULL,
'idColumn' => 'id',
'table' => 'users',
'column' => 'NULL',
'wheres' => 
array (
),
'using' => 
array (
),
)),
),
'timezone' => 'required|max:191',
'password'    => 'required|min:6|confirmed',
'roles' => 'required|array',
'extra_field_1' =>  'required|alpha',
'extra_field_2' =>  'required|numeric',
)

That way those extra fields are only required when userrole is selected.

Dry7
Dry7
6 months ago (152,030 XP)

@ravasaurio I think it's impossible through this validation rule. try to create your own validation rule https://laravel.com/docs/5.5/validation#custom-validation-rules

ravasaurio

Hello, I found a way to do it and I will post it here in case someone finds it helpful.

I changed this:

public function rules()
    {
      return [
            'first_name'     => 'required|max:191',
            'last_name'  => 'required|max:191',
            'email'    => ['required', 'email', 'max:191', Rule::unique('users')],
            'timezone' => 'required|max:191',
            'password' => 'required|min:6|confirmed',
            'roles' => 'required|array',
        ];
    }

To this:

public function rules()
    {
      $rules = [
        'first_name'    => 'required|max:191',
        'last_name'     => 'required|max:191',
        'email'         => ['required', 'email', 'max:191', Rule::unique('users')],
        'timezone'      => 'required|max:191',
        'password'    => 'required|min:6|confirmed',
        'roles'         => 'required|array',
      ];

      if(isset(request()->roles))
      {
        if(in_array('commerce',request()->roles))
        {
          $additionalRules = [
            'extra_field_1' =>  'required|alpha',
            'extra_field_2' =>  'required|numeric',
            //etc
          ];
          $rules = $rules+$additionalRules;
        }
      }

      \Log::debug($rules);
      return $rules;
    }

So instead of directly returning the set of rules, I store them on the rulesvariable. Then I check if the rolesarray is present and if it is there, I look for the userstring inside. If userrole was selected, then I create an additional set of rules and combine it with the original one.

This is how ruleslooks like on the logs:

Without userrole selected:

'first_name' => 'required|max:191',
'last_name' => 'required|max:191',
'email' => 
array (
0 => 'required',
1 => 'email',
2 => 'max:191',
3 => 
Illuminate\Validation\Rules\Unique::__set_state(array(
'ignore' => NULL,
'idColumn' => 'id',
'table' => 'users',
'column' => 'NULL',
'wheres' => 
array (
),
'using' => 
array (
),
)),
),
'timezone' => 'required|max:191',
'password'    => 'required|min:6|confirmed',
'roles' => 'required|array',
)

With userrole selected:

'first_name' => 'required|max:191',
'last_name' => 'required|max:191',
'email' => 
array (
0 => 'required',
1 => 'email',
2 => 'max:191',
3 => 
Illuminate\Validation\Rules\Unique::__set_state(array(
'ignore' => NULL,
'idColumn' => 'id',
'table' => 'users',
'column' => 'NULL',
'wheres' => 
array (
),
'using' => 
array (
),
)),
),
'timezone' => 'required|max:191',
'password'    => 'required|min:6|confirmed',
'roles' => 'required|array',
'extra_field_1' =>  'required|alpha',
'extra_field_2' =>  'required|numeric',
)

That way those extra fields are only required when userrole is selected.

Please sign in or create an account to participate in this conversation.