Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Validation of array form fields in laravel 4 error

How can we validate form fields that are arrays? Take a look at the following code

UserPhone Model:

 public static $rules= array(
    'phonenumber'=>'required|numeric',
    'isPrimary'=>'in:0,1'
)
...........

UserController:

$validation = UserPhone::validate(Input::only('phonenumber')));


    if($validation->passes())
      {
         $allInputs = Input::only('phonenumber','tid');
         $loopSize = sizeOf($allInputs);

         for($i=0;$i<$loopSize;$i++)
         {

         $phone = UserPhone::find($allInputs['tid'][$i]);
         $phone->phonenumber = $allInputs['phonenumber'][$i];
         $phone->save();

        }

     return Redirect::to('myprofile')->with('message','Update OK');

  }
  else
  {
     return Redirect::to('editPhone')->withErrors($validation);

  } 

}

the $validation comes from a BaseModel which extends Eloquent.

In my view:

 <?php $counter=1; ?>
          @foreach($phones as $thephone)

           <section class="col col-12">
              <label class="label">Phone Number {{$counter++}}</label>
              <label class="input">
              <i class="icon-append icon-phone"></i>
                 {{Form::text('phonenumber[]',$thephone->phonenumber)}}
                 {{Form::hidden('tid[]',$thephone->id)}}
              </label>
            </section>
          @endforeach

Everything is working fine and I get all the phone numbers I want in the Update Form, but I cannot update the model because the validation fails with the message "Phonenumber must be a number".

I know that there is not a simple solution for validating array form fields and I tried to extend the validator class but with no success.

How can I validate this kind of fields?

like image 629
Archimidis M Avatar asked Aug 10 '13 12:08

Archimidis M


People also ask

How do I validate an array in Laravel?

you can call validate() method directly on Request object like so: $data = $request->validate([ "name" => "required|array|min:3", "name. *" => "required|string|distinct|min:3", ]);

How show all errors in Laravel?

You can call any() method on $errors variable to check that there are any validation errors exist in it or not. It returns 1 if any errors exist in $errors variable. After that you can call foreach method on $errors->all() and display message using $error variable.


1 Answers

Here's the solution I use:

Usage

Simply transform your usual rules by prefixing each. For example:

'names' => 'required|array|each:exists,users,name'

Note that the each rule assumes your field is an array, so don't forget to use the array rule before as shown here.

Error Messages

Error messages will be automatically calculated by the singular form (using Laravel's str_singular() helper) of your field. In the previous example, the attribute is name.

Nested Arrays

This method works out of the box with nested arrays of any depth in dot notation. For example, this works:

'members.names' => 'required|array|each:exists,users,name'

Again, the attribute used for error messages here will be name.

Custom Rules

This method supports any of your custom rules out of the box.

Implementation

1. Extend the validator class

class ExtendedValidator extends Illuminate\Validation\Validator {

    public function validateEach($attribute, $value, $parameters)
    {
        // Transform the each rule
        // For example, `each:exists,users,name` becomes `exists:users,name`
        $ruleName = array_shift($parameters);
        $rule = $ruleName.(count($parameters) > 0 ? ':'.implode(',', $parameters) : '');

        foreach ($value as $arrayKey => $arrayValue)
        {
            $this->validate($attribute.'.'.$arrayKey, $rule);
        }

        // Always return true, since the errors occur for individual elements.
        return true;
    }

    protected function getAttribute($attribute)
    {
        // Get the second to last segment in singular form for arrays.
        // For example, `group.names.0` becomes `name`.
        if (str_contains($attribute, '.'))
        {
            $segments = explode('.', $attribute);

            $attribute = str_singular($segments[count($segments) - 2]);
        }

        return parent::getAttribute($attribute);
    }
}

2. Register your validator extension

Anywhere in your usual bootstrap locations, add the following code:

Validator::resolver(function($translator, $data, $rules, $messages)
{
    return new ExtendedValidator($translator, $data, $rules, $messages);
});

And that's it! Enjoy!

Bonus: Size rules with arrays

As a comment pointed out, there's seems to be no easy way to validate array sizes. However, the Laravel documentation is lacking for size rules: it doesn't mention that it can count array elements. This means you're actually allowed to use size, min, max and between rules to count array elements.

like image 178
Lazlo Avatar answered Sep 24 '22 22:09

Lazlo