Description
Following up on #28232
Addressed issues
-
Some validators alter the data they are validating before running the validation.
For instance, IbanValidator will remove any space and capitalize the string it is given before running validation. -
The behavior described in 1 is not consistent across validators.
For instance, IbanValidator accepts lower-cased strings while BicValidator refuses them. -
The behavior described in 1 breaks the Single Responsibility principle as the role of the validator is to validate, not sanitize nor filter nor normalize the data it is working on.
Description
Filtering some common accepted formattings is good UX (like stripping space off an IBAN) as it widens the acceptable data set, so it must be kept. The related use-case are forms written with Form component.
Each filtering should be placed in dedicated classes implementing the DataTransformInterface of the Form component.
Dedicated FormTypes should be created and register these DataTransform implementation (like \Symfony\Component\Form\Extension\Core\Type\NumberType
does with both NumberToLocalizedStringTransformer
and \Symfony\Component\Form\Extension\Core\DataTransformer\StringToFloatTransformer
)
In the next minor version, validators should have an option strict
set to false
by default to preserve BC. Setting this option to true
should skip normalization of the data under validation.
In the next major version:
- Validators should drop normalization and only run strict validation.
- Developers should use the new types in their forms.
Identified validators with this flaw:
- BicValidator (removes spaces)
- IsbnValidator (removes dashes)
- IbanValidator (removes spaces, capitalize)
- LocaleValidator (because of the
canonicalize
option)
All validators with a normalizer
option should be updated too (cf symfony/validator@fdf8dfc#diff-5b9cb67322b0684885ea5ae77e6932da) to remove this normalizer
UuidValidator already has a strict
option which may be out of the scope: I'm just wondering what is the point of accepting non-compliant UUIDs.
Example
For instance, we could rely on the following code for IBANs.
<?php
class StringToIbanTransformer implements DataTransformerInterface
{
public function transform($value)
{
if (null === $value) {
return null;
}
if (!\is_string($value)) {
throw new TransformationFailedException('Expected a string.');
}
return str_replace(' ', '', strtoupper($value));
}
public function reverseTransform($value)
{
if (null === $value) {
return null;
}
if (!\is_string($value)) {
throw new TransformationFailedException('Expected a string.');
}
// Some code to add a space every 4 chars
// FR1420041010050500013M02606 => FR14 2004 1010 0505 0001 3M02 606
return $value;
}
}
<?php
class IbanType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addViewTransformer(new StringToIbanTransformer());
}
}