InlineServiceDefinitionsPassTest.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\DependencyInjection\Tests\Compiler;
  11. use PHPUnit\Framework\TestCase;
  12. use Symfony\Component\DependencyInjection\Definition;
  13. use Symfony\Component\DependencyInjection\Compiler\AnalyzeServiceReferencesPass;
  14. use Symfony\Component\DependencyInjection\Compiler\RepeatedPass;
  15. use Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass;
  16. use Symfony\Component\DependencyInjection\Reference;
  17. use Symfony\Component\DependencyInjection\ContainerBuilder;
  18. use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
  19. use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
  20. class InlineServiceDefinitionsPassTest extends TestCase
  21. {
  22. public function testProcess()
  23. {
  24. $container = new ContainerBuilder();
  25. $container
  26. ->register('inlinable.service')
  27. ->setPublic(false)
  28. ;
  29. $container
  30. ->register('service')
  31. ->setArguments(array(new Reference('inlinable.service')))
  32. ;
  33. $this->process($container);
  34. $arguments = $container->getDefinition('service')->getArguments();
  35. $this->assertInstanceOf('Symfony\Component\DependencyInjection\Definition', $arguments[0]);
  36. $this->assertSame($container->getDefinition('inlinable.service'), $arguments[0]);
  37. }
  38. public function testProcessDoesNotInlinesWhenAliasedServiceIsShared()
  39. {
  40. $container = new ContainerBuilder();
  41. $container
  42. ->register('foo')
  43. ->setPublic(false)
  44. ;
  45. $container->setAlias('moo', 'foo');
  46. $container
  47. ->register('service')
  48. ->setArguments(array($ref = new Reference('foo')))
  49. ;
  50. $this->process($container);
  51. $arguments = $container->getDefinition('service')->getArguments();
  52. $this->assertSame($ref, $arguments[0]);
  53. }
  54. public function testProcessDoesInlineNonSharedService()
  55. {
  56. $container = new ContainerBuilder();
  57. $container
  58. ->register('foo')
  59. ->setShared(false)
  60. ;
  61. $container
  62. ->register('bar')
  63. ->setPublic(false)
  64. ->setShared(false)
  65. ;
  66. $container->setAlias('moo', 'bar');
  67. $container
  68. ->register('service')
  69. ->setArguments(array(new Reference('foo'), $ref = new Reference('moo'), new Reference('bar')))
  70. ;
  71. $this->process($container);
  72. $arguments = $container->getDefinition('service')->getArguments();
  73. $this->assertEquals($container->getDefinition('foo'), $arguments[0]);
  74. $this->assertNotSame($container->getDefinition('foo'), $arguments[0]);
  75. $this->assertSame($ref, $arguments[1]);
  76. $this->assertEquals($container->getDefinition('bar'), $arguments[2]);
  77. $this->assertNotSame($container->getDefinition('bar'), $arguments[2]);
  78. }
  79. public function testProcessInlinesMixedServicesLoop()
  80. {
  81. $container = new ContainerBuilder();
  82. $container
  83. ->register('foo')
  84. ->addArgument(new Reference('bar'))
  85. ->setShared(false)
  86. ;
  87. $container
  88. ->register('bar')
  89. ->setPublic(false)
  90. ->addMethodCall('setFoo', array(new Reference('foo')))
  91. ;
  92. $this->process($container);
  93. $this->assertEquals($container->getDefinition('foo')->getArgument(0), $container->getDefinition('bar'));
  94. }
  95. /**
  96. * @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException
  97. * @expectedExceptionMessage Circular reference detected for service "bar", path: "bar -> foo -> bar".
  98. */
  99. public function testProcessThrowsOnNonSharedLoops()
  100. {
  101. $container = new ContainerBuilder();
  102. $container
  103. ->register('foo')
  104. ->addArgument(new Reference('bar'))
  105. ->setShared(false)
  106. ;
  107. $container
  108. ->register('bar')
  109. ->setShared(false)
  110. ->addMethodCall('setFoo', array(new Reference('foo')))
  111. ;
  112. $this->process($container);
  113. }
  114. public function testProcessNestedNonSharedServices()
  115. {
  116. $container = new ContainerBuilder();
  117. $container
  118. ->register('foo')
  119. ->addArgument(new Reference('bar1'))
  120. ->addArgument(new Reference('bar2'))
  121. ;
  122. $container
  123. ->register('bar1')
  124. ->setShared(false)
  125. ->addArgument(new Reference('baz'))
  126. ;
  127. $container
  128. ->register('bar2')
  129. ->setShared(false)
  130. ->addArgument(new Reference('baz'))
  131. ;
  132. $container
  133. ->register('baz')
  134. ->setShared(false)
  135. ;
  136. $this->process($container);
  137. $baz1 = $container->getDefinition('foo')->getArgument(0)->getArgument(0);
  138. $baz2 = $container->getDefinition('foo')->getArgument(1)->getArgument(0);
  139. $this->assertEquals($container->getDefinition('baz'), $baz1);
  140. $this->assertEquals($container->getDefinition('baz'), $baz2);
  141. $this->assertNotSame($baz1, $baz2);
  142. }
  143. public function testProcessInlinesIfMultipleReferencesButAllFromTheSameDefinition()
  144. {
  145. $container = new ContainerBuilder();
  146. $a = $container->register('a')->setPublic(false);
  147. $b = $container
  148. ->register('b')
  149. ->addArgument(new Reference('a'))
  150. ->addArgument(new Definition(null, array(new Reference('a'))))
  151. ;
  152. $this->process($container);
  153. $arguments = $b->getArguments();
  154. $this->assertSame($a, $arguments[0]);
  155. $inlinedArguments = $arguments[1]->getArguments();
  156. $this->assertSame($a, $inlinedArguments[0]);
  157. }
  158. public function testProcessInlinesPrivateFactoryReference()
  159. {
  160. $container = new ContainerBuilder();
  161. $container->register('a')->setPublic(false);
  162. $b = $container
  163. ->register('b')
  164. ->setPublic(false)
  165. ->setFactory(array(new Reference('a'), 'a'))
  166. ;
  167. $container
  168. ->register('foo')
  169. ->setArguments(array(
  170. $ref = new Reference('b'),
  171. ));
  172. $this->process($container);
  173. $inlinedArguments = $container->getDefinition('foo')->getArguments();
  174. $this->assertSame($b, $inlinedArguments[0]);
  175. }
  176. public function testProcessDoesNotInlinePrivateFactoryIfReferencedMultipleTimesWithinTheSameDefinition()
  177. {
  178. $container = new ContainerBuilder();
  179. $container
  180. ->register('a')
  181. ;
  182. $container
  183. ->register('b')
  184. ->setPublic(false)
  185. ->setFactory(array(new Reference('a'), 'a'))
  186. ;
  187. $container
  188. ->register('foo')
  189. ->setArguments(array(
  190. $ref1 = new Reference('b'),
  191. $ref2 = new Reference('b'),
  192. ))
  193. ;
  194. $this->process($container);
  195. $args = $container->getDefinition('foo')->getArguments();
  196. $this->assertSame($ref1, $args[0]);
  197. $this->assertSame($ref2, $args[1]);
  198. }
  199. public function testProcessDoesNotInlineReferenceWhenUsedByInlineFactory()
  200. {
  201. $container = new ContainerBuilder();
  202. $container
  203. ->register('a')
  204. ;
  205. $container
  206. ->register('b')
  207. ->setPublic(false)
  208. ->setFactory(array(new Reference('a'), 'a'))
  209. ;
  210. $inlineFactory = new Definition();
  211. $inlineFactory->setPublic(false);
  212. $inlineFactory->setFactory(array(new Reference('b'), 'b'));
  213. $container
  214. ->register('foo')
  215. ->setArguments(array(
  216. $ref = new Reference('b'),
  217. $inlineFactory,
  218. ))
  219. ;
  220. $this->process($container);
  221. $args = $container->getDefinition('foo')->getArguments();
  222. $this->assertSame($ref, $args[0]);
  223. }
  224. public function testProcessDoesNotInlineWhenServiceIsPrivateButLazy()
  225. {
  226. $container = new ContainerBuilder();
  227. $container
  228. ->register('foo')
  229. ->setPublic(false)
  230. ->setLazy(true)
  231. ;
  232. $container
  233. ->register('service')
  234. ->setArguments(array($ref = new Reference('foo')))
  235. ;
  236. $this->process($container);
  237. $arguments = $container->getDefinition('service')->getArguments();
  238. $this->assertSame($ref, $arguments[0]);
  239. }
  240. public function testProcessDoesNotInlineWhenServiceReferencesItself()
  241. {
  242. $container = new ContainerBuilder();
  243. $container
  244. ->register('foo')
  245. ->setPublic(false)
  246. ->addMethodCall('foo', array($ref = new Reference('foo')))
  247. ;
  248. $this->process($container);
  249. $calls = $container->getDefinition('foo')->getMethodCalls();
  250. $this->assertSame($ref, $calls[0][1][0]);
  251. }
  252. public function testProcessDoesNotSetLazyArgumentValuesAfterInlining()
  253. {
  254. $container = new ContainerBuilder();
  255. $container
  256. ->register('inline')
  257. ->setShared(false)
  258. ;
  259. $container
  260. ->register('service-closure')
  261. ->setArguments(array(new ServiceClosureArgument(new Reference('inline'))))
  262. ;
  263. $container
  264. ->register('iterator')
  265. ->setArguments(array(new IteratorArgument(array(new Reference('inline')))))
  266. ;
  267. $this->process($container);
  268. $values = $container->getDefinition('service-closure')->getArgument(0)->getValues();
  269. $this->assertInstanceOf(Reference::class, $values[0]);
  270. $this->assertSame('inline', (string) $values[0]);
  271. $values = $container->getDefinition('iterator')->getArgument(0)->getValues();
  272. $this->assertInstanceOf(Reference::class, $values[0]);
  273. $this->assertSame('inline', (string) $values[0]);
  274. }
  275. public function testGetInlinedServiceIdData()
  276. {
  277. $container = new ContainerBuilder();
  278. $container
  279. ->register('inlinable.service')
  280. ->setPublic(false)
  281. ;
  282. $container
  283. ->register('non_inlinable.service')
  284. ->setPublic(true)
  285. ;
  286. $container
  287. ->register('other_service')
  288. ->setArguments(array(new Reference('inlinable.service')))
  289. ;
  290. $inlinePass = new InlineServiceDefinitionsPass();
  291. $repeatedPass = new RepeatedPass(array(new AnalyzeServiceReferencesPass(), $inlinePass));
  292. $repeatedPass->process($container);
  293. $this->assertEquals(array('inlinable.service' => array('other_service')), $inlinePass->getInlinedServiceIds());
  294. }
  295. protected function process(ContainerBuilder $container)
  296. {
  297. $repeatedPass = new RepeatedPass(array(new AnalyzeServiceReferencesPass(), new InlineServiceDefinitionsPass()));
  298. $repeatedPass->process($container);
  299. }
  300. }