Search code examples
phplaravelvalidationlaravel-8laravel-validation

Laravel Array:Key Validation


My Laravel Backend receives a JSON converted Javascript Array and decodes it into the following php array:

dd($cart) EDITED Keys Changed

array:4 [▼
  "personcount" => 2
  "person1" => array:2 [▼
     "Customer" => array:2 [▶]
      "Items" => array:5 [▼
        "key1" => 0
        "key2" => 0
        "key3" => 0
        "key4" => 0
        "key5" => 1
      ]
       
  ]
  "person2" => array:2 [▼
     "Customer" => array:2 [▶]
     "Items" => array:5 [▶]
  ]
]

I created a Filter Middleware which should validate the given array and redirect back in case of failure.

Filter.php EDITED added new (not working) validation rule approach

$cart = json_decode($request->input('cart'), true);

$validation_rules = [];

$TotalItemCount = 0;

for ($i = 1; $i <= $person_count; $i++) {

    foreach ($cart[$i]["Items"] as $Item => $ItemCount) {
        $TotalItemCount += $ItemCount;
    }

    $validation_rules += [
        "person$i.Customer.FirstName" => "required|string|min:2|max:255",
        "person$i.Customer.LastName" => "required|string|min:2|max:255",
        "person$i.Items.*" => "required|numeric",
        "person$i.Items" => ['required', 'array',
                    Rule::in(["Key1", "Items"]),
                ],
    ];
}
$validated_input = Validator::make($cart, $validation_rules);

It seems like the validator is ignoring the $i.Items validation rules. I even changed size:5 to size:6 which had to fire an error 100% because the given Item Array always contains only 5 elements.

Furthermore I tried to Validate array keys:

"$i.Items" => "required|array:key1,key2,key3"

It also didn't fire at all. I want all keys to be required. The firstName/Lastname rules apply.

I'm happy for suggestions.


Solution

  • Doing a lot of research and trying hard I found the solution:

    For everybody searching desperately for an example of advanced array validation in Laravel 8+:

    1. Step: ALWAYS use an array, not an object. For that purpose:
    public function fCreateArrayFromObject($Object) {
                $toArray = function ($x) use (&$toArray) {
                    return is_scalar($x)
                        ? $x
                        : array_map($toArray, (array)$x);
                };
       
    return $toArray($Object);
    }
    
    1. Step: I will use my example to show you how its easily done:

    My array ($cart):

    array:3 [▼
      "user1" => array:2 [▼
        "Items" => array:5 [▼
          "blue" => 0
          "grey" => 1
          "brown" => 1
          "look" => 0
          "black" => 0
        ]
        "User" => array:2 [▼
          "LastName" => "alice"
          "FirstName" => "Bobby"
        ]
      ]
      "user2" => ......
    ]
    

    My rules:

    $person_count = 2; // Up to 5
    
    $validation_rules = [];
            
            for ($i = 1; $i <= $person_count; $i++) {
    
                $validation_rules += [
                    "user$i" => "array:Items,Customer|size:2|distinct",
                    "user$i.user.FirstName" => "required|string|min:2|max:255",
                    "user$i.user.LastName" => "required|string|min:2|max:255",
                    "user$i.Items.*" => "required|numeric|min:0",
                    "user$i.Items" => "required|array:blue,grey,brown,look,black|size:5|distinct",
              
                ];
            }
    

    Action:

    $validated_input = Validator::make((array)$cart, $validation_rules);
    

    I am not quite sure, why the make method doesn't interpret my $cart array without the (array) as an array, but it works. Goals:

    • validate the whole cart: has to contain each person as an array with exactly 2 elements (up to five person arrays) works
    • validate each person itself: has to contain the user and items array works
    • validate the user array: has to contain the first and last name between 2 and 255 characters each as strings works
    • validate the Items array: has to be exactly of size:5, has to contain all the given keys works
    • validate the key values of the Items array: they have to be numeric and at least 0 works

    Obviously everything has to be existent as well: "required"

    Tags: Laravel Array Validation, Laravel Nested Array Validation