respect-validation/docs/handling-exceptions.md
Henrique Moody f85d34db3d
Update "Handling Exceptions" documentation
After many changes in the codebase, the documentation was outdated.
2026-01-26 12:00:17 +01:00

6.7 KiB

Handling exceptions

The ValidatorBuilder::assert() method throws a ValidationException when validation fails. This exception provides detailed feedback on what went wrong.

The ValidationException

The ValidationException extends PHP's default InvalidArgumentException. That means you can simply catch InvalidArgumentException.

try {
    v::alnum()->assert($input);
} catch (InvalidArgumentException $exception) {
    echo $exception->getMessage();
}

Helpful stack traces

When an exception is thrown, PHP reports where it was created, not where it was caused. In most validation libraries that means stack traces point deep inside library internals. You end up hunting through the trace to find your actual code.

Although the ValidationException is thrown deep inside Validation's internals, we overwrite the stack trace to provide a helpful message. If v::intType()->assert($input) fails in /opt/example.php line 78, your stack trace looks like this:

Stack trace:
#0 /opt/example.php(78): Respect\Validation\Validator->assert(1.0)
#1 {main}

Exception message

The getMessage() method returns the message from the first failed validator.

use Respect\Validation\Exceptions\ValidationException;
use Respect\Validation\ValidatorBuilder as v;

try {
    v::alnum()->lowercase()->assert('The Panda');
} catch (ValidationException $exception) {
    echo $exception->getMessage();
}

The code above generates the following output:

"The Panda" must contain only letters (a-z) and digits (0-9)

Full exception message

The getFullMessage() method will return a full comprehensive explanation of validators that didn't pass in a nested Markdown list format.

use Respect\Validation\Exceptions\ValidationException;
use Respect\Validation\ValidatorBuilder as v;

try {
    v::alnum()->lowercase()->assert('The Panda');
} catch (ValidationException $exception) {
    echo $exception->getFullMessage();
}

The code above generates the following output:

- "The Panda" must pass all the rules
  - "The Panda" must contain only letters (a-z) and digits (0-9)
  - "The Panda" must contain only lowercase letters

Full exception messages as an array

Retrieve validation messages in array format using getMessages().

use Respect\Validation\Exceptions\ValidationException;
use Respect\Validation\ValidatorBuilder as v;

try {
    v::alnum()->lowercase()->assert('The Panda');
} catch (ValidationException $exception) {
    print_r($exception->getMessages());
}

The code above generates the following output:

Array
(
    [__root__] => "The Panda" must pass all the rules
    [alnum] => "The Panda" must contain only letters (a-z) and digits (0-9)
    [lowercase] => "The Panda" must contain only lowercase letters
)

When validating with Key or Property, the keys will correspond to the name of the key or property that failed the validation.

Custom exception

You can pass a custom exception as the second argument of ValidatorBuilder::assert() in two ways.

Custom exception as object

Pass a Throwable to throw a custom exception instead of ValidationException.

use Respect\Validation\ValidatorBuilder as v;

try {
    v::alnum()->assert($input, new DomainValidationException('Validation failed!'));
} catch (DomainValidationException $exception) {
     echo $exception->getMessage();
}

Custom exception as callable

Pass a callable to intercept the ValidationException before throwing your own exception.

use Respect\Validation\Exceptions\ValidationException;
use Respect\Validation\ValidatorBuilder as v;

try {
    v::alnum()->assert(
        $input,
        fn (ValidationException $exception) => new DomainException(
            'Validation error: ' . $exception->getMessage(),
            $exception->getCode(),
            $exception
        )
    );
} catch (DomainException $exception) {
     echo $exception->getMessage();
}

Custom templates

The assert() method accepts different types of templates as the second argument to customize exception messages.

Custom templates as string

Pass a single string template to replace the root message of the exception.

use Respect\Validation\Exceptions\ValidationException;
use Respect\Validation\ValidatorBuilder as v;

try {
    v::alnum()->assert('The Panda', 'Invalid username provided');
} catch (ValidationException $exception) {
     echo $exception->getFullMessage();
}

The code above generates the following output.

- Invalid username provided

Custom templates as array

Pass custom templates as an array to the assert() method for one-off use cases.

use Respect\Validation\Exceptions\ValidationException;
use Respect\Validation\ValidatorBuilder as v;

try {
    v::alnum()
        ->lowercase()
        ->assert(
            'The Panda',
            [
                '__root__' => 'The given input is not valid',
                'alnum' => 'Your username must contain only letters and digits',
                'lowercase' => 'Your username must be lowercase',
            ]
        );
} catch (ValidationException $exception) {
    print_r($exception->getMessages());
}

The code above generates the following output.

Array
(
    [__root__] => The given input is not valid
    [alnum] => Your username must contain only letters and digits
    [lowercase] => Your username must be lowercase
)

Custom templates with Templated validator

Use the Templated validator to attach templates directly to the chain. That way your chain of validators will always have the same template.

use Respect\Validation\Exceptions\ValidationException;
use Respect\Validation\ValidatorBuilder as v;

try {
    v::templated('Invalid email address', v::email())
        ->assert('not an email');
} catch (ValidationException $exception) {
     echo $exception->getMessage();
}

The code above generates the following output.

Invalid email address

You can also use Templated with template parameters to create dynamic messages.

use Respect\Validation\Exceptions\ValidationException;
use Respect\Validation\ValidatorBuilder as v;

try {
    v::templated(
        'The author of the page {{title}} is empty',
        v::notBlank(),
        ['title' => 'Feature Guide']
    )->assert('');
} catch (ValidationException $exception) {
     echo $exception->getMessage();
}

The code above generates the following output.

The author of the page "Feature Guide" is empty