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

Skip to content

[DependencyInjection] Add SubscribedService attribute, deprecate current ServiceSubscriberTrait usage #42238

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 1 commit into from
Oct 27, 2021

Conversation

kbond
Copy link
Member

@kbond kbond commented Jul 23, 2021

Q A
Branch? 5.4
Bug fix? yes
New feature? yes
Deprecations? yes
Tickets Fix #42217
License MIT
Doc PR TODO

This is a fix for #42217 using what I proposed there (adding SubscribedService attribute). The current usage is deprecated in 5.4 only when using PHP 8+. I suggest removing the current usage entirely in Symfony 6.0 - this will fully fix the bug.

Deprecation Layer:

  1. Symfony 5.4 with PHP < 8, everything works as it does currently (no deprecation warnings).
  2. Symfony 5.4 with PHP > 8 and using the trait on a class w/o any methods marked with the SubscribedService attribute, works as it does currently but a deprecation warning is triggered.
  3. Symfony 5.4 with PHP > 8 and using the trait on a class with at least one method marked with the SubscribedService attribute, you've opted-into the new functionality (methods w/o the attribute are ignored).

@carsonbot carsonbot added Status: Needs Review Bug DependencyInjection Deprecation Feature RFC RFC = Request For Comments (proposals about features that you want to be discussed) labels Jul 23, 2021
@carsonbot carsonbot changed the title [RFC][DependencyInjection] Add SubscribedService attribute, deprecate current ServiceSubscriberTrait usage [DependencyInjection] Add SubscribedService attribute, deprecate current ServiceSubscriberTrait usage Jul 23, 2021
@kbond kbond force-pushed the service-subscriber-fix branch from 796f455 to 9baa209 Compare July 23, 2021 12:54
Copy link
Member

@weaverryan weaverryan left a comment

Choose a reason for hiding this comment

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

I like this approach - we have decided not to use ServiceSubscriberTrait in our site because, when trying to introduce it, one dev spent a long time trying to figure out a sudden autowiring error (it was because it was trying to wire a model class due to an unrelated method on the service that we did not want to be considered for the locator).


if (!$returnType instanceof \ReflectionNamedType) {
// todo, what exception to throw?
throw new \RuntimeException(sprintf('Cannot use "%s" on methods with a union return type in "%s::%s()".', SubscribedService::class, $method->name, self::class));
Copy link
Member

Choose a reason for hiding this comment

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

Why ? the previous loop does not have this restriction.

Copy link
Member Author

Choose a reason for hiding this comment

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

I treated this as a bug. If the return type is Service1|Service2, what should be used for the service locator?

Copy link
Member

Choose a reason for hiding this comment

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

@kbond Does #43479 help to answer that question?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes :). Is there an example of using union/intersection types with ServiceSubscriberInterface?

Copy link
Member

Choose a reason for hiding this comment

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

The example from the PR was an intersection of two serializer interfaces that would yield the serializer service, e.g. NormalizerInterface&DenormalizerInterface, so let's explore that:

class MyService implements ServiceSubscriberInterface
{
    use ServiceSubscriberTrait;

    private function getSerializer(): NormalizerInterface&DenormalizerInterface
    {
        return $this->container->get(__METHOD__);
    }
}

Copy link
Member Author

@kbond kbond Oct 20, 2021

Choose a reason for hiding this comment

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

Yep, I'll try to make that work. I'm looking for what the array returned from ServiceSubscriberInterface::getSubscribedServices() looks like when using union/intersection.

Copy link
Member

Choose a reason for hiding this comment

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

I see. We need to come up with a new convention for that, I guess.

@stof
Copy link
Member

stof commented Jul 23, 2021

To make the trait usable in 5.4 without WTF, we would need a way to opt-in for the new behavior (here, there is nothing that will stop registering other private methods, with no way to avoid the deprecation warning if they are not meant to be subscribed)

@nicolas-grekas
Copy link
Member

What about deprecating the trait instead?

@kbond
Copy link
Member Author

kbond commented Jul 23, 2021

To make the trait usable in 5.4 without WTF, we would need a way to opt-in for the new behavior

What about, if using the attribute on any method, you've opted into the new way and methods without the attribute are ignored?

@kbond
Copy link
Member Author

kbond commented Jul 23, 2021

What about deprecating the trait instead?

And creating a new trait entirely? Suggestions on a new name? SubscribedServiceTrait?

@stof
Copy link
Member

stof commented Jul 23, 2021

Well, providing an easy implemention of the getSubscribedServices method to provide better DX might make sense.
but maybe it should be a new trait entirely instead (and deprecating the existing one)

@nicolas-grekas
Copy link
Member

I was considering deprecating the trait and not replacing it, but if you think we should keep it, no need to create a new one if we can make a nice deprecation layer.

@kbond
Copy link
Member Author

kbond commented Jul 23, 2021

I was considering deprecating the trait and not replacing it, but if you think we should keep it...

I personally like this feature so I think we should keep it but I understand it's a bit... controversial (and could be easily abused).

If you're ok keeping it, I'll add the nice deprecation layer and finish this PR. Alternatively, if you want to deprecate/remove, I can easily maintain this feature in a 3rd party package.

@nicolas-grekas
Copy link
Member

I'm fine keeping it now that we have it.

@kbond kbond force-pushed the service-subscriber-fix branch 2 times, most recently from 07877ad to fee84f7 Compare July 23, 2021 15:04
@kbond
Copy link
Member Author

kbond commented Jul 23, 2021

I've updated/added tests and improved the deprecation layer:

  1. Symfony 5.4 with PHP < 8, everything works as it does currently (no deprecation warnings).
  2. Symfony 5.4 with PHP > 8 and using the trait on a class w/o any methods marked with the SubscribedService attribute, works as it does currently but a deprecation warning is triggered.
  3. Symfony 5.4 with PHP > 8 and using the trait on a class with at least one method marked with the SubscribedService attribute, you've opted-into the new functionality (methods w/o the attribute are ignored).

@kbond kbond force-pushed the service-subscriber-fix branch from fee84f7 to 4306aaa Compare July 23, 2021 15:27
@kbond
Copy link
Member Author

kbond commented Jul 23, 2021

I could use some direction on fixing the remaining CI errors.

@chalasr chalasr removed Bug RFC RFC = Request For Comments (proposals about features that you want to be discussed) labels Jul 26, 2021
@OskarStark OskarStark changed the title [DependencyInjection] Add SubscribedService attribute, deprecate current ServiceSubscriberTrait usage [DependencyInjection] Add SubscribedService attribute, deprecate current ServiceSubscriberTrait usage Aug 1, 2021
@chalasr chalasr added this to the 5.4 milestone Aug 6, 2021
@kbond kbond force-pushed the service-subscriber-fix branch 2 times, most recently from 54535f1 to 1cbc600 Compare September 8, 2021 12:37
@kbond
Copy link
Member Author

kbond commented Oct 20, 2021

Assuming this is still wanted for 5.4, once merged, I'll work on a PR to drop the deprecation layer in 6.0.

Still need a bit of direction for fixing the tests. I believe it's a dependency issue, symfony/dependency-injection is requiring the wrong version of symfony/service-contracts.

Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

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

ideally tests on DI should work on all versions of contracts, or be skipped on non-supported ones

@kbond kbond force-pushed the service-subscriber-fix branch 3 times, most recently from 7afa27c to 716b275 Compare October 20, 2021 15:14
@kbond kbond force-pushed the service-subscriber-fix branch from 716b275 to a5bb886 Compare October 20, 2021 15:30
@kbond
Copy link
Member Author

kbond commented Oct 20, 2021

I believe all related tests are now passing. I fixed some pslam issues but don't understand the remaining ones.

Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

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

one last non-trivial note :)

throw new \LogicException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class));
}

$services[$attribute->newInstance()->key ?? self::class.'::'.$method->name] = '?'.$returnType->getName();
Copy link
Member

Choose a reason for hiding this comment

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

this should likely do $returnType instanceof \ReflectionNamedType ? ->getName() : (string) for the last part.

also, when the attribute is used, I'm not sure about the ? prefix. Shouldn't we add it only when the type is nullable? (and remove |null from the string representation of the union)

Copy link
Member Author

Choose a reason for hiding this comment

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

this should likely do $returnType instanceof \ReflectionNamedType ? ->getName() : (string) for the last part.

Like this?

$services[$attribute->newInstance()->key ?? self::class.'::'.$method->name] = '?'.($returnType instanceof \ReflectionNamedType ? $returnType->getName() : $returnType);

I just realized ReflectionType::__toString is deprecated.. Should we be relying on this?

also, when the attribute is used, I'm not sure about the ? prefix. Shouldn't we add it only when the type is nullable? (and remove |null from the string representation of the union)

Good call, I'll make this change. Should I leave the BC layer as is?

Copy link
Member Author

Choose a reason for hiding this comment

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

I've made these changes (let me know if you'd like me to backport this to the BC layer).

I'm not sure how to handle union/intersection types. See #42238 (comment).

@kbond kbond force-pushed the service-subscriber-fix branch from a5bb886 to 2fa213f Compare October 20, 2021 15:53
Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

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

(with minor comments)

@nicolas-grekas
Copy link
Member

Thank you @kbond.

@kbond
Copy link
Member Author

kbond commented Oct 27, 2021

Great, once this makes its way into the 6.0 branch, I'll remove the deprecation layer.

@nicolas-grekas
Copy link
Member

now merged up to 6.0

fabpot added a commit that referenced this pull request Oct 27, 2021
…precation layer (kbond)

This PR was merged into the 6.0 branch.

Discussion
----------

[DependencyInjection] remove `ServiceSubscriberTrait` deprecation layer

| Q             | A
| ------------- | ---
| Branch?       | 6.0
| Bug fix?      | no
| New feature?  | no
| Deprecations? | no
| Tickets       | Followup to #42238
| License       | MIT
| Doc PR        | TODO

This removes the deprecation layer we added in #42238.

Commits
-------

4a6226d [DependencyInjection] remove ServiceSubscriberTrait deprecation layer
This was referenced Nov 5, 2021
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.

[DependencyInjection] ServiceSubscriberTrait does not allow non-service "getter" methods
8 participants