Allow to customise messages while asserting

Because we now have a single "assert()" method, we have more freedom to
add more customizations to it. This specific one is handy if someone
wants to use the library to validate but wants to use their own
exceptions.

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
This commit is contained in:
Henrique Moody 2024-03-26 12:53:15 +01:00
parent d7dc0f2b4e
commit 2ae1df177a
No known key found for this signature in database
GPG key ID: 221E9281655813A6
6 changed files with 149 additions and 44 deletions

View file

@ -199,15 +199,13 @@ method as well by passing the templates as an argument:
```php
try {
$usernameValidator->assert('really messed up screen#name');
$usernameValidator->assert('really messed up screen#name', [
'alnum' => '{{name}} must contain only letters and digits',
'noWhitespace' => '{{name}} cannot contain spaces',
'length' => '{{name}} must not have more than 15 chars',
]);
} catch(NestedValidationException $exception) {
print_r(
$exception->getMessages([
'alnum' => '{{name}} must contain only letters and digits',
'noWhitespace' => '{{name}} cannot contain spaces',
'length' => '{{name}} must not have more than 15 chars',
])
);
print_r($exception->getMessages());
}
```

View file

@ -16,15 +16,17 @@ use Respect\Validation\Message\StandardFormatter;
use Respect\Validation\Message\StandardRenderer;
use Respect\Validation\Mixins\StaticValidator;
use Respect\Validation\Rules\AllOf;
use Respect\Validation\Rules\Core\Standard;
use Throwable;
use function count;
use function current;
use function is_array;
use function is_string;
/**
* @mixin StaticValidator
*/
final class Validator extends Standard
final class Validator implements Validatable
{
use CanBindEvaluateRule;
@ -34,6 +36,10 @@ final class Validator extends Standard
/** @var array<string, mixed> */
private array $templates = [];
private ?string $name = null;
private ?string $template = null;
public function __construct(
private readonly Factory $factory,
private readonly Formatter $formatter,
@ -66,15 +72,24 @@ final class Validator extends Standard
return $this->evaluate($input)->isValid;
}
public function assert(mixed $input): void
/** @param array<string, mixed>|string|Throwable|null $template */
public function assert(mixed $input, array|string|Throwable|null $template = null): void
{
$result = $this->evaluate($input);
if ($result->isValid) {
return;
}
if ($template instanceof Throwable) {
throw $template;
}
$templates = $this->templates;
if (count($templates) === 0 && $this->getTemplate() != null) {
if (is_array($template)) {
$templates = $template;
} elseif (is_string($template)) {
$templates = ['__root__' => $template];
} elseif ($this->getTemplate() != null) {
$templates = ['__root__' => $this->getTemplate()];
}
@ -115,6 +130,30 @@ final class Validator extends Standard
$this->assert($input);
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): static
{
$this->name = $name;
return $this;
}
public function getTemplate(): ?string
{
return $this->template;
}
public function setTemplate(string $template): static
{
$this->template = $template;
return $this;
}
private function rule(): Validatable
{
if (count($this->rules) === 1) {

View file

@ -26,25 +26,27 @@ exceptionMessages(
->key('password', v::stringType())
->key('schema', v::stringType())
)
->setTemplates([
'mysql' => [
'user' => 'Value should be a MySQL username',
'host' => '`{{name}}` should be a MySQL host',
->assert(
[
'mysql' => [
'host' => 42,
'schema' => 42,
],
'postgresql' => [
'user' => 42,
'password' => 42,
],
],
'postgresql' => [
'schema' => 'You must provide a valid PostgreSQL schema',
],
])
->assert([
'mysql' => [
'host' => 42,
'schema' => 42,
],
'postgresql' => [
'user' => 42,
'password' => 42,
],
]);
[
'mysql' => [
'user' => 'Value should be a MySQL username',
'host' => '`{{name}}` should be a MySQL host',
],
'postgresql' => [
'schema' => 'You must provide a valid PostgreSQL schema',
],
]
);
}
);
?>

View file

@ -51,19 +51,11 @@ function run(array $scenarios): void
echo $description . PHP_EOL;
echo str_repeat('⎺', strlen($description)) . PHP_EOL;
if (is_string($template)) {
$rule->setTemplate($template);
}
if (is_array($template)) {
$rule->setTemplates($template);
}
$fallbackMessage = 'No exception was thrown with: ' . stringify($input);
exceptionMessage(static fn() => $rule->check($input), $fallbackMessage);
exceptionFullMessage(static fn() => $rule->assert($input), $fallbackMessage);
exceptionMessages(static fn() => $rule->assert($input), $fallbackMessage);
exceptionMessage(static fn() => $rule->assert($input, $template), $fallbackMessage);
exceptionFullMessage(static fn() => $rule->assert($input, $template), $fallbackMessage);
exceptionMessages(static fn() => $rule->assert($input, $template), $fallbackMessage);
echo PHP_EOL;
}
}

View file

@ -11,12 +11,11 @@ exceptionMessages(
static fn() => v::alnum()
->noWhitespace()
->length(v::between(1, 15))
->setTemplates([
->assert('really messed up screen#name', [
'alnum' => '{{name}} must contain only letters and digits',
'noWhitespace' => '{{name}} cannot contain spaces',
'length' => '{{name}} must not have more than 15 chars',
])
->assert('really messed up screen#name')
);
?>
--EXPECT--
@ -25,4 +24,4 @@ exceptionMessages(
'alnum' => '"really messed up screen#name" must contain only letters and digits',
'noWhitespace' => '"really messed up screen#name" cannot contain spaces',
'lengthBetween' => 'The length of "really messed up screen#name" must be between 1 and 15',
]
]

View file

@ -9,7 +9,9 @@ declare(strict_types=1);
namespace Respect\Validation;
use Exception;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use Respect\Validation\Exceptions\ComponentException;
use Respect\Validation\Test\Rules\Stub;
@ -49,4 +51,77 @@ final class ValidatorTest extends TestCase
self::assertFalse($validator->isValid('whatever'));
}
#[Test]
public function itShouldAssertUsingTheGivingExceptionEvenWhenRuleAlreadyHasTemplate(): void
{
$template = new Exception('This is a test');
$this->expectExceptionObject($template);
$validator = Validator::create(Stub::fail(1));
$validator->setTemplate('This wont be used');
$validator->assert('whatever', $template);
}
#[Test]
public function itShouldAssertUsingTheGivingStringTemplate(): void
{
$template = 'This is my new template';
$this->expectExceptionMessage($template);
$validator = Validator::create(Stub::fail(1));
$validator->assert('whatever', $template);
}
#[Test]
public function itShouldAssertUsingTheGivingArrayTemplateWithTheRuleNameAsKey(): void
{
$template = ['stub' => 'This is my new template'];
$this->expectExceptionMessage($template['stub']);
$validator = Validator::create(Stub::fail(1));
$validator->setTemplates(['stub' => 'This is my pre-defined template']);
$validator->assert('whatever', $template);
}
#[Test]
public function itShouldAssertUsingTheGivingArrayTemplateWithRootKey(): void
{
$template = ['__root__' => 'This is my new template'];
$this->expectExceptionMessage($template['__root__']);
$validator = Validator::create(Stub::fail(1));
$validator->setTemplates(['__root__' => 'This is my pre-defined template']);
$validator->assert('whatever', $template);
}
/** @param string|array<string, mixed> $template */
#[Test]
#[DataProvider('providerForTemplates')]
public function itShouldAssertNotOverwritingThePreDefinedTemplate(array|string $template): void
{
$preDefinedTemplate = 'This is my pre-defined template';
$this->expectExceptionMessage($preDefinedTemplate);
$validator = Validator::create(Stub::fail(1));
$validator->setTemplate($preDefinedTemplate);
$validator->assert('whatever', $template);
}
/**
* @return array<string, array{string|array<string, mixed>}>
*/
public static function providerForTemplates(): array
{
return [
'string' => ['This is my new template'],
'array key named key' => [['stub' => 'This is my new template']],
'array key __root__ key' => [['__root__' => 'This is my new template']],
];
}
}