randm's avatar

Array validation is not working. Am I doing something wrong or is this a bug in the framework?

I am trying to use the array validation feature in Laravel 5.2 but finding an issue. I am not sure if it is something I am doing incorrectly or it is a bug. But when I submit the form, it passes the validation when I un-select all the options even though I am using "required" rules.

'control_300.*' => ['required','dynamic_pick_item'];

The following are outputs and steps I do to run into the issue

Here is how I generate rules on the fly and call the validator

//Generate the rules, messages to validate with
$formRules = new FormRules($this->questions, $this->input);
//Validate the form
$validate = Validator::make( $this->input, $formRules->getRules(), $formRules->getMessages() );

Here is an output of dd($this->input)

   array:9 [▼
     "_token" => "bIUi3U2PGds3uLeqTWQDllse0WTz8gdCJB47nFhb"
     "survey_id" => "10"
     "call_id" => "100"
     "direction" => "next"
     "optionals" => ""
     "terminated" => "No"
     "control_317" => array:1 [▼
          0 => ""
     ]
     "control_318" => array:1 [▼
          0 => ""
     ]
     "control_319" => array:1 [▼
          0 => ""
     ]
   ]

Here is a an output of dd( $formRules->getRules() )

array:1 [▼
     "control_300.*" => array:2 [▼
          0 => "required"
          1 => "dynamic_pick_item"
     ]
   ]

Here is an output of dd( $formRules->getMessages() )

   array:1 [▼
       "control_300.dynamic_pick_item" => "Invalid Item was selected"
     ]

Here is an output of dd( $validate )

Here is how I define my "dynamic_pick_item" rule

    Validator::extend('dynamic_pick_item', function($attribute, $value, $parameters, $validator) {

        $optionValue = explode(':', $value);

        if( ! $this->isValidKey($optionValue) ){
            return false;
        }

        return true;
    });

   protected function isValidKey(array $key)
   {
       return ( (count($key) == 2) && is_numeric($key[0] ) && is_numeric($key[1]) && $key[0] > 0 && $key[1] > 0) ? true : false;
   }

Here is my entire form if needed

<form method="POST" action="https://app.app/survey/store" accept-charset="UTF-8" class="form" id="survey_form">
 <input name="_token" type="hidden" value="bIUi3U2PGds3uLeqTWQDllse0WTz8gdCJB47nFhb">
 <input name="survey_id" type="hidden" value="10">
 <input name="call_id" type="hidden" value="100">
 <input id="survey-nav-direction" name="direction" type="hidden" value="next">
 <input id="survey-optional-controls" name="optionals" type="hidden" value="">
 <input id="survey-is-terminated" name="terminated" type="hidden" value="">
 <div class="questionPanel panel panel-default " id="question_50">
    <div class="panel-heading">4) Please tell me what stores are located conveniently enough to do most of your grocery shopping if you wished.  (PROBE:)  What others?</div>
    <div class="panel-body">
       <fieldset class="survey-control-fieldset" id="wrapper_300">
          <div class="survey-control-title">
          </div>
          <div class="checkbox">
             <label for="item_300_23_0">
             <input type="checkbox" name="control_300[0][]" id="item_300_23_0" value="300:23"  > Whole Foods
             </label>
          </div>
          <div class="checkbox">
             <label for="item_300_22_0">
             <input type="checkbox" name="control_300[0][]" id="item_300_22_0" value="300:22"  > Wegmans
             </label>
          </div>
          <div class="checkbox">
             <label for="item_300_19_0">
             <input type="checkbox" name="control_300[0][]" id="item_300_19_0" value="300:19"  > Walgreens
             </label>
          </div>
          <div class="checkbox">
             <label for="item_300_21_0">
             <input type="checkbox" name="control_300[0][]" id="item_300_21_0" value="300:21"  > Wal-Mart Supercenter
             </label>
          </div>
          <div class="checkbox">
             <label for="item_300_20_0">
             <input type="checkbox" name="control_300[0][]" id="item_300_20_0" value="300:20"  > Wal-Mart
             </label>
          </div>
          <div class="checkbox">
             <label for="item_300_18_0">
             <input type="checkbox" name="control_300[0][]" id="item_300_18_0" value="300:18"  > Trader Joes
             </label>
          </div>
          <div class="checkbox">
             <label for="item_300_17_0">
             <input type="checkbox" name="control_300[0][]" id="item_300_17_0" value="300:17"  > Target
             </label>
          </div>
          <div class="checkbox">
             <label for="item_300_16_0">
             <input type="checkbox" name="control_300[0][]" id="item_300_16_0" value="300:16"  > Super Target
             </label>
          </div>
          <div class="checkbox">
             <label for="item_300_1_0">
             <input type="checkbox" name="control_300[0][]" id="item_300_1_0" value="300:1"  > STOP & SHOP
             </label>
          </div>
          <div class="checkbox">
             <label for="item_300_15_0">
             <input type="checkbox" name="control_300[0][]" id="item_300_15_0" value="300:15"  > Star Market
             </label>
          </div>
          <div class="checkbox">
             <label for="item_300_1022_0">
             <input type="checkbox" name="control_300[0][]" id="item_300_1022_0" value="301:1022"  > Other 1
             </label>
             <div class="control_300 hiddenGroup " id="group_301_1022" >
                <div class="form-group ">
                   <label for="control_317_0">Specify Other Store Name</label>
                   <input type="text" name="control_317[0]" id="control_317_0" 
                      value=""
                      placeholder="" class="form-control">
                </div>
             </div>
          </div>
          <div class="checkbox">
             <label for="item_300_1023_0">
             <input type="checkbox" name="control_300[0][]" id="item_300_1023_0" value="301:1023"  > Other 2
             </label>
             <div class="control_300 hiddenGroup " id="group_301_1023" >
                <div class="form-group ">
                   <label for="control_318_0">Specify Other Store Name</label>
                   <input type="text" name="control_318[0]" id="control_318_0" 
                      value=""
                      placeholder="" class="form-control">
                </div>
             </div>
          </div>
          <div class="checkbox">
             <label for="item_300_1024_0">
             <input type="checkbox" name="control_300[0][]" id="item_300_1024_0" value="301:1024"  > Other 3
             </label>
             <div class="control_300 hiddenGroup " id="group_301_1024" >
                <div class="form-group ">
                   <label for="control_319_0">Specify Other Store Name</label>
                   <input type="text" name="control_319[0]" id="control_319_0" 
                      value=""
                      placeholder="" class="form-control">
                </div>
             </div>
          </div>
          <div class="checkbox">
             <label for="item_300_1000_0">
             <input type="checkbox" name="control_300[0][]" id="item_300_1000_0" value="301:1000"  > None
             </label>
          </div>
          <div class="checkbox">
             <label for="item_300_1001_0">
             <input type="checkbox" name="control_300[0][]" id="item_300_1001_0" value="301:1001"  > Don't Know/No Answer
             </label>
          </div>
          <div class="checkbox">
             <label for="item_300_1002_0">
             <input type="checkbox" name="control_300[0][]" id="item_300_1002_0" value="301:1002"  data-terminator="Yes"> Refused
             </label>
          </div>
       </fieldset>
    </div>
 </div>
 <div class="row" id="survey-navegation-bar">
    <div class="col-md-4 text-left">
    </div>
    <div class="col-md-4 text-center">
    </div>
    <div class="col-md-4 text-right">
       <input class="btn btn-primary survey-navigator" type="submit" value="Next Page >>">
    </div>
 </div>
</form>
</div>
0 likes
5 replies
randm's avatar

I am still not sure if this is a bug or a design. One workaround I found in to change the validation rules to something like this

'control_300' => ['required'];   //make the control required
'control_300.*' => ['dynamic_pick_item'];  //use this custom rule to check each selected option
jonmolnar's avatar

@malhayek - Yes. I could be wrong, but it looks like you're trying to validate the array elements of control_300, but it looks like $this->input isn't even getting the control_300 array, so my guess is Laravel doesn't know where to find the elements because the array doesn't exist.

Which is why

'control_300' => ['required'];

is the appropriate rule.

randm's avatar

@jonmolnar I would think Laravel should handle that for you since you are saying control_300.*

But thanks for your feedback

suguna's avatar

I think you might use control_300 [0], control_300 [1], so on for doing array validation.

randm's avatar

Actually by design the item in the array and the array name are validated separately.

So the correct way to validate would be this

'control_300' => ['required'];   //make the control required
'control_300.*' => ['dynamic_pick_item'];  //use this custom rule to check each selected option

so "required" will be applied on $_POST['control_300']

and the rule dynamic_pick_item will be applied on each item in that control_300 array.

Laravel will do something like this

foreach( $_POST['control_300'] as $index => $value){

//apply the rule here }

1 like

Please or to participate in this conversation.