197

I try to validate array POST in Laravel:

$validator = Validator::make($request->all(), [
    "name.*" => 'required|distinct|min:3',
    "amount.*" => 'required|integer|min:1',
    "description.*" => "required|string"
             
]);

I send empty POST and get this if ($validator->fails()) {} as False. It means that validation is true, but it is not.

How to validate array in Laravel? When I submit a form with input name="name[]"

Christos Lytras
  • 36,310
  • 4
  • 80
  • 113
Darama
  • 3,130
  • 7
  • 25
  • 34

7 Answers7

443

Asterisk symbol (*) is used to check values in the array, not the array itself.

$validator = Validator::make($request->all(), [
    "names"    => "required|array|min:3",
    "names.*"  => "required|string|distinct|min:3",
]);

In the example above:

  • "names" must be an array with at least 3 elements,
  • values in the "names" array must be distinct (unique) strings, at least 3 characters long.

EDIT: Since Laravel 5.5 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",
]);
Filip Sobol
  • 5,198
  • 3
  • 13
  • 24
  • 1
    remember to place it in a try catch if you are using `$request->validate([...])`. An exception will be raised if the data is fails the validation. – daisura99 Oct 03 '18 at 16:15
  • how to get the error message of a specific field? like I have 2 fields of name, and then it's the second field that has only the error, how can I attain it? – Eem Jee Oct 17 '19 at 10:37
  • 2
    the required on the 'name.*' isn't needed as it only validates it if it exists – Ben Gooding Sep 08 '20 at 14:24
  • 1
    This is brilliant. I wonder why there are no examples of this in the [official documentation of array validation](https://laravel.com/docs/8.x/validation#validating-arrays). – Binar Web Nov 27 '20 at 09:10
  • How to display msg then for example $validator = Validator::make($request->all(), [ "names" => "required|array|min:3", "names.*" => "required|string|distinct|min:3", ],[ name.required=>"You left this name" ]); IS it correct ? If it is then its not working for me – Mohammad Fahad Rao Jul 19 '21 at 12:04
  • This is not useful solution. I have 2 name elements as array when I submit the form after applying given solution, error message is showing like 'The name.1 field is required.', 'The name.2 field is required.'. Is this user friendly message?? – Kamlesh Nov 15 '22 at 10:59
84

I have this array as my request data from a HTML+Vue.js data grid/table:

[0] => Array
    (
        [item_id] => 1
        [item_no] => 3123
        [size] => 3e
    )
[1] => Array
    (
        [item_id] => 2
        [item_no] => 7688
        [size] => 5b
    )

And use this to validate which works properly:

$this->validate($request, [
    '*.item_id' => 'required|integer',
    '*.item_no' => 'required|integer',
    '*.size'    => 'required|max:191',
]);
Nisal Gunawardana
  • 1,345
  • 16
  • 20
  • Nice answer but I have arrays like so and my forms has radio buttons with the same name, when I submit I get back validation errors because of radio buttons sharing names. – Theodory Apr 03 '21 at 10:55
36

The recommended way to write validation and authorization logic is to put that logic in separate request classes. This way your controller code will remain clean.

You can create a request class by executing php artisan make:request SomeRequest.

In each request class's rules() method define your validation rules:

//SomeRequest.php
public function rules()
{
   return [
    "name"    => [
          'required',
          'array', // input must be an array
          'min:3'  // there must be three members in the array
    ],
    "name.*"  => [
          'required',
          'string',   // input must be of type string
          'distinct', // members of the array must be unique
          'min:3'     // each string must have min 3 chars
    ]
  ];
}

In your controller write your route function like this:

// SomeController.php
public function store(SomeRequest $request) 
{
  // Request is already validated before reaching this point.
  // Your controller logic goes here.
}

public function update(SomeRequest $request)
{
  // It isn't uncommon for the same validation to be required
  // in multiple places in the same controller. A request class
  // can be beneficial in this way.
}

Each request class comes with pre- and post-validation hooks/methods which can be customized based on business logic and special cases in order to modify the normal behavior of request class.

You may create parent request classes for similar types of requests (e.g. web and api) requests and then encapsulate some common request logic in these parent classes.

joelvh
  • 16,700
  • 4
  • 28
  • 20
Sumit Kumar
  • 1,855
  • 19
  • 19
25

Little bit more complex data, mix of @Laran's and @Nisal Gunawardana's answers

[ 
   {  
       "foodItemsList":[
    {
       "id":7,
       "price":240,
       "quantity":1
                },
               { 
                "id":8,
                "quantity":1
               }],
        "price":340,
        "customer_id":1
   },
   {   
      "foodItemsList":[
    {
       "id":7,
       "quantity":1
    },
    { 
        "id":8,
        "quantity":1
    }],
    "customer_id":2
   }
]

The validation rule will be

 return [
            '*.customer_id' => 'required|numeric|exists:customers,id',
            '*.foodItemsList.*.id' => 'required|exists:food_items,id',
            '*.foodItemsList.*.quantity' => 'required|numeric',
        ];
Halfacht
  • 924
  • 1
  • 12
  • 22
Prafulla Kumar Sahu
  • 9,321
  • 11
  • 68
  • 105
3

You have to loop over the input array and add rules for each input as described here: Loop Over Rules

Here is a some code for ya:

$input = Request::all();
$rules = [];

foreach($input['name'] as $key => $val)
{
    $rules['name.'.$key] = 'required|distinct|min:3';
}

$rules['amount'] = 'required|integer|min:1';
$rules['description'] = 'required|string';

$validator = Validator::make($input, $rules);

//Now check validation:
if ($validator->fails()) 
{ 
  /* do something */ 
}
Chad Fisher
  • 353
  • 4
  • 16
1

The below code working for me on array coming from ajax call .

  $form = $request->input('form');
  $rules = array(
            'facebook_account' => 'url',
            'youtube_account' => 'url',
            'twitter_account' => 'url',
            'instagram_account' => 'url',
            'snapchat_account' => 'url',
            'website' => 'url',
        );
        $validation = Validator::make($form, $rules);

        if ($validation->fails()) {
            return Response::make(['error' => $validation->errors()], 400);
        }
Abd Abughazaleh
  • 4,615
  • 3
  • 44
  • 53
0

In my Case it works fine

$validator = Validator::make($request->all(), [
    "names" => "required|array|min:3",
    "*.names"=> "required|string|distinct|min:3",
]);