feature #40240 [Validator] Add Validation::createIsValidCallable() that returns a boolean instead of exception (wouterj)

This PR was merged into the 5.3-dev branch.

Discussion
----------

[Validator] Add Validation::createIsValidCallable() that returns a boolean instead of exception

| Q             | A
| ------------- | ---
| Branch?       | 5.x
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       | Fix #36820
| License       | MIT
| Doc PR        | tbd

This adds a `Validator::createValidCallable()` (I'm very open for other name suggestions) that returns a boolean instead of exceptions. This allows usingit in places where booleans are expected, for instance in the referenced OptionsResolver case:

```php
$resolver->setAllowedValues('name', Validation::createValidCallable(
    new Assert\Length(['min' => 10 ])
));
```

Commits
-------

e731f5fda9 [Validator] Add createValidCallable() that returns a boolean
This commit is contained in:
Fabien Potencier 2021-03-12 09:58:03 +01:00
commit 6c0102c184
3 changed files with 53 additions and 7 deletions

View File

@ -1,6 +1,11 @@
CHANGELOG
=========
5.3
---
* Add `Validation::createIsValidCallable()` that returns true/false instead of throwing exceptions
5.2.0
-----

View File

@ -30,7 +30,29 @@ class ValidationTest extends TestCase
public function testCreateCallableInvalid()
{
$validator = Validation::createCallable(new Email());
$this->expectException(ValidationFailedException::class);
$validator('test');
try {
$validator('test');
$this->fail('No ValidationFailedException thrown');
} catch (ValidationFailedException $e) {
$this->assertEquals('test', $e->getValue());
$violations = $e->getViolations();
$this->assertCount(1, $violations);
$this->assertEquals('This value is not a valid email address.', $violations->get(0)->getMessage());
}
}
public function testCreateIsValidCallableValid()
{
$validator = Validation::createIsValidCallable(new Email());
$this->assertTrue($validator('test@example.com'));
}
public function testCreateIsValidCallableInvalid()
{
$validator = Validation::createIsValidCallable(new Email());
$this->assertFalse($validator('test', $violations));
$this->assertCount(1, $violations);
$this->assertEquals('This value is not a valid email address.', $violations->get(0)->getMessage());
}
}

View File

@ -25,8 +25,30 @@ final class Validation
* Creates a callable chain of constraints.
*
* @param Constraint|ValidatorInterface|null $constraintOrValidator
*
* @return callable($value)
*/
public static function createCallable($constraintOrValidator = null, Constraint ...$constraints): callable
{
$validator = self::createIsValidCallable($constraintOrValidator, ...$constraints);
return static function ($value) use ($validator) {
if (!$validator($value, $violations)) {
throw new ValidationFailedException($value, $violations);
}
return $value;
};
}
/**
* Creates a callable that returns true/false instead of throwing validation exceptions.
*
* @param Constraint|ValidatorInterface|null $constraintOrValidator
*
* @return callable($value, &$violations = null): bool
*/
public static function createIsValidCallable($constraintOrValidator = null, Constraint ...$constraints): callable
{
$validator = $constraintOrValidator;
@ -39,13 +61,10 @@ final class Validation
$validator = $validator ?? self::createValidator();
return static function ($value) use ($constraints, $validator) {
return static function ($value, &$violations = null) use ($constraints, $validator) {
$violations = $validator->validate($value, $constraints);
if (0 !== $violations->count()) {
throw new ValidationFailedException($value, $violations);
}
return $value;
return 0 === $violations->count();
};
}