From 38a9efb998ff5b4a511a239d55569c1ea84eb950 Mon Sep 17 00:00:00 2001 From: bjorn Date: Sun, 5 Jul 2026 17:27:02 +0200 Subject: [PATCH 1/5] feat: add AddSymfonyConstraintValidatorTypeDeclarationsRector [#3600790] --- ...straintValidatorTypeDeclarationsRector.php | 127 ++++++++++++++++++ .../Component/Validator/Constraint.php | 13 ++ .../Validator/ConstraintValidator.php | 22 +++ .../ConstraintValidatorInterface.php | 18 +++ .../Context/ExecutionContextInterface.php | 13 ++ ...intValidatorTypeDeclarationsRectorTest.php | 26 ++++ .../config/configured_rule.php | 11 ++ .../fixture/already_typed.php.inc | 14 ++ .../fixture/constraint_validator.php.inc | 29 ++++ .../fixture/not_a_validator.php.inc | 11 ++ .../self_validating_constraint.php.inc | 37 +++++ 11 files changed, 321 insertions(+) create mode 100644 src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector.php create mode 100644 stubs/Symfony/Component/Validator/Constraint.php create mode 100644 stubs/Symfony/Component/Validator/ConstraintValidator.php create mode 100644 stubs/Symfony/Component/Validator/ConstraintValidatorInterface.php create mode 100644 stubs/Symfony/Component/Validator/Context/ExecutionContextInterface.php create mode 100644 tests/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector/AddSymfonyConstraintValidatorTypeDeclarationsRectorTest.php create mode 100644 tests/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector/config/configured_rule.php create mode 100644 tests/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector/fixture/already_typed.php.inc create mode 100644 tests/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector/fixture/constraint_validator.php.inc create mode 100644 tests/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector/fixture/not_a_validator.php.inc create mode 100644 tests/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector/fixture/self_validating_constraint.php.inc diff --git a/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector.php b/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector.php new file mode 100644 index 000000000..dac3164d5 --- /dev/null +++ b/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector.php @@ -0,0 +1,127 @@ +> */ + public function getNodeTypes(): array + { + return [Class_::class]; + } + + /** + * @param Class_ $node + */ + public function refactor(Node $node): ?Node + { + if (!$this->isObjectType($node, new ObjectType(self::CONSTRAINT_VALIDATOR_INTERFACE))) { + return null; + } + + $changed = false; + + $validate = $node->getMethod('validate'); + if ($validate instanceof ClassMethod) { + if ($this->addMixedFirstParam($validate)) { + $changed = true; + } + if ($this->addVoidReturnType($validate)) { + $changed = true; + } + } + + $initialize = $node->getMethod('initialize'); + if ($initialize instanceof ClassMethod) { + if ($this->addVoidReturnType($initialize)) { + $changed = true; + } + } + + return $changed ? $node : null; + } + + private function addVoidReturnType(ClassMethod $method): bool + { + if ($method->returnType !== null) { + return false; + } + + $method->returnType = new Identifier('void'); + + return true; + } + + private function addMixedFirstParam(ClassMethod $method): bool + { + if (!isset($method->params[0]) || $method->params[0]->type !== null) { + return false; + } + + $method->params[0]->type = new Identifier('mixed'); + + return true; + } +} diff --git a/stubs/Symfony/Component/Validator/Constraint.php b/stubs/Symfony/Component/Validator/Constraint.php new file mode 100644 index 000000000..de7ed93ac --- /dev/null +++ b/stubs/Symfony/Component/Validator/Constraint.php @@ -0,0 +1,13 @@ +doTestFile($filePath); + } + + public static function provideData(): \Iterator + { + return self::yieldFilesFromDirectory(__DIR__.'/fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__.'/config/configured_rule.php'; + } +} diff --git a/tests/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector/config/configured_rule.php b/tests/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector/config/configured_rule.php new file mode 100644 index 000000000..97029ca02 --- /dev/null +++ b/tests/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector/config/configured_rule.php @@ -0,0 +1,11 @@ + diff --git a/tests/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector/fixture/constraint_validator.php.inc b/tests/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector/fixture/constraint_validator.php.inc new file mode 100644 index 000000000..04f79a3c5 --- /dev/null +++ b/tests/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector/fixture/constraint_validator.php.inc @@ -0,0 +1,29 @@ + +----- + diff --git a/tests/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector/fixture/not_a_validator.php.inc b/tests/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector/fixture/not_a_validator.php.inc new file mode 100644 index 000000000..fc8076f7a --- /dev/null +++ b/tests/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector/fixture/not_a_validator.php.inc @@ -0,0 +1,11 @@ + diff --git a/tests/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector/fixture/self_validating_constraint.php.inc b/tests/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector/fixture/self_validating_constraint.php.inc new file mode 100644 index 000000000..a0f6587a1 --- /dev/null +++ b/tests/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector/fixture/self_validating_constraint.php.inc @@ -0,0 +1,37 @@ + +----- + From 6dc5c1e5843198c4cd54d9aff3442ce400bb2442 Mon Sep 17 00:00:00 2001 From: bjorn Date: Sun, 5 Jul 2026 17:34:23 +0200 Subject: [PATCH 2/5] feat: register AddSymfonyConstraintValidatorTypeDeclarationsRector in drupal-11 floor and new drupal-12 sets [#3600790] --- config/drupal-11/drupal-11.0-deprecations.php | 9 +++++++++ config/drupal-12/drupal-12.0-deprecations.php | 15 +++++++++++++++ src/Set/Drupal12SetList.php | 10 ++++++++++ src/Set/DrupalSetProvider.php | 3 ++- tests/src/Set/DrupalSetProviderTest.php | 7 +++++-- 5 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 config/drupal-12/drupal-12.0-deprecations.php create mode 100644 src/Set/Drupal12SetList.php diff --git a/config/drupal-11/drupal-11.0-deprecations.php b/config/drupal-11/drupal-11.0-deprecations.php index a4d1e3ce7..97d3f2864 100644 --- a/config/drupal-11/drupal-11.0-deprecations.php +++ b/config/drupal-11/drupal-11.0-deprecations.php @@ -7,6 +7,7 @@ use DrupalRector\Drupal11\Rector\Deprecation\MigrateSqlGetMigrationPluginManagerRector; use DrupalRector\Drupal11\Rector\Deprecation\RemoveStateCacheSettingRector; use DrupalRector\Drupal11\Rector\Deprecation\StripMigrationDependenciesExpandArgRector; +use DrupalRector\Drupal12\Rector\Deprecation\AddSymfonyConstraintValidatorTypeDeclarationsRector; use DrupalRector\Rector\PHPUnit\PhpUnitTestAnnotationToAttributeRector; use DrupalRector\Rector\PHPUnit\ValueObject\PhpUnitTestAnnotationToAttributeConfiguration; use DrupalRector\Rector\ValueObject\DrupalIntroducedVersionConfiguration; @@ -59,4 +60,12 @@ new PhpUnitTestAnnotationToAttributeConfiguration('11.0.0', '12.0.0', 'depends', 'PHPUnit\Framework\Attributes\Depends'), new PhpUnitTestAnnotationToAttributeConfiguration('11.0.0', '12.0.0', 'testWith', 'PHPUnit\Framework\Attributes\TestWith'), ]); + + // Forward-compat Symfony 8 / Drupal 12 signature change (NOT an 11.0 + // deprecation). Registered here so it fires on drupal/core ^11.0 (every D11 + // install) — the change is backward compatible, so applying it while still + // on D11 is safe and prepares the module for D12. Also registered in the + // drupal-12.0 set for installs already on ^12.0. + // https://git.drupalcode.org/project/redirect/-/merge_requests/200 + $rectorConfig->rule(AddSymfonyConstraintValidatorTypeDeclarationsRector::class); }; diff --git a/config/drupal-12/drupal-12.0-deprecations.php b/config/drupal-12/drupal-12.0-deprecations.php new file mode 100644 index 000000000..f97c86108 --- /dev/null +++ b/config/drupal-12/drupal-12.0-deprecations.php @@ -0,0 +1,15 @@ +rule(AddSymfonyConstraintValidatorTypeDeclarationsRector::class); +}; diff --git a/src/Set/Drupal12SetList.php b/src/Set/Drupal12SetList.php new file mode 100644 index 000000000..99660d830 --- /dev/null +++ b/src/Set/Drupal12SetList.php @@ -0,0 +1,10 @@ + Drupal11SetList::DRUPAL_112, '11.3' => Drupal11SetList::DRUPAL_113, '11.4' => Drupal11SetList::DRUPAL_114, + '12.0' => Drupal12SetList::DRUPAL_120, ]; /** @@ -74,7 +75,7 @@ final class DrupalSetProvider implements SetProviderInterface * * @var string[] */ - private const MAJOR_FLOORS = ['10.0', '11.0']; + private const MAJOR_FLOORS = ['10.0', '11.0', '12.0']; /** * @return SetInterface[] diff --git a/tests/src/Set/DrupalSetProviderTest.php b/tests/src/Set/DrupalSetProviderTest.php index b95145bd1..2bec774f6 100644 --- a/tests/src/Set/DrupalSetProviderTest.php +++ b/tests/src/Set/DrupalSetProviderTest.php @@ -90,8 +90,11 @@ public static function installedVersionProvider(): array 'drupal-11.4-breaking.php', 'drupal-bootstrap.php', ]], - // A future major out of range matches nothing. - '12.0.0 matches nothing' => ['12.0.0', []], + // The next major's floor loads only its own set + bootstrap. + '12.0.0 loads only 12.0' => ['12.0.0', [ + 'drupal-12.0-deprecations.php', + 'drupal-bootstrap.php', + ]], ]; } From 24e3edeb8eb67904e76845805db06904c1f6bd38 Mon Sep 17 00:00:00 2001 From: bjorn Date: Sun, 5 Jul 2026 17:39:15 +0200 Subject: [PATCH 3/5] docs: changelog for AddSymfonyConstraintValidatorTypeDeclarationsRector [#3600790] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8af98eb37..74f44f037 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ release-by-release. ## [Unreleased] +### Added + +- **`AddSymfonyConstraintValidatorTypeDeclarationsRector`** — adds the Symfony 8 / Drupal 12 type declarations (`mixed $value` and `: void` on `validate()`, `: void` on `initialize()`) to `Symfony\Component\Validator\ConstraintValidatorInterface` implementers. Backward compatible on all supported Drupal versions, so no version gate. [#3600790] + ## [1.0.0] — 2026-07-02 ### Changed From 8edc7ebf9817e5deff1ca7060c89bd9bb1b2db40 Mon Sep 17 00:00:00 2001 From: bjorn Date: Sun, 5 Jul 2026 17:45:23 +0200 Subject: [PATCH 4/5] test: add Constraint-only negative fixture for AddSymfonyConstraintValidatorTypeDeclarationsRector guard [#3600790] --- .../fixture/constraint_only.php.inc | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector/fixture/constraint_only.php.inc diff --git a/tests/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector/fixture/constraint_only.php.inc b/tests/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector/fixture/constraint_only.php.inc new file mode 100644 index 000000000..1a2e1d8b0 --- /dev/null +++ b/tests/src/Drupal12/Rector/Deprecation/AddSymfonyConstraintValidatorTypeDeclarationsRector/fixture/constraint_only.php.inc @@ -0,0 +1,13 @@ + From effdb31b522ec3f3c653edf41d77cb119316d33b Mon Sep 17 00:00:00 2001 From: bjorn Date: Sun, 5 Jul 2026 19:05:21 +0200 Subject: [PATCH 5/5] feat: add drupal-12-all aggregate set and Drupal12SetList::DRUPAL_12 [#3600790] --- config/drupal-12/drupal-12-all-deprecations.php | 16 ++++++++++++++++ src/Set/Drupal12SetList.php | 1 + 2 files changed, 17 insertions(+) create mode 100644 config/drupal-12/drupal-12-all-deprecations.php diff --git a/config/drupal-12/drupal-12-all-deprecations.php b/config/drupal-12/drupal-12-all-deprecations.php new file mode 100644 index 000000000..8f60c677e --- /dev/null +++ b/config/drupal-12/drupal-12-all-deprecations.php @@ -0,0 +1,16 @@ +sets([ + Drupal12SetList::DRUPAL_120, + ]); + + $rectorConfig->bootstrapFiles([ + __DIR__.'/../drupal-phpunit-bootstrap-file.php', + ]); +}; diff --git a/src/Set/Drupal12SetList.php b/src/Set/Drupal12SetList.php index 99660d830..f47d7768e 100644 --- a/src/Set/Drupal12SetList.php +++ b/src/Set/Drupal12SetList.php @@ -6,5 +6,6 @@ final class Drupal12SetList { + public const DRUPAL_12 = __DIR__.'/../../config/drupal-12/drupal-12-all-deprecations.php'; public const DRUPAL_120 = __DIR__.'/../../config/drupal-12/drupal-12.0-deprecations.php'; }