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

Skip to content

[Autowiring] Add interface FQCN as a valid service name to avoid collisions #21132

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

Closed
wants to merge 3 commits into from

Conversation

theofidry
Copy link
Contributor

Q A
Branch? master? (not sure)
Bug fix? yes/no (not sure)
New feature? yes
BC breaks? possibly
Deprecations? no
Tests pass? yes
Fixed tickets none
License MIT
Doc PR TODO

As of now, if you have:

interface CollisionInterface {}

class A implements CollisionInterface {}

class UseCollision
{
  function __construct(CollisionInterface $collision) {}
}
services:
  app.a:
    class: A
    autowire: true

  app.b:
    class: A

  CollisionInterface: '@app.b'

  app.use_collision:
    class: UseCollision
    autowire: true

It would fail, because you have app.a and app.b which are both implementing CollisionInterface. However as you can see, in this scenario this is a bit stupid, as if you bother doing CollisionInterface: '@app.b', this is equivalent to (or rather should be IMO) have:

services:
  #...

  app.b:
    class: A
    autowired_types: [ CollisionInterface ]

You might wonder what's the diff and why bother yourself with that, the diff IMO is the location of your service definitions. For example I may try to follow a more DDD oriented architecture, e.g. the hexagonal architecture, where I have:

config/
  domain.yml # service definitions related to the domain layer
  infrastructure.yml # service definitions related to the infrastructure layer

src/
  Domain/
    CollisionInterface.php
  Infrastructure/
    A.php
    UseCollision.php

and try to have something like:

# config/domain.yml
services:
  App\Domain\CollisionInterface: '@app.b'
# config/infrastructure.yml
  app.a:
    class: A
    autowire: true

  app.b:
    class: A

  app.use_collision:
    class: UseCollision
    autowire: true

I am not sure if this can be caused any BC and if this should be considered as a feature or a bugfix.

/cc @dunglas

@GuilhemN
Copy link
Contributor

GuilhemN commented Jan 2, 2017

Sounds hard to support without having a dedicated system in ContainerBuilder. For example we can't support the following using the current autowiring types system as the service is not yet defined:

services:
  CollisionInterface: '@app.b'

  app.a:
    class: A
    autowire: true

  app.b:
    class: A

  app.use_collision:
    class: UseCollision
    autowire: true

@nicolas-grekas nicolas-grekas added this to the 3.x milestone Jan 2, 2017
@dunglas
Copy link
Member

dunglas commented Jan 3, 2017

Shouldn't we deprecate the autowiring_types key to only use the `CollisionInterface: '@app.b' syntax now?

@@ -338,11 +338,15 @@ private function set($type, $id)
*/
private function createAutowiredDefinition(\ReflectionClass $typeHint, $id)
{
if (isset($this->ambiguousServiceTypes[$typeHint->name])) {
if (isset($this->ambiguousServiceTypes[$typeHintName = $typeHint->name])) {
Copy link
Member

Choose a reason for hiding this comment

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

Why is necessary to create the $typeHintName variable? It makes the code harder to read for no benefit over using the prop directly.

{
$container = new ContainerBuilder();

$container->register('c1', __NAMESPACE__.'\CollisionA');
Copy link
Member

Choose a reason for hiding this comment

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

You can use CollisionA::class for Symfony 3+. Same of lines below.

@theofidry
Copy link
Contributor Author

Shouldn't we deprecate the autowiring_types key to only use the `CollisionInterface: '@app.b' syntax now?

I'm for it, but should it be done here or another PR? Also should this be merged in master or an older branch?

@theofidry
Copy link
Contributor Author

theofidry commented Jan 3, 2017

@GuilhemN I'm not sure to understand your concern, all services are registered being process that way so the order does not matter.

@GuilhemN
Copy link
Contributor

GuilhemN commented Jan 3, 2017

@theofidry oops, I didn't realize it was a PR and I was thinking you'll try to implement it otherwise... 😐

LGTM 👍 I'm also for deprecating the autowiring_types key.

$classOrInterface = $typeHint->isInterface() ? 'interface' : 'class';
$matchingServices = implode(', ', $this->ambiguousServiceTypes[$typeHint->name]);

throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". Multiple services exist for this %s (%s).', $typeHint->name, $id, $classOrInterface, $matchingServices), 1);
throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". Multiple services exist for this %s (%s).', $typeHint->name, $id, $classOrInterface, $matchingServices));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

needs to be reverted

@theofidry
Copy link
Contributor Author

@dunglas updated, but I'm still unsure on which branch we should merge this as if we want to deprecate autowiring_types, it would need to be merged on the oldest possible, as you cannot do without autowiring_types without this PR.

@nicolas-grekas
Copy link
Member

the deprecation part is for master for sure
so you may need to split this PR in two if a bug needs to be fixed in a lower branch

@theofidry
Copy link
Contributor Author

theofidry commented Jan 6, 2017

@nicolas-grekas I'm actually not sure if this should be considered a feature or a bug (hence my question of which branch to target). The PR doesn't need to be split, deprecating autowiring_types is not done yet and I plan to do it in another PR.

@dunglas
Copy link
Member

dunglas commented Jan 6, 2017

👍

@@ -339,6 +339,10 @@ private function set($type, $id)
private function createAutowiredDefinition(\ReflectionClass $typeHint, $id)
{
if (isset($this->ambiguousServiceTypes[$typeHint->name])) {
if ($this->container->has($typeHint->name)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can't this be moved here to avoid building the map when not necessary?

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 point, gonna try

@nicolas-grekas
Copy link
Member

Closing, see ##21494.

@theofidry
Copy link
Contributor Author

Thanks :)

@theofidry theofidry deleted the bugfix/autowire-interface branch February 1, 2017 21:02
@nicolas-grekas nicolas-grekas modified the milestones: 3.x, 3.3 Mar 24, 2017
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.

5 participants