I'm using a Compiler Pass to add an `addMethodCall` to a
service definition to register tagged services. However, it seems that my
`addMethodCall` is being added to the container definition in such a way
that it is causing a circular reference. Here is my desired container
configuration:
<service id="data_provider_manager" />
<service id="formatter_manager">
<argument type="service" id="data_provider_manager" />
</service>
<service id="some_special_data_provider">
<argument type="service" id="formatter_manager" />
<tag name="data_provider" alias="some_special" />
</service>
My expectation is for the following to happen:
$dataProviderManager = new DataProviderManager;
$formatterManager = new FormatterManager($dataProviderManager);
$someSpecialDataProvider = new SomeSpecialDataProvider($formatterManager);
// ... at some point later.
$dataProviderManager->registerDataProvider('some_special',
$someSpecialDataProvider);
This is not what happens. :) It looks like the registerDataProvider()
method is called right after $dataProviderManager is instantiated. Which
has a dependency on $someSpecialDataProvider, which depends on
$formatterManager, which depends on $dataProviderManager. So I can see that
there is a circular reference *if the registerDataProvider happens as soon
as $dataProviderManager is requested*.
I have temporarily solved this problem by doing the following configuration
instead:
<service id="data_provider_manager" />
<service id="formatter_manager">
<call method="setDataProviderManager">
<argument type="service" id="data_provider_manager" />
</call>
</service>
<service id="some_special_data_provider">
<argument type="service" id="formatter_manager" />
<tag name="data_provider" alias="some_special" />
</service>
I'm not entirely certain why this works when my original service
configuration did not. It seems to me as though they are both calling
methods (`registerDataProvider` and `setDataProviderManager`) but this
somehow breaks the circular reference.
I have two question:
1) Can someone unwind for me what is going on here and why making this
change removes the circular dependency from my configuration?
2) My naive understanding was that the `setDataProviderManager` call, as
configured from the service configuration, must be being added to the
container at a different part of the container compilation lifecycle. If
this is the case, is there any way for me to have my data_provider tag do
the same thing? If so, will I be able to get away from the circular
reference problem without having to use `setDataProviderManager`? From
looking at the container cache I can't see that this is actually the case,
though.
I'm guessing if there is a solution to this it will involve using a
non-default PassConfig. I tried the PassConfig used by the kernel listener
but it made no difference. The docs were not very clear on when you would
use a certain PassConfig so I'm not sure if any of them would actually be
useful.
I asked on the Symfony Users group and didn't get very far. I had a few
people question the design of the classes. That is a fair point, and I very
well may try to find a way for formatter_manager to not depend on
data_provider_manager, but I would like to not get bogged down in those
details. I'm mainly hoping to find out more about the container lifecycle
and whether or not there is something I can do with my Compiler Pass to add
the method call to another part of the lifecycle so that my data provider
can be registered in such a way that I don't have to worry about calling
`setDataProviderManager` on my Formatter Manager.
--
If you want to report a vulnerability issue on symfony, please send it to
security at symfony-project.com
You received this message because you are subscribed to the Google
Groups "symfony developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/symfony-devs?hl=en