Skip to content
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

EntityListener can't be applied to multiple services with same class name #1224

Closed
biozshock opened this issue Oct 2, 2020 · 9 comments
Closed

Comments

@biozshock
Copy link
Contributor

With current implementation of ContainerEntityListenerResolver it's not possible to use same class, even if it has different service IDs

Consider following config:

services:
  service_a:
    class: My\Class
    parameters: ['param1`]
    tags:
      - {'name': 'doctrine.orm.entity_listener', 'entity': 'My\Entity1'}

  service_b:
    class: My\Class
    parameters: ['param2`]
    tags:
      - {'name': 'doctrine.orm.entity_listener', 'entity': 'My\Entity2'}

The entity listener service_b will be applied to entity My\Entity1, because https://github.com/doctrine/DoctrineBundle/blob/2.1.2/Mapping/ContainerEntityListenerResolver.php#L66 uses class name instead of the service ID to collect entity listeners.

@stof
Copy link
Member

stof commented Oct 2, 2020

AFAICT, this is because the way the ORM works is that it uses a class name as the input of the resolver (and so does not allow having multiple ones with the same class name)

@biozshock
Copy link
Contributor Author

This is because how a class metadata is collected in EntityListenerPass. Doctrine does not operate with class names here, but with strings. I'm positive that DoctrineBundle can put service IDs instead of real class names, and it will just work.
Though i'm not really sure how to implement such logic for services that are marked as lazy. Because an interface accepts only an instance of the listener, w/o the ID.

@stof
Copy link
Member

stof commented Oct 2, 2020

The interface in the ORM explicitly declares the argument as being a class name rather than an arbitrary string: https://github.com/doctrine/orm/blob/e0eb82a3b12a3fd0878b5d56c3c293c04c168329/lib/Doctrine/ORM/Mapping/EntityListenerResolver.php#L42-L51

@biozshock
Copy link
Contributor Author

In terms of the symfony bundle that's an ID of the service.

@ostrolucky
Copy link
Member

Not in your example. If you want to discrespect the contract, you can do it on your own, but we don't want to do that in a bundle. Another option is to open issue in ORM which relaxes the contract.

@stof
Copy link
Member

stof commented Oct 2, 2020

@biozshock no. The ContainerEntityListenerResolver lookups the provided argument into the ServiceLocator it takes as argument. So it can indeed work with any kind of string internally as long as both sides are matching. But the expectation of the signature are defined by the interface it implements, which is why the ServiceLocator is configured with class names as keys.

@ostrolucky
Copy link
Member

Marking on hold until contract is changed in ORM

@ostrolucky
Copy link
Member

Change unblocking this has been merged upstream, so this is ready to implement now

@ostrolucky ostrolucky added Ready to work on and removed Status: On Hold Most likely waiting for upstream resolution labels Jan 30, 2021
@ostrolucky
Copy link
Member

Hmm I think we still can't do anything here, because resolve method must return 1 object (listener) only. Unfortunately you will have to ask in https://github.com/doctrine/orm to change its event system

@ostrolucky ostrolucky closed this as not planned Won't fix, can't repro, duplicate, stale Jul 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants