Message from discussion
Question about Container lifecycle (circular references, Compiler Pass adding `addMethodCall` vs container configuration calling a method)
Date: Sat, 29 Sep 2012 14:50:21 -0700 (PDT)
From: Beau Simensen <simen...@gmail.com>
To: symfony-devs@googlegroups.com
Message-Id: <c7068077-a4b6-42d0-ae67-16e7c88d4ea9@googlegroups.com>
In-Reply-To: <48368c67-21ac-4442-9ae3-cf5bc7735961@googlegroups.com>
References: <48368c67-21ac-4442-9ae3-cf5bc7735961@googlegroups.com>
Subject: Re: Question about Container lifecycle (circular references,
Compiler Pass adding `addMethodCall` vs container configuration calling a
method)
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="----=_Part_1410_8981190.1348955421797"
------=_Part_1410_8981190.1348955421797
Content-Type: multipart/alternative;
boundary="----=_Part_1411_19041808.1348955421797"
------=_Part_1411_19041808.1348955421797
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 7bit
Any chance someone is able to help me better understand this? It still
isn't clear to me why addMethodCall fixes my circular dependency for a
service definition but not when I add the method call via a compiler pass.
On Tuesday, August 28, 2012 5:52:26 PM UTC-7, Beau Simensen wrote:
>
> 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.
>
------=_Part_1411_19041808.1348955421797
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable
Any chance someone is able to help me better understand this? It still isn'=
t clear to me why addMethodCall fixes my circular dependency for =
a service definition but not when I add the method call via a compiler pass=
.<br><br>On Tuesday, August 28, 2012 5:52:26 PM UTC-7, Beau Simensen wrote:=
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bor=
der-left: 1px #ccc solid;padding-left: 1ex;">I'm using a Compiler Pass to a=
dd an `addMethodCall` to a service definition to register tagged =
services. However, it seems that my `addMethodCall` is being added to the c=
ontainer definition in such a way that it is causing a circular reference. =
Here is my desired container configuration:<br><div><br></div><div><pre sty=
le=3D"font-size:12px;line-height:1.4em;font-family:'Bitstream Vera Sans Mon=
o',Courier,monospace;color:rgb(0,0,0)"><div style=3D"padding-left:1em;line-=
height:1.4em"><span style=3D"line-height:1.4em;color:rgb(0,0,128)"><serv=
ice</span> <span style=3D"line-height:1.4em;color:rgb(0,128,128)">id=3D</sp=
an><span style=3D"line-height:1.4em;color:rgb(221,17,68)">"data_provider_ma=
nager"</span> <span style=3D"line-height:1.4em;color:rgb(0,0,128)">/></s=
pan></div><div style=3D"padding-left:1em;line-height:1.4em"><span style=3D"=
line-height:1.4em;color:rgb(0,0,128)"><service</span> <span style=3D"lin=
e-height:1.4em;color:rgb(0,128,128)">id=3D</span><span style=3D"line-height=
:1.4em;color:rgb(221,17,68)">"formatter_manager"</span><span style=3D"line-=
height:1.4em;color:rgb(0,0,128)">></span></div><div style=3D"padding-lef=
t:1em;line-height:1.4em"> <span style=3D"line-height=
:1.4em;color:rgb(0,0,128)"><argument</span> <span style=3D"line-height:1=
.4em;color:rgb(0,128,128)">type=3D</span><span style=3D"line-height:1.4em;c=
olor:rgb(221,17,68)">"service"</span> <span style=3D"line-height:1.4em;colo=
r:rgb(0,128,128)">id=3D</span><span style=3D"line-height:1.4em;color:rgb(22=
1,17,68)">"data_provider_manager"</span> <span style=3D"line-height:1.4em;c=
olor:rgb(0,0,128)">/></span></div><div style=3D"padding-left:1em;line-he=
ight:1.4em"><span style=3D"line-height:1.4em;color:rgb(0,0,128)"></servi=
ce></span></div><div style=3D"padding-left:1em;line-height:1.4em"><span =
style=3D"line-height:1.4em;color:rgb(0,0,128)"><service</span> <span sty=
le=3D"line-height:1.4em;color:rgb(0,128,128)">id=3D</span><span style=3D"li=
ne-height:1.4em;color:rgb(221,17,68)">"some_special_data_<wbr>provider"</sp=
an><span style=3D"line-height:1.4em;color:rgb(0,0,128)">></span></div><d=
iv style=3D"padding-left:1em;line-height:1.4em"> <sp=
an style=3D"line-height:1.4em;color:rgb(0,0,128)"><argument</span> <span=
style=3D"line-height:1.4em;color:rgb(0,128,128)">type=3D</span><span style=
=3D"line-height:1.4em;color:rgb(221,17,68)">"service"</span> <span style=3D=
"line-height:1.4em;color:rgb(0,128,128)">id=3D</span><span style=3D"line-he=
ight:1.4em;color:rgb(221,17,68)">"formatter_manager"</span> <span style=3D"=
line-height:1.4em;color:rgb(0,0,128)">/></span></div><div style=3D"paddi=
ng-left:1em;line-height:1.4em"> <span style=3D"line-=
height:1.4em;color:rgb(0,0,128)"><tag</span> <span style=3D"line-height:=
1.4em;color:rgb(0,128,128)">name=3D</span><span style=3D"line-height:1.4em;=
color:rgb(221,17,68)">"data_provider"</span> <span style=3D"line-height:1.4=
em;color:rgb(0,128,128)">alias=3D</span><span style=3D"line-height:1.4em;co=
lor:rgb(221,17,68)">"some_special"</span> <span style=3D"line-height:1.4em;=
color:rgb(0,0,128)">/></span></div><div style=3D"padding-left:1em;line-h=
eight:1.4em"><span style=3D"line-height:1.4em;color:rgb(0,0,128)"></serv=
ice></span></div></pre></div><div><br></div><div><br></div><div>My expec=
tation is for the following to happen:</div><div><br></div><div><pre style=
=3D"font-size:12px;line-height:1.4em;font-family:'Bitstream Vera Sans Mono'=
,Courier,monospace;color:rgb(0,0,0)"><div style=3D"padding-left:1em;line-he=
ight:1.4em"><span style=3D"line-height:1.4em;color:rgb(0,128,128)">$dataPro=
viderManager</span> <span style=3D"line-height:1.4em;font-weight:bold">=3D<=
/span> <span style=3D"line-height:1.4em;font-weight:bold">new</span> <span =
style=3D"line-height:1.4em">DataProviderManager</span><span style=3D"line-h=
eight:1.4em">;</span></div><div style=3D"padding-left:1em;line-height:1.4em=
"><span style=3D"line-height:1.4em;color:rgb(0,128,128)">$formatterManager<=
/span> <span style=3D"line-height:1.4em;font-weight:bold">=3D</span> <span =
style=3D"line-height:1.4em;font-weight:bold">new</span> <span style=3D"line=
-height:1.4em">FormatterManager</span><span style=3D"line-height:1.4em">(</=
span><span style=3D"line-height:1.4em;color:rgb(0,128,128)">$<wbr>dataProvi=
derManager</span><span style=3D"line-height:1.4em">);</span></div><div styl=
e=3D"padding-left:1em;line-height:1.4em"><span style=3D"line-height:1.4em;c=
olor:rgb(0,128,128)">$someSpecialDataProvider</span> <span style=3D"line-he=
ight:1.4em;font-weight:bold">=3D</span> <span style=3D"line-height:1.4em;fo=
nt-weight:bold">new</span> <span style=3D"line-height:1.4em">SomeSpecialDat=
aProvider</span><span style=3D"line-height:1.4em">(</span><span style=3D"li=
ne-height:1.4em;color:rgb(0,128,128)">$<wbr>formatterManager</span><span st=
yle=3D"line-height:1.4em">);</span></div><div style=3D"padding-left:1em;lin=
e-height:1.4em"><br style=3D"margin:0px;padding:0px;line-height:1.4em"></di=
v><div style=3D"padding-left:1em;line-height:1.4em"><span style=3D"line-hei=
ght:1.4em;color:rgb(153,153,136);font-style:italic">// ... at some point la=
ter.</span></div><div style=3D"padding-left:1em;line-height:1.4em"><span st=
yle=3D"line-height:1.4em;color:rgb(0,128,128)">$dataProviderManager</span><=
span style=3D"line-height:1.4em;font-weight:bold">-></span><span style=
=3D"line-height:1.4em;color:rgb(0,128,128)">register<wbr>DataProvider</span=
><span style=3D"line-height:1.4em">(</span><span style=3D"line-height:1.4em=
;color:rgb(221,17,68)">'some_special'</span><span style=3D"line-height:1.4e=
m">,</span> <span style=3D"line-height:1.4em;color:rgb(0,128,128)">$someSpe=
cialDataProvider</span><span style=3D"line-height:1.4em">);</span></div></p=
re></div><div><br></div><div><br></div><div>This is not what happens. :) It=
looks like the registerDataProvider() method is called right after $dataPr=
oviderManager is instantiated. Which has a dependency on $someSpecialDataPr=
ovider, which depends on $formatterManager, which depends on $dataProviderM=
anager. So I can see that there is a circular reference <i>if the registerD=
ataProvider happens as soon as $dataProviderManager is requested</i>.</div>=
<div><br></div><div>I have temporarily solved this problem by doing the fol=
lowing configuration instead:</div><div><br></div><div><pre style=3D"font-s=
ize:12px;line-height:1.4em;font-family:'Bitstream Vera Sans Mono',Courier,m=
onospace;color:rgb(0,0,0)"><div style=3D"padding-left:1em;line-height:1.4em=
"><span style=3D"line-height:1.4em;color:rgb(0,0,128)"><service</span> <=
span style=3D"line-height:1.4em;color:rgb(0,128,128)">id=3D</span><span sty=
le=3D"line-height:1.4em;color:rgb(221,17,68)">"data_provider_manager"</span=
> <span style=3D"line-height:1.4em;color:rgb(0,0,128)">/></span></div><d=
iv style=3D"padding-left:1em;line-height:1.4em"><span style=3D"line-height:=
1.4em;color:rgb(0,0,128)"><service</span> <span style=3D"line-height:1.4=
em;color:rgb(0,128,128)">id=3D</span><span style=3D"line-height:1.4em;color=
:rgb(221,17,68)">"formatter_manager"</span><span style=3D"line-height:1.4em=
;color:rgb(0,0,128)">></span></div><div style=3D"padding-left:1em;line-h=
eight:1.4em"> <span style=3D"line-height:1.4em;color=
:rgb(0,0,128)"><call</span> <span style=3D"line-height:1.4em;color:rgb(0=
,128,128)">method=3D</span><span style=3D"line-height:1.4em;color:rgb(221,1=
7,68)">"<wbr>setDataProviderManager"</span><span style=3D"line-height:1.4em=
;color:rgb(0,0,128)">></span></div><div style=3D"padding-left:1em;line-h=
eight:1.4em"> <span style=3D=
"line-height:1.4em;color:rgb(0,0,128)"><argument</span> <span style=3D"l=
ine-height:1.4em;color:rgb(0,128,128)">type=3D</span><span style=3D"line-he=
ight:1.4em;color:rgb(221,17,68)">"service"</span> <span style=3D"line-heigh=
t:1.4em;color:rgb(0,128,128)">id=3D</span><span style=3D"line-height:1.4em;=
color:rgb(221,17,68)">"data_provider_manager"</span> <span style=3D"line-he=
ight:1.4em;color:rgb(0,0,128)">/></span></div><div style=3D"padding-left=
:1em;line-height:1.4em"> <span style=3D"line-height:=
1.4em;color:rgb(0,0,128)"></call></span></div><div style=3D"padding-l=
eft:1em;line-height:1.4em"><span style=3D"line-height:1.4em;color:rgb(0,0,1=
28)"></service></span></div><div style=3D"padding-left:1em;line-heigh=
t:1.4em"><span style=3D"line-height:1.4em;color:rgb(0,0,128)"><service</=
span> <span style=3D"line-height:1.4em;color:rgb(0,128,128)">id=3D</span><s=
pan style=3D"line-height:1.4em;color:rgb(221,17,68)">"some_special_data_<wb=
r>provider"</span><span style=3D"line-height:1.4em;color:rgb(0,0,128)">>=
</span></div><div style=3D"padding-left:1em;line-height:1.4em"> =
<span style=3D"line-height:1.4em;color:rgb(0,0,128)"><argume=
nt</span> <span style=3D"line-height:1.4em;color:rgb(0,128,128)">type=3D</s=
pan><span style=3D"line-height:1.4em;color:rgb(221,17,68)">"service"</span>=
<span style=3D"line-height:1.4em;color:rgb(0,128,128)">id=3D</span><span s=
tyle=3D"line-height:1.4em;color:rgb(221,17,68)">"formatter_manager"</span> =
<span style=3D"line-height:1.4em;color:rgb(0,0,128)">/></span></div><div=
style=3D"padding-left:1em;line-height:1.4em"> <span=
style=3D"line-height:1.4em;color:rgb(0,0,128)"><tag</span> <span style=
=3D"line-height:1.4em;color:rgb(0,128,128)">name=3D</span><span style=3D"li=
ne-height:1.4em;color:rgb(221,17,68)">"data_provider"</span> <span style=3D=
"line-height:1.4em;color:rgb(0,128,128)">alias=3D</span><span style=3D"line=
-height:1.4em;color:rgb(221,17,68)">"some_special"</span> <span style=3D"li=
ne-height:1.4em;color:rgb(0,0,128)">/></span></div><div style=3D"padding=
-left:1em;line-height:1.4em"><span style=3D"line-height:1.4em;color:rgb(0,0=
,128)"></service></span></div></pre></div><div><br></div><div><br></d=
iv><div>I'm not entirely certain why this works when my original service co=
nfiguration did not. It seems to me as though they are both calling methods=
(`registerDataProvider` and `setDataProviderManager`) but this somehow bre=
aks the circular reference.</div><div><br></div><div>I have two question:</=
div><div><br></div><div>1) Can someone unwind for me what is going on here =
and why making this change removes the circular dependency from my configur=
ation?</div><div><br></div><div>2) My naive understanding was that the `set=
DataProviderManager` call, as configured from the service configuration, mu=
st be being added to the container at a different part of the container com=
pilation 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 fro=
m the circular reference problem without having to use `setDataProviderMana=
ger`? From looking at the container cache I can't see that this is actually=
the case, though.</div><div><br></div><div>I'm guessing if there is a solu=
tion to this it will involve using a non-default PassConfig. I tr=
ied the PassConfig used by the kernel listener but it made no difference. T=
he 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.</div><div><br></div><d=
iv>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_pro=
vider_manager, but I would like to not get bogged down in those d=
etails. I'm mainly hoping to find out more about the container lifecycle an=
d whether or not there is something I can do with my Compiler Pass to add t=
he method call to another part of the lifecycle so that my data provider ca=
n be registered in such a way that I don't have to worry about calling `set=
DataProviderManager` on my Formatter Manager.</div></blockquote>
------=_Part_1411_19041808.1348955421797--
------=_Part_1410_8981190.1348955421797--