docs/handling-results.md
The ResultQuery class provides a fluent interface for inspecting validation results. It's returned by the validate() method and offers methods to check validity, retrieve error messages, and query nested validation results.
use Respect\Validation\ValidatorBuilder as v;
$result = v::intType()->positive()->validate($input);
if ($result->hasFailed()) {
echo $result->getMessage();
}
Returns true if validation passed, false otherwise.
$result = v::email()->validate('[email protected]');
$result->hasFailed(); // false
$result = v::email()->validate('not-an-email');
$result->hasFailed(); // true
Returns the first error message from the validation result. Returns an empty string if validation passed.
$result = v::intType()->validate('not an integer');
echo $result->getMessage();
// → "not an integer" must be an integer
Returns a complete error tree showing all validation failures in a nested Markdown list format. Useful for debugging or displaying comprehensive error feedback.
$result = v::alnum()->lowercase()->validate('The Panda');
echo $result->getFullMessage();
// → - "The Panda" must pass all the rules
// → - "The Panda" must consist only of letters (a-z) and digits (0-9)
// → - "The Panda" must consist only of lowercase letters
Returns all error messages as an associative array. Keys correspond to validator IDs or paths.
$result = v::alnum()->lowercase()->validate('The Panda');
print_r($result->getMessages());
// Array
// (
// [__root__] => "The Panda" must pass all the rules
// [alnum] => "The Panda" must consist only of letters (a-z) and digits (0-9)
// [lowercase] => "The Panda" must consist only of lowercase letters
// )
For nested structures, keys reflect the path:
$result = v::init()
->key('name', v::stringType())
->key('age', v::intType())
->validate(['name' => 123, 'age' => 'twenty']);
print_r($result->getMessages());
// Array
// (
// [__root__] => `["name": 123, "age": "twenty"]` must pass all the rules
// [name] => name must be a string
// [age] => age must be an integer
// )
ResultQuery implements Stringable, so you can use it directly in string contexts. It returns the same value as getMessage().
$result = v::email()->validate('invalid');
echo $result; // "invalid" must be a valid email address
When validating complex nested structures, ResultQuery provides methods to find and inspect specific parts of the validation result tree.
All finder methods (findByPath(), findByName(), findById()) return either:
ResultQuery instance wrapping the found resultnull if no matching result was foundThis allows safe chaining with null checks:
$result = $validator->validate($input);
$nested = $result->findByPath('user.profile.email');
if ($nested?->hasFailed()) {
echo $nested->getMessage();
}
Finds a result by its path through the data structure. Supports dot notation for nested paths.
$result = v::init()
->key('user', v::key('email', v::email()))
->validate(['user' => ['email' => 'invalid']]);
// Find the email validation result
$emailResult = $result->findByPath('user.email');
if ($emailResult?->hasFailed()) {
echo $emailResult->getMessage();
// → `.user.email` must be a valid email address
}
Paths can also be integers for array indices:
$result = v::init()
->each(v::positive())
->validate([10, -5, 20]);
// Find the result for index 1
$itemResult = $result->findByPath(1);
if ($itemResult?->hasFailed()) {
echo $itemResult->getMessage();
// → `.1` must be a positive number
}
Combined paths work too:
$result = v::init()
->each(
v::key('email', v::email()),
)
->validate([
['email' => '[email protected]'],
['email' => 'invalid'],
]);
// Find the email of the second item
$emailResult = $result->findByPath('1.email');
if ($emailResult?->hasFailed()) {
echo $emailResult->getMessage();
// → `.1.email` must be a valid email address
}
Paths support wildcards using * to match any single path segment:
items.* matches the first result under items*.email matches the first .email path founddata.*.value matches the first nested path ending with .value$result = v::init()
->key('items', v::each(v::positive()))
->validate(['items' => [10, -5, 20]]);
// Find the first invalid item (items.1)
$firstInvalid = $result->findByPath('items.*');
if ($firstInvalid?->hasFailed()) {
echo $firstInvalid->getMessage();
// → `.items.1` must be a positive number
}
Finds a result by a custom name assigned with the Named validator.
$result = v::named('User Email', v::email())->validate('invalid');
echo $result->findByName('User Email');
// → User Email must be a valid email address
This is useful when you need to locate results by semantic names rather than structural paths:
$result = v::init()
->key(
'contact',
v::named('Primary Email', v::key('email', v::email())),
)
->validate(['contact' => ['email' => 'bad']]);
echo $result->findByName('Primary Email');
// → `.contact.email` (<- Primary Email) must be a valid email address
Finds a result by validator ID. IDs are automatically generated from validator class names (e.g., StringType becomes stringType).
$result = v::stringType()->email()->validate(123);
echo $result->findById('stringType');
// → 123 must be a string
$result = v::init()
->key('email', v::email())
->key('age', v::intType()->positive())
->validate($formData);
// Check if email specifically is valid
$emailResult = $result->findByPath('email');
if ($emailResult?->hasFailed()) {
// Email failed validation
}
$result = v::init()
->key('username', v::alnum()->lengthBetween(3, 20))
->key('password', v::lengthGreaterThanOrEqual(8))
->validate($input);
$errors = [
'username' => $result->findByPath('username')?->getMessage(),
'password' => $result->findByPath('password')?->getMessage(),
];
$items = [
['name' => 'Widget', 'price' => 10],
['name' => 123, 'price' => -5],
['name' => 'Gadget', 'price' => 20],
];
$result = v::init()
->each(
v::init()
->key('name', v::stringType())
->key('price', v::positive())
)
->validate($items);
// Check each item individually
for ($i = 0; $i < count($items); $i++) {
$itemResult = $result->findByPath($i);
if ($itemResult !== null && !$itemResult->hasFailed()) {
echo "Item $i has errors: " . $itemResult->getMessage() . "\n";
}
}
// Or get a specific field from a specific item
$priceResult = $result->findByPath('1.price');
if ($priceResult !== null) {
echo $priceResult->getMessage();
// → `.1.price` must be a positive number
}
$result = v::init()
->key('email', v::email())
->key('age', v::intType())
->validate($input, [
'email' => 'Please provide a valid email address',
'age' => 'Age must be a whole number',
]);
$emailResult = $result->findByPath('email');
if ($emailResult?->hasFailed()) {
echo $emailResult->getMessage();
// → Please provide a valid email address
}