Closed dimuska139 closed 2 years ago
This should work, as it is expressed on this test:
https://github.com/Respect/Validation/blob/master/tests/integration/get_messages.phpt
The ::create()
calls here should not interfere, but it might be a bug. Can you check for me if putting them fixes the problem?
@alganet If I understood you correctly, the test shows an example with associative arrays. But in translations
and platforms
i have a simple arrays with numerical keys (non-associatve arrays). I checked your example and wrote new code to validate my data. It shows:
Array
(
[translations] => Array
(
[language] => language must be present
[platforms] => platforms must be present
)
)
But i expect to see something like this:
Array
(
[translations] => Array
(
[0] => Array
(
[platforms] => Array
(
[1] => Array
(
[minimum] => minimum must be present
)
)
)
)
)
My code sample:
<?php
declare(strict_types=1);
require 'vendor/autoload.php';
use Respect\Validation\Exceptions\NestedValidationException;
use Respect\Validation\Validator as v;
$bodyParams = [
'original_name' => 'Exiles',
'translations' => [
[
'language' => 'en',
'title' => 'Exiles',
'overview' => 'From the creators of the award winning...',
'platforms' => [
[
'id' => 8,
'minimum' => 'iPad 2',
],
[
'id' => 7,
// There is no minimum
]
]
]
]
];
try {
v::create()
->key('original_name', v::stringType())
->key('translations',
v::create()
->key('language', v::stringType())
->key('platforms', v::create()
->key('id', v::intType())
->key('minimum', v::stringType())
->key('recommended', v::optional(
v::stringType()
))
->key('release_date', v::allOf(
v::stringType(),
v::date('Y-m-d')
)),
true)
, true)->assert($bodyParams);
} catch (NestedValidationException $exception) {
print_r($exception->getMessages());
}
You could walk the exception tree by yourself, implementing an Iterator.
Internally, Respect does so to resolve the tree into a flat list: https://github.com/Respect/Validation/blob/master/library/Exceptions/RecursiveExceptionIterator.php. This can be seen in action using $exception->getFullMessage()
.
You could either re-implement the RecursiveExceptionIterator to allow multidimensional keys or perhaps use the flat result:
<?php
require 'vendor/autoload.php';
use Respect\Validation\Exceptions\NestedValidationException;
use Respect\Validation\Validator as v;
$bodyParams = [
'original_name' => 'Exiles',
'translations' => [
[
'language' => 'en',
'title' => 'Exiles',
'overview' => 'From the creators of the award winning...',
'platforms' => [
[
'id' => 8,
'minimum' => 'iPad 2',
],
[
'id' => 7,
// There is no minimum
]
]
]
]
];
try {
v::key('original_name', v::stringType())
->key('translations', v::arrayType()->each(
v::key('language', v::stringType())
->key('platforms', v::arrayType()
->each(
v::key('id', v::intType())
->key('minimum', v::stringType())
->key('recommended', v::stringType(), false)
->key('release_date', v::allOf(
v::stringType(),
v::date('Y-m-d')
))->setName('Platform Object')
))->setName("Translation Object")
)
)->assert($bodyParams);
} catch (NestedValidationException $exception) {
$messages = [];
foreach ($exception->getIterator() as $sub) {
$messages[] = [
'message' => $sub->getMessage(),
'identifier' => $sub->getId(),
'input' => $sub->getParams()['input']
];
}
print_r($messages);
}
I've added setName
to some of the grouped validators, this reflects on the identifier
they inherit and it might make individual failures easier to find.
Instead of $exception->getIterator
you could:
$iterator = new RecursiveIteratorIterator(
new Respect\Validation\Exceptions\RecursiveExceptionIterator($exception),
RecursiveIteratorIterator::SELF_FIRST
);
This would allow using $iterator->hasChildren()
and $iterator->getChildren()
to navigate freely on the structure. Check https://www.php.net/manual/en/class.recursiveiteratoriterator.php for more methods.
The code with the simple $exception->getIterator()
should print this:
Array
(
[0] => Array
(
[message] => These rules must pass for Translation Object
[identifier] => Translation Object
[input] => Array
(
[language] => en
[title] => Exiles
[overview] => From the creators of the award winning...
[platforms] => Array
(
[0] => Array
(
[id] => 8
[minimum] => iPad 2
)
[1] => Array
(
[id] => 7
)
)
)
)
[1] => Array
(
[message] => Each item in platforms must be valid
[identifier] => platforms
[input] => Array
(
[0] => Array
(
[id] => 8
[minimum] => iPad 2
)
[1] => Array
(
[id] => 7
)
)
)
[2] => Array
(
[message] => These rules must pass for Platform Object
[identifier] => Platform Object
[input] => Array
(
[id] => 8
[minimum] => iPad 2
)
)
[3] => Array
(
[message] => release_date must be present
[identifier] => release_date
[input] => Array
(
[id] => 8
[minimum] => iPad 2
)
)
[4] => Array
(
[message] => These rules must pass for Platform Object
[identifier] => Platform Object
[input] => Array
(
[id] => 7
)
)
[5] => Array
(
[message] => minimum must be present
[identifier] => minimum
[input] => Array
(
[id] => 7
)
)
[6] => Array
(
[message] => release_date must be present
[identifier] => release_date
[input] => Array
(
[id] => 7
)
)
)
From there you could find what went wrong with each specific key or maybe even rebuild the hierarchy.
I hope this can help in your scenario.
@alganet thank you!
Hi,
I need to validate a data with the multidimensional structure:
My validation code is:
The result of execution (if key
minimum
in anyplatforms
doesn't exist) is:Is there a way to get the full hierarchy of error (including nesting)? Something like this: