Thanks to visit codestin.com
Credit goes to github.com

Skip to content

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

Merged
merged 6 commits into from
Sep 25, 2015
Merged

Conversation

Taluu
Copy link
Contributor

@Taluu Taluu commented Aug 7, 2015

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 ?

  • Make a POC
  • Gather some feedbacks
  • Dump the tag in XML, YAML and PHP
  • Load the definition from XML, YAML and PHP
  • Fix some forgotten things such as the key existence check
  • Work on inline services in the php dumper
  • 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.

@apfelbox
Copy link
Contributor

apfelbox commented Aug 7, 2015

Aren't services lazy loaded? You could get away with just putting the trigger_error in the constructor of the service.

This won't work for factories, etc… though

@Taluu
Copy link
Contributor Author

Taluu commented Aug 7, 2015

A trigger_error could be used in the constructor indeed (except factories then), but my first goal was also to use a deprecated tag (or php and yaml equivalents) to suggest another service to use instead.

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 :}

@Taluu
Copy link
Contributor Author

Taluu commented Aug 7, 2015

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 :{

@linaori
Copy link
Contributor

linaori commented Aug 7, 2015

What about easily suppressible (and collectible) notices upon building the container or when initializing the container?

@Taluu
Copy link
Contributor Author

Taluu commented Aug 7, 2015

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 ?

@linaori
Copy link
Contributor

linaori commented Aug 7, 2015

Finding the usage of a service is usually the easy part.

@dosten
Copy link
Contributor

dosten commented Aug 9, 2015

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.

@linaori
Copy link
Contributor

linaori commented Aug 10, 2015

@dosten but the framework bundle can, the component doesn't have to know about it.

@wouterj
Copy link
Member

wouterj commented Aug 10, 2015

Fixes #14307

*
* @return bool
*
* @api
Copy link
Member

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.

Copy link
Contributor Author

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

@Taluu
Copy link
Contributor Author

Taluu commented Aug 10, 2015

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.

@Taluu Taluu changed the title [WIP / POC] Add support for deprecated definitions Add support for deprecated definitions Aug 10, 2015
@Taluu Taluu force-pushed the container-deprecated branch from 2313a67 to 17a72c0 Compare August 10, 2015 09:29
*
* @api
*/
public function setDeprecated($boolean = true)
Copy link
Contributor

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.

@nicolas-grekas
Copy link
Member

I like this PR (as much I liked the linked issue :) )
I don't think the debug mode should influence the generated container. At least all other places that trigger deprecations are not sensitive to the env.
@iltar is right but that's out of scope for this PR: we need a way to collect early deprecations that happen before the error handler (=deprecation handler) is set up.

@stof
Copy link
Member

stof commented Aug 10, 2015

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 ?

@Taluu
Copy link
Contributor Author

Taluu commented Aug 10, 2015

@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

@stof
Copy link
Member

stof commented Aug 10, 2015

@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)

@stof
Copy link
Member

stof commented Aug 10, 2015

@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);
}
Copy link
Contributor Author

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

Copy link
Member

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()?

Copy link
Contributor Author

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 ?

@Taluu
Copy link
Contributor Author

Taluu commented Aug 10, 2015

I added the possibility to set a custom deprecation message when using the deprecated feature. /cc @nicolas-grekas @stof

$return[] = '';
}

$return[] = '@deprecated';
Copy link
Member

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

Copy link
Contributor Author

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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ping @Taluu

Copy link
Contributor Author

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...

Copy link
Contributor Author

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.

Copy link
Member

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.

Copy link
Contributor Author

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 ?

Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

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.

@nicolas-grekas
Copy link
Member

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" />
Copy link
Member

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.

Copy link
Contributor Author

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>

Copy link
Member

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).

@fabpot
Copy link
Member

fabpot commented Sep 22, 2015

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
Copy link
Member

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?

Copy link
Contributor Author

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...

Copy link
Contributor Author

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

Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

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 ?

Copy link
Member

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

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deprecated it is then.

@Taluu Taluu force-pushed the container-deprecated branch 2 times, most recently from 82ae5a3 to c188e6b Compare September 23, 2015 13:09
@@ -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.
Copy link
Contributor

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)?

Copy link
Contributor Author

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

Copy link
Member

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)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough.

@Taluu Taluu force-pushed the container-deprecated branch from c188e6b to 0c31716 Compare September 24, 2015 08:50
@Taluu Taluu force-pushed the container-deprecated branch from 0c31716 to 83f4e9c Compare September 24, 2015 08:53
@fabpot
Copy link
Member

fabpot commented Sep 24, 2015

ping @symfony/deciders

@fabpot
Copy link
Member

fabpot commented Sep 24, 2015

@Taluu Can you fixed fabbot issues?

@Taluu
Copy link
Contributor Author

Taluu commented Sep 24, 2015

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 ?

@fabpot
Copy link
Member

fabpot commented Sep 25, 2015

Thank you @Taluu.

@fabpot fabpot merged commit 83f4e9c into symfony:2.8 Sep 25, 2015
fabpot added a commit that referenced this pull request Sep 25, 2015
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
@stof
Copy link
Member

stof commented Sep 25, 2015

@fabpot could you make fabbot ignore fixture files ?

@nicolas-grekas
Copy link
Member

@Taluu would you like to open an other PR that adds tags to deprecated services?
See e.g.

@trigger_error('The '.__METHOD__.' method is deprecated since version 2.4 and will be removed in 3.0. The only reliable way to get the "Request" object is to inject it in the action method.', E_USER_DEPRECATED);
or
This service is deprecated, you should use the request_stack service instead.
(there must be more)

@Taluu Taluu deleted the container-deprecated branch September 29, 2015 13:02
@Taluu
Copy link
Contributor Author

Taluu commented Sep 29, 2015

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)

wouterj added a commit to symfony/symfony-docs that referenced this pull request Oct 10, 2015
… (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
@fabpot fabpot mentioned this pull request Nov 16, 2015
public function setDeprecated($status = true, $template = null)
{
if (null !== $template) {
if (preg_match('#[\r\n]|\*/#', $template)) {
Copy link
Contributor

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

Copy link
Contributor Author

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...

Copy link
Contributor

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.

Copy link
Contributor Author

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

Copy link
Contributor

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.