I would like to validate the following json in CI4:
{
"field1": "some value",
"array1": {
"2876": "4358",
"9904": "17"
}
}
Array 1 can reasonably contain up to 50 key value pairs.
I have validation rules for both the keys and values in array1, for the purposes of this question lets require them both to be numeric.
The code I have so far is:
$validation = \Config\Services::validation();
$validation->setRules([
'field1' => 'required|max_length[20]',
'array1.*' => 'required|numeric',
]);
if (! $validation->withRequest($this->request)->run()) {
return $this->failValidationErrors($validation->getErrors());
}
Alternatively based on an answer I've seen elsewhere:
$validation = \Config\Services::validation();
$validation->setRules([
'field1' => 'required|max_length[20]'
]);
$to_validate = $this->request->getPost();
foreach ($to_validate['array1'] as $key => $value) {
$validation->setRule('array1.' . $key , null, 'required|numeric');
}
if (! $validation->withRequest($this->request)->run()) {
return $this->failValidationErrors($validation->getErrors());
}
This code successfully rejects a value of "abcd" but how do I reject a string key?
I could pre-process by putting the keys into their own array which can be validated with an array2.* rule but this seems like a simple use case which should work out of the box.
Also how should I implement the array size limit check?
I would like to validate the following json in CI4:
{
"field1": "some value",
"array1": {
"2876": "4358",
"9904": "17"
}
}
Array 1 can reasonably contain up to 50 key value pairs.
I have validation rules for both the keys and values in array1, for the purposes of this question lets require them both to be numeric.
The code I have so far is:
$validation = \Config\Services::validation();
$validation->setRules([
'field1' => 'required|max_length[20]',
'array1.*' => 'required|numeric',
]);
if (! $validation->withRequest($this->request)->run()) {
return $this->failValidationErrors($validation->getErrors());
}
Alternatively based on an answer I've seen elsewhere:
$validation = \Config\Services::validation();
$validation->setRules([
'field1' => 'required|max_length[20]'
]);
$to_validate = $this->request->getPost();
foreach ($to_validate['array1'] as $key => $value) {
$validation->setRule('array1.' . $key , null, 'required|numeric');
}
if (! $validation->withRequest($this->request)->run()) {
return $this->failValidationErrors($validation->getErrors());
}
This code successfully rejects a value of "abcd" but how do I reject a string key?
I could pre-process by putting the keys into their own array which can be validated with an array2.* rule but this seems like a simple use case which should work out of the box.
Also how should I implement the array size limit check?
Share Improve this question asked 10 hours ago ChrisGChrisG 739 bronze badges2 Answers
Reset to default 0array1.*
validates the values of array1 and indeed not the keys.
The idea you had to provide the keys upfront is not bad at all, as it would turn the keys into values and you then would be able to validate them with the standard rules:
$to_validate = $this->request->getPost();
$to_validate['array1_keys'] = array_keys($to_validate['array1'] ?? []);
...
Then it is possible to use array1_keys.*
next to array1.*
.
I would start with that as you can find out how far you get with the standard rules.
Furthermore if you would like to dig deeper towards custom rules, I'd suggest to look into rules for file uploads as they refer to array fields. Their implementation (read the source code of them) should show how you can access array data including keys (IIRC). You can then experiment creating your own rules.
This works:
$validation = \Config\Services::validation();
$validation->setRules([
'field1' => 'required|max_length[20]',
'array1' => 'required',
'array1.*' => 'required|numeric',
'array1_keys.*' => 'required|numeric',
'array1_count' => 'required|numeric|greater_than_equal_to[1]|less_than_equal_to[50]'
]);
$to_validate = $this->request->getPost();
$to_validate["array1_keys"] = array_keys($to_validate['array1'] ?? []);
$to_validate["array1_count"] = count($to_validate["array1_keys"]);
if (! $validation->run($to_validate)) {
return $this->failValidationErrors($validation->getErrors());
}
That said it is hardly elegant so I will happily upvote a more concise alternative.