Reputation: 8661
I wonder if it's possible to validate an array of objects in Laravel? I have built a form looking like an Excel page using Vue, so the user can edit many rows, which gets uploaded later.
The data that I wish to validate when making a POST request to my controller looks like this:
[
// 0
{
title: "my title",
post: "my post text",
},
// 1
{
title: "my title",
post: "my post text",
},
// 2
{
title: "my title",
post: "my post text",
},
];
So how can I, for example, add a required
rule to each input?
Upvotes: 27
Views: 46000
Reputation: 868
$validator = Validator::make($request->all(), [
'*.title' => 'required',
'*.post' => 'required',
]);
Upvotes: 2
Reputation: 804
Laravel validations works fine if the elements of the array are associative arrays, but if they are objects it will fail, and sometimes you want to keep your data as objects for further manipulations.
I created the following custom rule
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
use Illuminate\Support\Facades\Validator;
/**
* Valida in arreglo de objetos
*
* Si bien Laravel puede validar arrays, solo funciona
* si sus elementos son arreglos asociativos, cuando son
* objetos la regla no se aplica
*/
class ArrayOfObjects implements Rule
{
/**
* Reglas de validacion
*/
private array $rules;
/**
* Mensaje de error
*/
private string $error;
/**
* Create a new rule instance.
*
* @return void
*/
public function __construct(array $rules)
{
$this->rules = $rules;
}
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
foreach ($this->rules as $property => $property_rules)
{
$rules = [$property => $property_rules];
if (isset($value->{$property}))
{
$data = [$property => $value->{$property}];
$validator = Validator::make($data, $rules);
if ($validator->fails())
{
$this->error = $validator->errors()->first($property);
// Detener el loop si hay un error
return false;
}
}
else
{
if (in_array('required', $property_rules))
{
$this->error = __('validation.required', ['attribute' => $property]);
return false;
}
}
}
return true;
}
/**
* Get the validation error message.
*
* @return string
*/
public function message()
{
return $this->error;
}
}
Its ussage in a controller for example
public function store (Request $request)
{
$object_rules = [
'attr_1' => ['required', 'string'],
'attr_2' => ['required', 'numeric']
];
$request->validate([
'array.*' => new ArrayOfObjects($object_rules)
]);
}
Upvotes: 2
Reputation: 1040
The approved answer works if your posting an array, however to take it a step further, I am needing to save multiple arrays. While that approach would work if I make two separate endpoints, what if I want to save everything inside one DB::transaction
?
Viola:
// POST:
{
"array1": [
{ "key1": "string", "key2": 1 },
{ "key1": "string", "key2": 0 }
],
"array2": [
{ "key3": "string", "key4": 1 },
{ "key3": "string", "key4": 0 }
]
}
// SERVER:
$this->validate($request, [
'array1' => 'present|array',
'array2' => 'present|array',
'array1.*.key1' => 'required|string',
'array1.*.key2' => 'required|integer',
'array2.*.key3' => 'required|string',
'array2.*.key4' => 'required|integer'
]);
DB::transaction(function() use($request) {
foreach($request['array1'] as $x){
// ...do stuff here
};
});
Note: 'present|array'
accepts empty arrays whereas 'required|array'
would reject them.
Upvotes: 17
Reputation: 807
You can use array validation of Laravel.
eg.
$validator = Validator::make($request->all(), [
'row.*.title' => 'required',
'row.*.post' => 'required',
]);
You can find more about Laravel array validation here
Upvotes: 45