Add AddSymfonyConstraintValidatorTypeDeclarationsRector (Symfony 8 / Drupal 12 validator type declarations)#407
Conversation
… drupal-11 floor and new drupal-12 sets [#3600790]
…lidatorTypeDeclarationsRector guard [#3600790]
Live test resultsRan Ground-truth match — for the
Other modules (all correct):
Both class shapes ( (No PHPStan deprecation-coverage entry applies here — this rule is matched by interface implementation and tightens signatures, not a deprecated-symbol rewrite, so it emits no PHPStan deprecation message.) |
Summary
Adds
AddSymfonyConstraintValidatorTypeDeclarationsRector, a new rule that gives SymfonyConstraintValidatorInterfaceimplementers their Drupal 12 / Symfony 8 type declarations:validate()— addsmixedto param 0 (when untyped) and a: voidreturn (when absent)initialize()— adds a: voidreturn (when absent)It matches any class that is a
Symfony\Component\Validator\ConstraintValidatorInterface— coveringextends ConstraintValidator, directimplements, and the legacyextends Constraint implements ConstraintValidatorInterfaceself-validating pattern.Surfaced by redirect's automated Drupal 12 work (project/redirect!200), which made exactly these edits to
UniqueHashValidatorandSourceLinkTypeConstraint. Affects many contrib modules and wasn't handled by any automated tool yet.Issue: #3600790
Backward compatibility
No version gate /
DeprecationHelper— the change is backward compatible on every supported Drupal version. A child class may declare a return/param type its interface does not (Drupal core itself shipsvalidate(mixed $value, Constraint $constraint): voidwhile running on a Symfony 7.4 interface without the native: void); addingmixedis contravariant-widening (and Symfony 7 already declaresmixed $valueon the interface). Validators return nothing by contract, so: voidis a runtime no-op.Deliberately not matching
Constrainton its own: its methods (validatedBy(),getTargets(), etc.) have been typed since Symfony 7.4, so any untyped override already fatals on Drupal 11 — there are no real targets there.Placement
Registered in the Drupal 11 floor set (
^11.0, so every D11 install picks it up and modules can adopt the types while still supporting D11) and a new Drupal 12 set (^12.0, covering installs already on 12 that same-major matching excludes from the D11 sets). Same rule in both; idempotent, so double coverage is harmless. Adds the firstDrupal12scaffolding (Drupal12SetList,config/drupal-12/,DrupalSetProviderwiring).Testing
extends ConstraintValidator; legacyextends Constraint implements ConstraintValidatorInterface; already-typed (idempotency no-op); a non-validator class (type-guard negative); and aConstraint-only class with an untypedvalidate()(proves the guard does not fire onConstraintalone).stubs/(classmap-autoloaded) soisObjectTyperesolves.