Skip to content

[Form] Change FormTypeValidatorExtension construct signature #49502

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: 7.4
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions UPGRADE-6.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ DependencyInjection
* Deprecate `PhpDumper` options `inline_factories_parameter` and `inline_class_loader_parameter`, use `inline_factories` and `inline_class_loader` instead
* Deprecate undefined and numeric keys with `service_locator` config, use string aliases instead

Form
----

* Remove argument `$legacyErrorMessages` from the constructor of `FormTypeValidatorExtension` and `ValidatorExtension`

FrameworkBundle
---------------

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@
->set('form.type_extension.form.validator', FormTypeValidatorExtension::class)
->args([
service('validator'),
false,
service('twig.form.renderer')->ignoreOnInvalid(),
service('translator')->ignoreOnInvalid(),
])
Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Component/Form/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

6.3
---

* Remove argument `$legacyErrorMessages` from the constructor of `FormTypeValidatorExtension` and `ValidatorExtension`

6.2
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,27 @@ class FormTypeValidatorExtension extends BaseValidatorExtension
{
private ValidatorInterface $validator;
private ViolationMapper $violationMapper;
private bool $legacyErrorMessages;

public function __construct(ValidatorInterface $validator, bool $legacyErrorMessages = true, FormRendererInterface $formRenderer = null, TranslatorInterface $translator = null)
/**
* @param FormRendererInterface|null $formRenderer
* @param TranslatorInterface|null $translator
*/
public function __construct(ValidatorInterface $validator, /* FormRendererInterface */ $formRenderer = null, /* TranslatorInterface */ $translator = null)
{
if (\is_bool($formRenderer)) {
trigger_deprecation('symfony/form', '6.3', 'The signature of "%s" constructor requires 3 arguments: "ValidatorInterface $validator, FormRendererInterface $formRenderer = null, TranslatorInterface $translator = null". Passing argument $legacyErrorMessages is deprecated.', __CLASS__);
$formRenderer = $translator;
$translator = 4 <= \func_num_args() ? func_get_arg(3) : null;
}

if (null !== $formRenderer && !$formRenderer instanceof FormRendererInterface) {
throw new \TypeError(sprintf('Argument 2 passed to "%s()" must be an instance of "%s" or null, "%s" given.', __METHOD__, FormRendererInterface::class, get_debug_type($formRenderer)));
}

if (null !== $translator && !$translator instanceof TranslatorInterface) {
throw new \TypeError(sprintf('Argument 3 passed to "%s()" must be an instance of "%s" or null, "%s" given.', __METHOD__, TranslatorInterface::class, get_debug_type($formRenderer)));
}

$this->validator = $validator;
$this->violationMapper = new ViolationMapper($formRenderer, $translator);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,26 @@ class ValidatorExtension extends AbstractExtension
private ValidatorInterface $validator;
private ?FormRendererInterface $formRenderer;
private ?TranslatorInterface $translator;
private bool $legacyErrorMessages;

public function __construct(ValidatorInterface $validator, bool $legacyErrorMessages = true, FormRendererInterface $formRenderer = null, TranslatorInterface $translator = null)
/**
* @param FormRendererInterface|null $formRenderer
* @param TranslatorInterface|null $translator
*/
public function __construct(ValidatorInterface $validator, /* FormRendererInterface */ $formRenderer = null, /* TranslatorInterface */ $translator = null)
{
$this->legacyErrorMessages = $legacyErrorMessages;
if (\is_bool($formRenderer)) {
trigger_deprecation('symfony/form', '6.3', 'The signature of "%s" constructor requires 3 arguments: "ValidatorInterface $validator, FormRendererInterface $formRenderer = null, TranslatorInterface $translator = null". Passing argument $legacyErrorMessages is deprecated.', __CLASS__);
$formRenderer = $translator;
$translator = 4 <= \func_num_args() ? func_get_arg(3) : null;
}

if (null !== $formRenderer && !$formRenderer instanceof FormRendererInterface) {
throw new \TypeError(sprintf('Argument 2 passed to "%s()" must be an instance of "%s" or null, "%s" given.', __METHOD__, FormRendererInterface::class, get_debug_type($formRenderer)));
}

if (null !== $translator && !$translator instanceof TranslatorInterface) {
throw new \TypeError(sprintf('Argument 3 passed to "%s()" must be an instance of "%s" or null, "%s" given.', __METHOD__, TranslatorInterface::class, get_debug_type($translator)));
}

$metadata = $validator->getMetadataFor(\Symfony\Component\Form\Form::class);

Expand All @@ -60,7 +75,7 @@ public function loadTypeGuesser(): ?FormTypeGuesserInterface
protected function loadTypeExtensions(): array
{
return [
new Type\FormTypeValidatorExtension($this->validator, $this->legacyErrorMessages, $this->formRenderer, $this->translator),
new Type\FormTypeValidatorExtension($this->validator, $this->formRenderer, $this->translator),
new Type\RepeatedTypeValidatorExtension(),
new Type\SubmitTypeValidatorExtension(),
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@ protected function getValidatorExtension(): ValidatorExtension
$this->validator->expects($this->any())->method('getMetadataFor')->will($this->returnValue($metadata));
$this->validator->expects($this->any())->method('validate')->will($this->returnValue(new ConstraintViolationList()));

return new ValidatorExtension($this->validator, false);
return new ValidatorExtension($this->validator);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class FormValidatorPerformanceTest extends FormPerformanceTestCase
protected function getExtensions()
{
return [
new ValidatorExtension(Validation::createValidator(), false),
new ValidatorExtension(Validation::createValidator()),
];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public function testInvalidConstraint()
public function testGroupSequenceWithConstraintsOption()
{
$form = Forms::createFormFactoryBuilder()
->addExtension(new ValidatorExtension(Validation::createValidator(), false))
->addExtension(new ValidatorExtension(Validation::createValidator()))
->getFormFactory()
->create(FormTypeTest::TESTED_TYPE, null, ['validation_groups' => new GroupSequence(['First', 'Second'])])
->add('field', TextTypeTest::TESTED_TYPE, [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Component\Form\Tests\Extension\Validator;

use PHPUnit\Framework\TestCase;
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
use Symfony\Component\Form\Extension\Validator\Constraints\Form as FormConstraint;
use Symfony\Component\Form\Extension\Validator\ValidatorExtension;
use Symfony\Component\Form\Extension\Validator\ValidatorTypeGuesser;
Expand All @@ -24,8 +25,15 @@

class ValidatorExtensionTest extends TestCase
{
public function test2Dot5ValidationApi()
use ExpectDeprecationTrait;

/**
* @group legacy
*/
public function testLegacy2Dot5ValidationApi()
{
$this->expectDeprecation('Since symfony/form 6.3: The signature of "Symfony\Component\Form\Extension\Validator\ValidatorExtension" constructor requires 3 arguments: "ValidatorInterface $validator, FormRendererInterface $formRenderer = null, TranslatorInterface $translator = null". Passing argument $legacyErrorMessages is deprecated.');

$metadata = new ClassMetadata(Form::class);

$metadataFactory = new FakeMetadataFactory();
Expand All @@ -46,4 +54,67 @@ public function test2Dot5ValidationApi()
$this->assertSame(TraversalStrategy::NONE, $metadata->traversalStrategy);
$this->assertCount(0, $metadata->getPropertyMetadata('children'));
}

/**
* @group legacy
*/
public function testLegacyWithBadFormRendererType()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not the legacy signature, but the new one though, as you don't pass the boolean.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. But when type hint will be set in 7.0. Args checking will be drop and tests must also be dropped.

I can keep @group legacy and only remove legacy in function name ?

{
$metadata = new ClassMetadata(Form::class);

$metadataFactory = new FakeMetadataFactory();
$metadataFactory->addMetadata($metadata);

$validator = Validation::createValidatorBuilder()
->setMetadataFactory($metadataFactory)
->getValidator();

$this->expectException(\TypeError::class);
$this->expectExceptionMessage('Argument 2 passed to "Symfony\Component\Form\Extension\Validator\ValidatorExtension::__construct()" must be an instance of "Symfony\Component\Form\FormRendererInterface" or null, "stdClass" given.');

new ValidatorExtension($validator, new \stdClass());
}

/**
* @group legacy
*/
public function testLegacyWithBadTranslatorType()
{
$metadata = new ClassMetadata(Form::class);

$metadataFactory = new FakeMetadataFactory();
$metadataFactory->addMetadata($metadata);

$validator = Validation::createValidatorBuilder()
->setMetadataFactory($metadataFactory)
->getValidator();

$this->expectException(\TypeError::class);
$this->expectExceptionMessage('Argument 3 passed to "Symfony\Component\Form\Extension\Validator\ValidatorExtension::__construct()" must be an instance of "Symfony\Contracts\Translation\TranslatorInterface" or null, "stdClass" given.');

new ValidatorExtension($validator, null, new \stdClass());
}

public function test2Dot5ValidationApi()
{
$metadata = new ClassMetadata(Form::class);

$metadataFactory = new FakeMetadataFactory();
$metadataFactory->addMetadata($metadata);

$validator = Validation::createValidatorBuilder()
->setMetadataFactory($metadataFactory)
->getValidator();

$extension = new ValidatorExtension($validator);

$this->assertInstanceOf(ValidatorTypeGuesser::class, $extension->loadTypeGuesser());

$this->assertCount(1, $metadata->getConstraints());
$this->assertInstanceOf(FormConstraint::class, $metadata->getConstraints()[0]);

$this->assertSame(CascadingStrategy::NONE, $metadata->cascadingStrategy);
$this->assertSame(TraversalStrategy::NONE, $metadata->traversalStrategy);
$this->assertCount(0, $metadata->getPropertyMetadata('children'));
}
}