-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Add support for deprecated definitions #15491
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
Conversation
Aren't services lazy loaded? You could get away with just putting the This won't work for factories, etc… though |
A And as services are indeed lazy-loaded, this trigger should happen only if you indeed use this service. so I think this is at the right place. I may be wrong though :} |
btw, the fabbot errors (and the php7 build error) have some errors that I will soon correct, but most of them are not coming from me :{ |
What about easily suppressible (and collectible) notices upon building the container or when initializing the container? |
Then I guess the notice would be fired only once when building the container, no ? Shouldn't the error be triggered at each use (or injection), so that everything can be tracked ? |
Finding the usage of a service is usually the easy part. |
I'm 👎 on this, IMO the container shouldn't be aware of the how to handle the deprecation of services, this is out of the scope of the component. |
@dosten but the framework bundle can, the component doesn't have to know about it. |
Fixes #14307 |
* | ||
* @return bool | ||
* | ||
* @api |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC, things shouldn't be tagged as @api
in PRs. And, btw, the class is already API so there is also no need.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ported the tags from the abstract behaviour, but I can remove those if it's too soon to put them here
Oh, didn't see the issue, so I'll add it in the PR header, as this is exactly what this PR aims to implement. As for the idea to implement it only in debug mode (In the debug component or the debug bundle ?), I'll need to check those to see how it can be implemented. |
2313a67
to
17a72c0
Compare
* | ||
* @api | ||
*/ | ||
public function setDeprecated($boolean = true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer using $deprecated instead of $boolean as variable and the default value here doesn't make sense.
I like this PR (as much I liked the linked issue :) ) |
I like this feature (it will also allow us to remove the request-specific hack in the current codebase in the container btw). When documenting it, we should however make it clear that when you are deprecating a class, you should trigger the deprecation the class itself, not in the service (so that it works for any usage of the class, not only for the usage as service). Deprecated services should be used only when the class itself is not deprecated. And should we also support marking aliases as deprecated ? |
@stof so that all the aliases that points out to the deprecated service are also marked as deprecated (or at least trigger a deprecated error) ? I like that. But yes, the scope of such a tag / attribute would really be to deprecate the service, not if the class is deprecated (both at the same should be possible though), e.g if the service was renamed. I think this is a bit different. I could also add this tag / attribute on the alias tags, WDYT ? So that if an alias is created because it was a deprecated name for the service it points to, so this usage triggers the error |
@Taluu no. this would happen automatically as it would get the service itself. Deprecating an alias would be there in case you want to deprecate only the alias, but keeping the new name not deprecated. This would cover the case of renaming services and keeping an alias with the old name for BC (yes, it should be an alias otherwise you end up with 2 different unrelated services) |
@Taluu the ContainerBuilder should also trigger deprecation errors when trying to instantiate a deprecated service from it (i.e. for the case where you are not dumping the container) |
@@ -844,6 +844,10 @@ public function setDefinition($id, Definition $definition) | |||
|
|||
$id = strtolower($id); | |||
|
|||
if ($definition->isDeprecated()) { | |||
@trigger_error(sprintf('The service %s relies on a deprecated definition. You should avoid using it.', $id), E_USER_DEPRECATED); | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be enough on the container builder or should I put it somewhere else ? cc @stof
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't it make more sense to move this to getDefinition()?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is also what I thought, but maybe then port it into the container itself ? Or should it be enough in the builder only ?
I added the possibility to set a custom deprecation message when using the deprecated feature. /cc @nicolas-grekas @stof |
$return[] = ''; | ||
} | ||
|
||
$return[] = '@deprecated'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you could append the message here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch ! I'll add it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ping @Taluu
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reverted the change I made here, as after a second thought, I don't think it has any sense to add the same message of the trigger error (@deprecated The service %s is deprecated. You should stop using it, as it will soon be removed
).
I think a message following a @deprecated
should not be the same . it should states from which version it is deprecated (vX.Y.Z
), eventually a replacement (using something else instead). Not a generic message, like the one thrown in the triggered error.
And I don't think adding yet another template would be that good though...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And also not adding the message provides us a way to avoid having to handle a case where there is a */
in the message, which could break everything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, my arg may not be the best, but we should think in reverse: what would be the argument for NOT putting the message here? @Taluu has two:
- the default message is not really useful
- issue with
\r
,\n
,*/
These are good ones but I gave counter arguments:
- recommend overwriting the default message in the doc
- forbid the special chars
Which imo means we have no more args for NOT putting the message here. Unless I missed something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having a recommandation does not erase the fact that the default message is not useful enough to be put here. Having a recommandation is saying "you should, not you must....
I could then make the default message optionnal AND if it is null, use the default. Then in the @deprecated
part, if the "message" is not null, then add it here... But doesn't that honestly seem overkill ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sorry but I don't see the blocker for putting the default message here. It wouldn't be a mistake, and we provide a way to have a better one.
If I go up to your arguments, then I would recommend to remove the default message completely and force deprecation authors to always provide one. That being for this use case or for the trigger_error below, or anywhere else we use the message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added back the message if it was customized (if it was provided through the setDeprecated
method). If none was found, I still think we shouldn't add it, and the original message is returned. I just escaped the */
though, even if I don't think it is really pretty here...
I also don't think we should forbid \n
, \r
and */
in the message... The end user should be able to use those as he pleases, especially as in all the trigger_error it doesn't make any problems to leave those as they are...
This is kind of acrobatics but meh. I'll add the recomandation into the docs as you suggested though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the end of the story, I changed my mind as I discussed with @nicolas-grekas, and we'd rather be stricter than necessary to be able to loose up the thing is needed.
Basically, I am now checking if the given template is valid enough (not containing \r
, \n
, */
symbols, and if provided, must contain %service_id%
variable). In the XML and YAML dumpers, I also dump with %service_id% as its "id" instead of
$id`, to be sure that the variable is there on the dump.
I'll update the docs saying that it is recomanded to change the deprecation message to be adapted on the specific use-case where the deprecation is activated.
ping @symfony/deciders |
@@ -81,6 +81,7 @@ | |||
<xsd:element name="argument" type="argument" minOccurs="0" maxOccurs="unbounded" /> | |||
<xsd:element name="configurator" type="callable" minOccurs="0" maxOccurs="1" /> | |||
<xsd:element name="factory" type="callable" minOccurs="0" maxOccurs="1" /> | |||
<xsd:element name="deprecated" type="xsd:string" minOccurs="0" maxOccurs="1" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be a boolean, not a string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It has to receive the deprecation message, not a flag ; this is a xml element
<deprecated>This service is deprecated</deprecated>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was confused by the difference between the YAML and XML syntax (see my other comment).
Apart from the small comment about the XSD, 👍 |
@@ -76,6 +76,10 @@ services: | |||
class: stdClass | |||
decorates: decorated | |||
decoration_inner_name: decorated.pif-pouf | |||
deprecated_service: | |||
class: stdClass | |||
deprecated: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to define deprecated
and deprecated_template
? Why not do the same as for XML and just define deprecated
with the message as the value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The deprecated_template
is actually optionnal (as in the XML), you can use only deprecated
which is basically a flag.
In XML, there wasn't any point of having a boolean attribute (as it was the case before I added the message customization) and a tag, while only a tag could do the trick. The thing is, even if the tag has a xsd:string
type, it should be able to accept no value at all (its only presence marks the service as deprecated) : <deprecated />
(then the message template will be the generic default one) .
Having two members in the yaml (and the php too) allows us to override the flag or even use the default message without specifying the deprecated_template
part, and just use the flag part. But as I noted in the PR, I still haven't found how to override this deprecation in XML...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But then, for YAML and XML, I could merge the two attributes (allowing a null
value to use the default message), and just the presence of deprecated
be enough to mark the service as deprecated...
But then again, we wouldn't be able to override the deprecation status in a inherited / decorated service, as it is currently the case in XML
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think providing a way to override the deprecation status in inherited services is a good thing, I would even not allow that at all. Having just one deprecated
entry sounds better to me in all supported formats.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then in PHP we would still have one (or two) arguments : $container->setDeprecated(true, 'message template %service_id');
But I think that in PHP, it should be okay to allow more customization, unlike in XML or YAML. I'll make the change then, it would be easier to allow more customization rather than restrict it afterwards.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fabpot I changed the key then, and only allow a deprecated
key in a YAML service configuration file. If it is present, then the service is marked as deprecated (and so are services decorating or extending this service).
But I was wondering if the naming was appropriate for XML and YAML. Wouldn't be deprecation
better then ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
deprecation
in my opinion sounds better
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed that deprecated is better
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
deprecated
it is then.
82ae5a3
to
c188e6b
Compare
@@ -76,6 +76,9 @@ services: | |||
class: stdClass | |||
decorates: decorated | |||
decoration_inner_name: decorated.pif-pouf | |||
deprecated_service: | |||
class: stdClass | |||
deprecated: The "%service_id%" service is deprecated. You should stop using it, as it will soon be removed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add test with deprecated: true
(without overwrite default deprecation message)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It already supports the null
value (or ~
), but I can also add true
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we give a special meaning to "true", then we should also add one to "false". But we don't want to allow "false". Thus I wouldn't allow "true". The expected value is either a deprecation message template, or null (which is not recommended: the best practice is to set a more contextual message)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough.
c188e6b
to
0c31716
Compare
0c31716
to
83f4e9c
Compare
ping @symfony/deciders |
@Taluu Can you fixed fabbot issues? |
I can't, this is due to ExpressionLanguage (and it is not a change I made) : https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php#L52 This is due to the concatenation in the container fixture file. but if I have to remove those spaces, wouldn't the ExpressionLanguage still convert those with a space between the dots ? |
Thank you @Taluu. |
This PR was merged into the 2.8 branch. Discussion ---------- Add support for deprecated definitions | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #14307 | License | MIT | Doc PR | symfony/symfony-docs#5689 This add a sort of marker in the Definition of a service that marks it as "deprecated". This is useful when we have a bunch of service and a bunch of where it is used, and we need to track if there are any uses before removing it (in a later version or right now). I was not sure if the `trigger_error` would be enough, or if I should log them instead. I'm first gathering some feedback, and then I'll try to update the doc. I was not sure if it should target 2.8 or master (3.0) though. What's left ? ========== - [x] Make a POC - [x] Gather some feedbacks - [x] Dump the tag in XML, YAML and PHP - [x] Load the definition from XML, YAML and PHP - [x] Fix some forgotten things such as the key existence check - [x] Work on inline services in the php dumper - [x] Handle deprecations for decorators - ~~Possibility to overwrite the deprecated flag in the decorators in `XmlFileLoader` ?~~ Nope, and this behavior is also ported to the `YamlFileLoader`. Commits ------- 83f4e9c [DI] Support deprecated definitions in decorators 0b3d0a0 [DI] Allow to change the deprecation message in Definition 954247d [DI] Trigger a deprecated error on the container builder 2f37cb1 [DI] Dump the deprecated status 8f6c21c [DI] Supports the deprecated tag in loaders 4b6fab0 [DI] Add a deprecated status to definitions
@fabpot could you make fabbot ignore fixture files ? |
@Taluu would you like to open an other PR that adds tags to deprecated services?
|
I'll take a look when I'll have some time if needed (But I guess doing it step by step would be easier and faster). For the controller, I don't think it should be up to this feature, as this is not really a service (just a way to access the current request which should be injected as a parameter). But that would be another story for the request service for example (I think it is still around until 3.0, no ? didn't check) |
… (Taluu) This PR was merged into the 2.8 branch. Discussion ---------- [DI] Add some documentation for the deprecation feature | Q | A | ------------- | --- | Doc fix? | no | New docs? | yes symfony/symfony#15491 | Applies to | 2.8+ | Fixed tickets | ~ Document the deprecation feature I introduced in symfony/symfony#15491 Commits ------- 1e1b036 [DI] Add some documentation for the deprecation feature
public function setDeprecated($status = true, $template = null) | ||
{ | ||
if (null !== $template) { | ||
if (preg_match('#[\r\n]|\*/#', $template)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Taluu : sorry for digging this up but… isn't there any way this could strip out carriage returns and trim indention instead of refusing carriage returns? This gives very long lines
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I recall correctly, it was @nicolas-grekas's idea to forbid these characters, but I can't find his comment (had just a quick look).
IMO, it shouldn't be this long, or otherwise it's too much information...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the reply, what do you mean by "too much information"? Is there a limit to what the profiler can display? In my case, of I don't provide that much info, I'm afraid people won't be able to migrate w/o opening issues. Plus, it doesn't take much to be above 120 characters given the amount of indention in this tag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not that I know, but IMO a deprecation message should only state that the thing is deprecated (since when), and what to use as a suggestion (not why or how). This should be done in an upgrade file.
But then it's not really an obligation either...
If I remember correctly, the behavior you're suggesting (striping the carriages returns) was what was done in the first place, but @nicolas-grekas wanted to be stricter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do have an upgrade file in our project, so I guess I will put all the details in it
This add a sort of marker in the Definition of a service that marks it as "deprecated". This is useful when we have a bunch of service and a bunch of where it is used, and we need to track if there are any uses before removing it (in a later version or right now). I was not sure if the
trigger_error
would be enough, or if I should log them instead.I'm first gathering some feedback, and then I'll try to update the doc.
I was not sure if it should target 2.8 or master (3.0) though.
What's left ?
Possibility to overwrite the deprecated flag in the decorators inNope, and this behavior is also ported to theXmlFileLoader
?YamlFileLoader
.