feature #31351 [Validator] Improve TypeValidator to handle array of types (jschaedl)

This PR was merged into the 4.4 branch.

Discussion
----------

[Validator] Improve TypeValidator to handle array of types

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #31330
| License       | MIT
| Doc PR        | tbd.

The `@Type` constraint is now able to handle multiple types:

```php
/**
 * @var string|array
 * @Assert\Type(type={"string", "array"})
 */
 private $name;
```

and will pass when `$name` is either of type `string` or `array`.

Commits
-------

c8100f34f8 [Validator] Improve TypeValidator to handle array of types
This commit is contained in:
Fabien Potencier 2019-06-04 09:08:54 +02:00
commit 8d359b2525
3 changed files with 61 additions and 11 deletions

View File

@ -6,6 +6,7 @@ CHANGELOG
* added the `compared_value_path` parameter in violations when using any
comparison constraint with the `propertyPath` option.
* added support for checking an array of types in `TypeValidator`
4.3.0
-----

View File

@ -33,22 +33,25 @@ class TypeValidator extends ConstraintValidator
return;
}
$type = strtolower($constraint->type);
$type = 'boolean' == $type ? 'bool' : $constraint->type;
$isFunction = 'is_'.$type;
$ctypeFunction = 'ctype_'.$type;
$types = (array) $constraint->type;
if (\function_exists($isFunction) && $isFunction($value)) {
return;
} elseif (\function_exists($ctypeFunction) && $ctypeFunction($value)) {
return;
} elseif ($value instanceof $constraint->type) {
return;
foreach ($types as $type) {
$type = strtolower($type);
$type = 'boolean' === $type ? 'bool' : $type;
$isFunction = 'is_'.$type;
$ctypeFunction = 'ctype_'.$type;
if (\function_exists($isFunction) && $isFunction($value)) {
return;
} elseif (\function_exists($ctypeFunction) && $ctypeFunction($value)) {
return;
} elseif ($value instanceof $type) {
return;
}
}
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setParameter('{{ type }}', $constraint->type)
->setParameter('{{ type }}', implode('|', $types))
->setCode(Type::INVALID_TYPE_ERROR)
->addViolation();
}

View File

@ -163,6 +163,52 @@ class TypeValidatorTest extends ConstraintValidatorTestCase
];
}
/**
* @dataProvider getValidValuesMultipleTypes
*/
public function testValidValuesMultipleTypes($value, array $types)
{
$constraint = new Type(['type' => $types]);
$this->validator->validate($value, $constraint);
$this->assertNoViolation();
}
public function getValidValuesMultipleTypes()
{
return [
['12345', ['array', 'string']],
[[], ['array', 'string']],
];
}
/**
* @dataProvider getInvalidValuesMultipleTypes
*/
public function testInvalidValuesMultipleTypes($value, $types, $valueAsString)
{
$constraint = new Type([
'type' => $types,
'message' => 'myMessage',
]);
$this->validator->validate($value, $constraint);
$this->buildViolation('myMessage')
->setParameter('{{ value }}', $valueAsString)
->setParameter('{{ type }}', implode('|', $types))
->setCode(Type::INVALID_TYPE_ERROR)
->assertRaised();
}
public function getInvalidValuesMultipleTypes()
{
return [
['12345', ['boolean', 'array'], '"12345"'],
];
}
protected function createFile()
{
if (!static::$file) {