Closed (fixed)
Project:
Drupal core
Version:
11.x-dev
Component:
typed data system
Priority:
Critical
Category:
Task
Assigned:
Unassigned
Issue tags:
Reporter:
Created:
1 Nov 2025 at 14:12 UTC
Updated:
12 Jun 2026 at 10:50 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #2
godotislateSome of the work in MR 12291 for #3522497: Passing an $options array to constraint constructors is deprecated, use named arguments instead may be relevant.
Comment #4
longwaveNot sure what to do here. We immediately run into
ContextDefinitionInterface::addConstraint()also accepting an array of options:and there is also some magic in
ConstraintManager::create(), I assume this default$options['value']key is also deprecated now:Comment #5
longwaveI think we have to deprecate that magic
valuesetter whatever we do, so let's try solving that first.Comment #6
godotislateThere's handling for that
valuesetter in the other MR I did on the original issue, similar to what you have so far. One thing I found was the need to be able to know in constraint factorycreateInstance()that the value setter thing happened in config managercreate(). I'll try porting over some of that work piece by piece here and see how much it helps with the deprecations.Comment #8
godotislateInstead of what I said in #6, I tried bringing over the bulk of MR 12291 to see what deprecations it might fix and what tests are breaking.
One major change from there is change the new ConstraintBase class not to pass options to the Symfony Contraint class parent, like this:
Will investigate the test failures as it seems that might not completely work.
Comment #9
godotislateResolved some of the test issues, but some function test failures still remain.
For the MR removed all the deprecation ignore entries except for "%Since symfony/validator 7.4: Support for passing the choices as the first argument to Symfony\\Component\\Validator\\Constraints\\Choice is deprecated.%", even though this issue is technically about one. They're all closely related, so it might be difficult to address them all completely separately.
After that, still left to do is to double check that changes to certain constraints don't break BC, and adding test coverage.
Comment #11
godotislateWanted to make sure I tracked and resolved any errors related to the changes separate from deprecation warnings, so opened another draft PR 13741 to address actual failures and errors with BC. A bunch of tests are red bc I left out the changes to address the deprecation warnings, which I will add back in later.
Comment #12
godotislateTemporarily removed the check on the number of required parameters in a constraint constructor to find which constraint causes errors, and it's ExtensionName.
Comment #15
godotislateFinally got MR 13741 to all green.
Approach is this:
addConstraint()methods are annotated to accept only eitherNULL, empty array, or an associative array for$optionsConstraintManager::create()triggers a deprecation if the options passed are not NULL, empty array, or an associative array. The functionality there that adds the'value'key to a non-array and non-NULL value is deprecatedConstraintBaseclass is introduced that handles constructor argument juggling, so it can handle either named arguments being passed or, for BC, an$optionsarray being passed. This saves (for now) needing to add a constructor to every Drupal constraint class and doing the argument juggling thereComplexDataConstrainthas deprecated passing in the options without the'properties'keySome future considerations:
addConstraint()methods, as well as adding constructors with property arguments to every constraint class. One outstanding question is what major this should happen in: it might be a lot of work for contrib/custom modules to be updated by D12, but if D12/Symfony 8 has removed the BC support for the $options array entirely, then D13 might be too far away. Unless for D12, theConstraintBaseclass is updated to take over the BC support from the Symfony Constraint classOther notes:
ConstraintBase(and other constructor changes) works as expected for BCComment #16
longwaveThanks for working on this, on a first review the changes generally look good.
In two minds whether we want to introduce ConstraintBase here; given Symfony recommends initializing properties in the constructor should we just go down that route? Unsure how many custom constraint plugins there are in contrib/custom code, but I can't imagine it being too many. If we want parity with Symfony to remove
$optionssupport and get rid of ConstraintBase eventually, maybe we just don't introduce it in the first place.Comment #17
godotislateMy thinking for introducing the new base class is to avoid having to add a constructor that has to do parameter juggling for every core constraint class right now , and then having to remove all that constructor parameter juggling later in the major branch. With the base class, most of the individual constructors only need to be touched once later.
For example, if we did the constructors now, this is is what FileSizeLimitConstrait would look something like:
And we'd have to do something similar to that (some easier, some more complicated, depending on how many properties a constraint has and whether the properties can have array values) for every constraint class.
But I'm also of two minds of whether going with the base class is a good idea, and what the future of the base class would be is a good question. Do we get rid of it? (Or maybe we use it to bring constraints more in line with other Drupal plugin types by implementing PluginInspectionInterface? Not sure what that gets us though other than access to the plugin ID and definition. Just throwing out ideas.)
Comment #18
longwaveCan we do this simpler pattern everywhere? Symfony seems to do this (in some places at least)
Comment #19
godotislate#18 looks like it should work for most cases, except weird ones like ComplexDataConstraint, but that is weird regardless of how we want to do it.
Also the edge(?) case if someone does something like
->addConstraint('FileSizeLimit', ['value' => 100]), but maybe we can just document not to do that in the CR.If we update every constructor, do we want do any BC testing? Do we just pick a random sample? My plan on testing BC with the base class was to create a few test constraint classes that extend the base class and cover the various conditions in
ConstraintFactory::createInstance(). As well as perhaps coverage for the few specific classes that have constructor changes.Just checking before I go update or add 68 constructors...
Comment #20
longwaveI don't think we need to provide tests for every single case, maybe we can do a sample of the more commonly used constraints?
Worth making this into yet another branch I think so we can compare approaches as well! I know this is a huge amount of work and hassle so thanks for taking it on!
Comment #22
godotislateOK, did individual constructors in MR 13811, and tests are finally green. Still need to do tests for both MRs. I also did property promotion for the *message* properties, because it was possible previously to override the message text via the options array, even if not common. There were examples of this happening in core/core test code, so it should still be possible now.
Comment #24
godotislateI updated the IS with details about the two approaches in the MRs, as well as pros/cons that I think each have.
I'm moving this to NR now to try to get consensus on which approach to take before writing the relevant tests for either approach.
Comment #25
quietone commentedThen let's tag it for framework and rm review.
Comment #26
kim.pepperAdded #3561135: Deprecate passing options array to UploadedFileConstraint as I think this was missed due to it not being a plugin.
Comment #27
godotislateOne thought I just had about possible growing use of named parameters generally, and not just for constraint classes:
For classes where there's a reasonable expectation for named parameters to be passed to their constructors, the named parameters kind of implicitly become API, resulting in some tension with the documented BC policy. This is especially exacerbated since passing named parameters that don't exist will cause fatal errors.
I wonder if we can make this a bit easier generally by making these constructors variadic, with a
...$otheror similar parameter used widely. The parameter doesn't have to correspond to any class properties, or technically be used at all. It's just there to allow named parameters to be passed with backward for forward compatibility. I grant that it seems a little ugly, but maybe worth considering?Comment #28
longwaveThe individual constructors and
HasNamedArgumentsapproach is obviously the way Symfony wants us to go, and I think it's worth the pain of synchronising with them. There is churn for downstream users either way because they can't do nothing, at a minimum they have to swap to the new ConstraintBase class - we will surely want to get rid of this eventually so we might as well make them go through this pain once instead of twice? Core provides a lot of validators (and is adding more with the ongoing config schema work) but I am not sure how widely added they are in contrib or custom code.Unfortunately the deprecations need updating to 11.4 now.
Comment #29
godotislateSounds good. Will rebase and update MR 13811 and have ready for review hopefully by early next week.
Tagging for IS update based on #28.
Not sure about contrib, but custom validators have been a regular part of projects I've worked on, especially those having custom entity types or field types. Or situations where the value of one field is constrained by other fields. Maybe we can search "extends Constraint" or "extends SymfonyConstraint" to get an idea of number of contrib constraints.
Either way, since we missed 11.3, the runway between 11.4 and 12.0 might be short, so getting this in early is ideal.
Comment #32
godotislateComment #33
godotislateComment #34
godotislateRebased and updated the deprecation message version. Also Updated the IS.
Still TBD
Add BC tests for a selected/representatve set of constraint
Update CR to include deprecations for
addConstraint()method parameters and any other relevant changesComment #35
godotislateI was thinking about the best way to write the BC tests, and then took a break for holidays. I will revisit as soon as I can, though I certainly welcome anyone else writing some constraint plugin BC tests.
Comment #36
godotislateFinally got back to this. Added BC tests, but I decided only to test Drupal constraint plugins whose
getDefaultOption()method returns a non-null value. This is so that I could test passing values other than non-associative arrays as$optionstoConstraintManager::create(). This simulates passing non-associative array options to all theaddConstraint()methods.For other constraint plugins, passing non-associative array values to
addConstraint()should have already been resulting in error to date, so I think testing the constructor changes are of lesser importance. The possible BC issue is if there are contrib/custom projects that implement their own constraint manager or constraint factory, but I think it's fairly low risk?Will review and update CR tomorrow.
Also tagging "Needs followup" to deprecate implementations of
getDefaultOption()andgetRequiredOptions()in Drupal constraint plugins, since those methods are deprecated in the SymfonyConstraintclass. Deprecating those are probably lower priority because with base methods removed in Symfony 8, they'll effectively will never be called.Comment #37
godotislateUpdated the CR to include notes about the method signature changes to all the
addConstraint()methods andConstraintManager::create().Also stubbed these follow ups:
#3569092: Update method signatures for addConstraint() and ConstraintManager::create() and remove HasNamedArguments use
#3569093: [12.x] Remove getDefaultOption() and getRequiredOptions() methods in Drupal Constraint plugin classe
#3569096: Remove BC layer $options argument from Constraint plugin constructors
Cleared the respective issue tags and updated the IS to reflect current state.
Comment #39
longwaveThanks again for keeping up with this. Added some questions to the MR but I think this is close, and we should try and get it in ASAP - this is the biggest blocker to the
mainbranch Drupal 12 upgrading to Symfony 8.Given the complexity of this subsystem, if you are doing this I think you are on your own and we can't promise BC. I don't immediately see a reason why anyone would even try something like this.
TBH I think we could hopefully just delete these implementations in D12 given Symfony itself is removing them from the interface, again if you were doing something with these directly then you are probably doing something non-standard and it's your problem to solve.
Comment #40
godotislateAgreed. Changed the follow up to be a removal instead of deprecation: [##3569093].
I think I addressed the latest MR comments. I also had to make some changes for new constraints upstream.
Comment #41
godotislateThinking about this some more, I wonder if we can just drop the
$optionsBC argument now from the constructors of all these constraint plugins (the ones that return NULL fromgetDefaultOption()). The only BC break I can think of is if there are any contrib or custom subclasses that implemented their own constructor and called the parent constructor,but in those cases, we're already changing the constructor signature and breaking that already.Edit: maybe not? since I imagine not many are passing the
$payloador$groupsargument.If there's any reason to keep the
$optionsargument, I'm all for it, since I'm not overly eager to update a whole bunch of constructors again right now, but they'll have to be removed eventually, so it might make sense to just do it if we can.Comment #42
longwaveSymfony removed the $options argument and the options methods at the same time: https://github.com/symfony/validator/commit/1d7117a57add22f42edef20a8219...
Perhaps we should just do the same thing - get this into Drupal 11 then make those changes early in D12?
No further comments on the MR, I think this is ready now.
Comment #43
larowlanGreat work! Just one issue with ComplexDataConstraint and property collision
Comment #44
godotislateReplied to MR comment. I think this isn't a regression, but we can handle in a follow up.
Comment #45
longwaveThanks for the explanation, I agree with the analysis; fwiw it would have been fine for you to set this straight back to RTBC.
Comment #46
longwaveOver in #3570077: Update to Symfony 8 I opened a trial MR with Symfony 8, there are some validator unit test failures:
https://git.drupalcode.org/issue/drupal-3570077/-/pipelines/726284/test_...
Haven't looked at the detail yet.
Comment #47
longwave#46 is a false positive; we need to remove the BC layer in
ConstraintFactory::createInstance()when we upgrade to Symfony 8, as the#[HasNamedArguments]attribute is removed.Comment #48
godotislateUpdated #3569096: Remove BC layer $options argument from Constraint plugin constructors to include removing the
#[HasNamedArgument]use as well as the BC layer in ConstraintManager/ConstraintFactory.Comment #49
larowlanNeeds a reroll after #3555532: Since symfony/http-foundation 7.4: Request::get() is deprecated, use properties ->attributes, query or request directly instead. - fine to self RTBC
Comment #50
godotislateStubbed a followup for the
propertiesthing: #3570464: ComplexDataConstraint does not work correctly with typed data having a property named propertiesComment #51
godotislateRebased so back to RTBC.
Note that the only conflict was in .deprecation-ignore.txt.
Comment #52
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #53
godotislateShushing the bot. Back to RTBC.
Comment #56
larowlanCommitted to main - thanks folks!
Comment #59
larowlanBackported to 11.x and published CR
Comment #60
godotislateNow that this is in, the D12 follow up/Symfony 8 blocker is ready for review: #3569092: Update method signatures for addConstraint() and ConstraintManager::create() and remove HasNamedArguments use
#3569096: Remove BC layer $options argument from Constraint plugin constructors is lower priority since Symfony 8 has kept the
$optionsparameter around. It just does nothing.Comment #61
wim leersCanvas validates many things very thoroughly. In doing so, it seems to trigger a higher number of deprecation notices than most projects: here's an example with ~6000 deprecation notices or a >1 MiB large subject string to check the expected deprecations against … which makes
preg_match()fail incorrectly 🤯🧟See: https://git.drupalcode.org/project/canvas/-/merge_requests/280#note_674164.
Work-around: only check unique deprecation notices: https://git.drupalcode.org/project/canvas/-/merge_requests/280#note_674181
Note that this only happens if your
core/phpunit.xmldoes not haveSYMFONY_DEPRECATIONS_HELPERconfigured to eitherdisabledor not at all (i.e. using the default). An ignore file does NOT help.Note that simply changing https://www.drupal.org/project/gitlab_templates' default of
SYMFONY_DEPRECATIONS_HELPER: disabledand instead settingSYMFONY_DEPRECATIONS_HELPER: "ignoreFile=$CI_PROJECT_DIR/$_WEB_ROOT/core/.deprecation-ignore.txt"causes it to fail the same way on GitLab CI: https://git.drupalcode.org/project/canvas/-/jobs/8388370#L1117Comment #63
ptmkenny commentedJust to note, I think that the fix here has a couple issues for 11.4.x, which I have reported here: #3599189: Some deprecation messages are missing E_USER_DEPRECATED