Problem/Motivation
Upgrading to Symfony 5.1 has revealed two new deprecation messages:
Since symfony/dependency-injection 5.1: The signature of method "Symfony\Component\DependencyInjection\Alias::setDeprecated()" requires 3 arguments: "string $package, string $version, string $message", not defining them is deprecated.
Since symfony/dependency-injection 5.1: The signature of method "Symfony\Component\DependencyInjection\Definition::setDeprecated()" requires 3 arguments: "string $package, string $version, string $message", not defining them is deprecated.
We only allow a single message to be set as the "deprecated" key for services and aliases, but Symfony now breaks this out into the package, version and message.
This also ties in with Symfony's new trigger_deprecation()
function which accepts the same three arguments.
Steps to reproduce
Upgrade to Symfony 5.1 and run any test involving the DI container.
Proposed resolution
We could set the package automatically via the _provider
tag as we know which module a service definition belongs to.
We could try to parse the version out of the message, as we have a standard format? We can't guarantee this will be used but we could fall back to empty string/null if we can't parse it?
Or, we could deprecate the single deprecated
key and add separate version and message top level or child keys.
Also consider if we want to adopt Symfony's trigger_deprecation()
elsewhere in core (out of scope for this issue).
Remaining tasks
User interface changes
API changes
Data model changes
Release notes snippet
Comment | File | Size | Author |
---|---|---|---|
#18 | interdiff.3187857.16-18.txt | 1.06 KB | longwave |
#18 | 3187857-18.patch | 3.39 KB | longwave |
Comments
Comment #2
longwaveComment #3
BerdirDeprecation on a deprecation method? That is very meta :)
Comment #4
catchI think we should probably go for this option.
This seems like a good bc layer. We could potentially even fall back to the current version of the provider too?
One annoyance here is that there's only version for the since bit of the message, there's no 'will be removed in %version' bit, so it's not compatible with our format (and nor is trigger_deprecation()).
Comment #5
catchOK thinking about it, this is more of a blocker than an annoyance.
Here's what a service deprecation currently looks like:
vs. the message that trigger_deprecation() generates:
https://github.com/symfony/deprecation-contracts/blob/main/function.php
So this change means we cannot use the container's deprecation functionality with the deprecation format that's in our coding standards.
This leaves several options:
1. Change the deprecation format to match Symfony's, only for service definitions.
2. Change the deprecation format to match Symfony's everywhere.
3. Re-implement service deprecation in our container subclasses to preserve existing functionality.
4. Try to make trigger_deprecation() more flexible upstream - for example adding a $removed_in version
#1 and #2 we can add the information that trigger_deprecation() is missing to the rest of the message string, but it loses us our current standard format.
Comment #6
longwave#1 feels inconsistent
#3 feels like a lot of work for not much gain - we don't currently extend Symfony's Definition or Alias objects which I think we would have to do here? Or we could do it outside of those classes, but that feels even more messy.
#4 unsure if upstream would accept this as it's probably not much use to them
This leaves #2 which would also let us use Symfony's
trigger_deprecation()
instead of callingtrigger_error()
manually, which might be a nice DX improvement? It does lose the "removed in" version though, but does that matter? If someone receives a deprecation message they can surely just assume the target version is the next major?As an aside, Symfony's
trigger_deprecation()
is wrapped inif (!function_exists('trigger_deprecation'))
so we can probably provide an override with a Symfony-compatible layer if we wanted to.Having said that...
Can we just leave everything as-is and call
->setDeprecation('', '', $message)
? $package and $version are allowed to be empty in both the method and the function, does defining them really add any value to us?Comment #7
catchWe've moved some deprecations to $next_major_version + 1 in the past, such as #3109480: Properly deprecate theme functions for Drupal 10 and #3113284: Move deprecation of REQUEST_TIME to Drupal 10. There are also issues for drupal check/upgrade status (which I can't find right now) to exclude far-future deprecations like that from reports - so that module authors can focus just on incompatibilities with the upcoming major release.
Having said that, we can put the removed in version in the message string - as long as we can make it fit grammatically, it doesn't have to be done as an arg. And trigger_deprecation() has an arbitrary $args argument for replacements which would allow us to do that elsewhere. Maybe Symfony would be open to adding an $args to setDeprecated() too.
Ah! I like this idea very much and think we should at least do that here to unblock Symfony 5/6, we can open up a follow-up for using trigger_deprecation() more generally.
One issue with that is we can't actually make that change until we're on Symfony 5, so it'd need to be a Drupal 10-only patch (although we could still have the patch ready).
Comment #8
longwaveThe problem now is that this deprecation was added in Symfony 5.1, so Symfony 4.4 still has the old signature:
If we can find a consistent way to detect Symfony 4 vs 5/6 we can call the method in different ways, I guess.
Comment #9
longwaveThe
getDeprecation()
method looks like a suitable candidate for detection.Comment #10
catchI was thinking about reflection maybe, but just checking that method seems fine - it's all internal and just a couple of places.
Comment #11
longwave#3161889-100: [META] Symfony 6 compatibility shows this works with Symfony 5 as well.
Comment #12
catchI've opened a Drupal 10 follow-up, and the 'Symfony 4/Symfony 5' comments are very googleable. Thought about what a longer comment might look like, but it'd just be describing what the code is doing, and we'd need to repeat it three times, what we have seems enough.
I think this is ready to go.
Comment #13
longwaveThe other option I thought of is "@todo Remove this in [...] when we no longer support Symfony 4.x" or similar above the else clause, which has a bit more explanation, but I think it's clear enough as is.
Comment #14
ilgnerfagundes CreditAttribution: ilgnerfagundes at CI&T commentedI applied the patch and for me everything is correct, rtbc +1
Comment #15
alexpottI discussed the version detection a bit more with @catch - I don't think the method_exists() check is elegant - but I can't come up with anything better so it seems fine.
I wonder though if we should consider changes to support package and version. Upstream YamlFileLoader does this...
Imo we could do:
To at least support Symfony's expected format for Sf5 (and 6). To me this is helpful because when someone reads Symfony docs about deprecating services then they will work for Drupal too. (Which feels more important than the the actual structure of the message)
Comment #16
longwaveWe've used the method_exists() test for major version compatibility shims elsewhere including Composer, Symfony BrowserKit and PHPUnit - it's never very clean but it's often the simplest way as there usually isn't a way to get the version of a dependency directly.
Updated with the suggestions from #16, and updated the inline comments to use @todo and link to the removal issue now it exists. Also set the package and version for
cache.null
in UpdateServiceProvider, which should probably have been removed in the D9 cycle - now the version is set we have more chance of picking it up in D10.Comment #17
alexpottI think this should be the package - ie. drupal/core
Comment #18
longwaveOK.
Comment #19
catchSeems OK to support the Symfony format while not actually using it. So back to RTBC for me.
Comment #20
alexpottCommitted 47344ca and pushed to 9.2.x. Thanks!
Comment #22
andypost