ContainerBuilderTest.php 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232
  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;
  11. require_once __DIR__.'/Fixtures/includes/classes.php';
  12. require_once __DIR__.'/Fixtures/includes/ProjectExtension.php';
  13. use PHPUnit\Framework\TestCase;
  14. use Psr\Container\ContainerInterface as PsrContainerInterface;
  15. use Symfony\Component\Config\Resource\ComposerResource;
  16. use Symfony\Component\Config\Resource\ResourceInterface;
  17. use Symfony\Component\Config\Resource\DirectoryResource;
  18. use Symfony\Component\DependencyInjection\Alias;
  19. use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
  20. use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
  21. use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
  22. use Symfony\Component\DependencyInjection\ChildDefinition;
  23. use Symfony\Component\DependencyInjection\Compiler\PassConfig;
  24. use Symfony\Component\DependencyInjection\ContainerBuilder;
  25. use Symfony\Component\DependencyInjection\ContainerInterface;
  26. use Symfony\Component\DependencyInjection\Definition;
  27. use Symfony\Component\DependencyInjection\Exception\RuntimeException;
  28. use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
  29. use Symfony\Component\DependencyInjection\Loader\ClosureLoader;
  30. use Symfony\Component\DependencyInjection\Reference;
  31. use Symfony\Component\DependencyInjection\TypedReference;
  32. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
  33. use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
  34. use Symfony\Component\Config\Resource\FileResource;
  35. use Symfony\Component\DependencyInjection\ServiceLocator;
  36. use Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition;
  37. use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass;
  38. use Symfony\Component\ExpressionLanguage\Expression;
  39. class ContainerBuilderTest extends TestCase
  40. {
  41. public function testDefaultRegisteredDefinitions()
  42. {
  43. $builder = new ContainerBuilder();
  44. $this->assertCount(1, $builder->getDefinitions());
  45. $this->assertTrue($builder->hasDefinition('service_container'));
  46. $definition = $builder->getDefinition('service_container');
  47. $this->assertInstanceOf(Definition::class, $definition);
  48. $this->assertTrue($definition->isSynthetic());
  49. $this->assertSame(ContainerInterface::class, $definition->getClass());
  50. $this->assertTrue($builder->hasAlias(PsrContainerInterface::class));
  51. $this->assertTrue($builder->hasAlias(ContainerInterface::class));
  52. }
  53. public function testDefinitions()
  54. {
  55. $builder = new ContainerBuilder();
  56. $definitions = array(
  57. 'foo' => new Definition('Bar\FooClass'),
  58. 'bar' => new Definition('BarClass'),
  59. );
  60. $builder->setDefinitions($definitions);
  61. $this->assertEquals($definitions, $builder->getDefinitions(), '->setDefinitions() sets the service definitions');
  62. $this->assertTrue($builder->hasDefinition('foo'), '->hasDefinition() returns true if a service definition exists');
  63. $this->assertFalse($builder->hasDefinition('foobar'), '->hasDefinition() returns false if a service definition does not exist');
  64. $builder->setDefinition('foobar', $foo = new Definition('FooBarClass'));
  65. $this->assertEquals($foo, $builder->getDefinition('foobar'), '->getDefinition() returns a service definition if defined');
  66. $this->assertSame($builder->setDefinition('foobar', $foo = new Definition('FooBarClass')), $foo, '->setDefinition() implements a fluid interface by returning the service reference');
  67. $builder->addDefinitions($defs = array('foobar' => new Definition('FooBarClass')));
  68. $this->assertEquals(array_merge($definitions, $defs), $builder->getDefinitions(), '->addDefinitions() adds the service definitions');
  69. try {
  70. $builder->getDefinition('baz');
  71. $this->fail('->getDefinition() throws a ServiceNotFoundException if the service definition does not exist');
  72. } catch (ServiceNotFoundException $e) {
  73. $this->assertEquals('You have requested a non-existent service "baz".', $e->getMessage(), '->getDefinition() throws a ServiceNotFoundException if the service definition does not exist');
  74. }
  75. }
  76. /**
  77. * @group legacy
  78. * @expectedDeprecation The "deprecated_foo" service is deprecated. You should stop using it, as it will soon be removed.
  79. */
  80. public function testCreateDeprecatedService()
  81. {
  82. $definition = new Definition('stdClass');
  83. $definition->setDeprecated(true);
  84. $builder = new ContainerBuilder();
  85. $builder->setDefinition('deprecated_foo', $definition);
  86. $builder->get('deprecated_foo');
  87. }
  88. public function testRegister()
  89. {
  90. $builder = new ContainerBuilder();
  91. $builder->register('foo', 'Bar\FooClass');
  92. $this->assertTrue($builder->hasDefinition('foo'), '->register() registers a new service definition');
  93. $this->assertInstanceOf('Symfony\Component\DependencyInjection\Definition', $builder->getDefinition('foo'), '->register() returns the newly created Definition instance');
  94. }
  95. public function testAutowire()
  96. {
  97. $builder = new ContainerBuilder();
  98. $builder->autowire('foo', 'Bar\FooClass');
  99. $this->assertTrue($builder->hasDefinition('foo'), '->autowire() registers a new service definition');
  100. $this->assertTrue($builder->getDefinition('foo')->isAutowired(), '->autowire() creates autowired definitions');
  101. }
  102. public function testHas()
  103. {
  104. $builder = new ContainerBuilder();
  105. $this->assertFalse($builder->has('foo'), '->has() returns false if the service does not exist');
  106. $builder->register('foo', 'Bar\FooClass');
  107. $this->assertTrue($builder->has('foo'), '->has() returns true if a service definition exists');
  108. $builder->set('bar', new \stdClass());
  109. $this->assertTrue($builder->has('bar'), '->has() returns true if a service exists');
  110. }
  111. /**
  112. * @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException
  113. * @expectedExceptionMessage You have requested a non-existent service "foo".
  114. */
  115. public function testGetThrowsExceptionIfServiceDoesNotExist()
  116. {
  117. $builder = new ContainerBuilder();
  118. $builder->get('foo');
  119. }
  120. public function testGetReturnsNullIfServiceDoesNotExistAndInvalidReferenceIsUsed()
  121. {
  122. $builder = new ContainerBuilder();
  123. $this->assertNull($builder->get('foo', ContainerInterface::NULL_ON_INVALID_REFERENCE), '->get() returns null if the service does not exist and NULL_ON_INVALID_REFERENCE is passed as a second argument');
  124. }
  125. /**
  126. * @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException
  127. */
  128. public function testGetThrowsCircularReferenceExceptionIfServiceHasReferenceToItself()
  129. {
  130. $builder = new ContainerBuilder();
  131. $builder->register('baz', 'stdClass')->setArguments(array(new Reference('baz')));
  132. $builder->get('baz');
  133. }
  134. public function testGetReturnsSameInstanceWhenServiceIsShared()
  135. {
  136. $builder = new ContainerBuilder();
  137. $builder->register('bar', 'stdClass');
  138. $this->assertTrue($builder->get('bar') === $builder->get('bar'), '->get() always returns the same instance if the service is shared');
  139. }
  140. public function testGetCreatesServiceBasedOnDefinition()
  141. {
  142. $builder = new ContainerBuilder();
  143. $builder->register('foo', 'stdClass');
  144. $this->assertInternalType('object', $builder->get('foo'), '->get() returns the service definition associated with the id');
  145. }
  146. public function testGetReturnsRegisteredService()
  147. {
  148. $builder = new ContainerBuilder();
  149. $builder->set('bar', $bar = new \stdClass());
  150. $this->assertSame($bar, $builder->get('bar'), '->get() returns the service associated with the id');
  151. }
  152. public function testRegisterDoesNotOverrideExistingService()
  153. {
  154. $builder = new ContainerBuilder();
  155. $builder->set('bar', $bar = new \stdClass());
  156. $builder->register('bar', 'stdClass');
  157. $this->assertSame($bar, $builder->get('bar'), '->get() returns the service associated with the id even if a definition has been defined');
  158. }
  159. public function testNonSharedServicesReturnsDifferentInstances()
  160. {
  161. $builder = new ContainerBuilder();
  162. $builder->register('bar', 'stdClass')->setShared(false);
  163. $this->assertNotSame($builder->get('bar'), $builder->get('bar'));
  164. }
  165. /**
  166. * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
  167. * @expectedExceptionMessage You have requested a synthetic service ("foo"). The DIC does not know how to construct this service.
  168. */
  169. public function testGetUnsetLoadingServiceWhenCreateServiceThrowsAnException()
  170. {
  171. $builder = new ContainerBuilder();
  172. $builder->register('foo', 'stdClass')->setSynthetic(true);
  173. // we expect a RuntimeException here as foo is synthetic
  174. try {
  175. $builder->get('foo');
  176. } catch (RuntimeException $e) {
  177. }
  178. // we must also have the same RuntimeException here
  179. $builder->get('foo');
  180. }
  181. public function testGetServiceIds()
  182. {
  183. $builder = new ContainerBuilder();
  184. $builder->register('foo', 'stdClass');
  185. $builder->bar = $bar = new \stdClass();
  186. $builder->register('bar', 'stdClass');
  187. $this->assertEquals(
  188. array(
  189. 'service_container',
  190. 'foo',
  191. 'bar',
  192. 'Psr\Container\ContainerInterface',
  193. 'Symfony\Component\DependencyInjection\ContainerInterface',
  194. ),
  195. $builder->getServiceIds(),
  196. '->getServiceIds() returns all defined service ids'
  197. );
  198. }
  199. public function testAliases()
  200. {
  201. $builder = new ContainerBuilder();
  202. $builder->register('foo', 'stdClass');
  203. $builder->setAlias('bar', 'foo');
  204. $this->assertTrue($builder->hasAlias('bar'), '->hasAlias() returns true if the alias exists');
  205. $this->assertFalse($builder->hasAlias('foobar'), '->hasAlias() returns false if the alias does not exist');
  206. $this->assertEquals('foo', (string) $builder->getAlias('bar'), '->getAlias() returns the aliased service');
  207. $this->assertTrue($builder->has('bar'), '->setAlias() defines a new service');
  208. $this->assertSame($builder->get('bar'), $builder->get('foo'), '->setAlias() creates a service that is an alias to another one');
  209. try {
  210. $builder->setAlias('foobar', 'foobar');
  211. $this->fail('->setAlias() throws an InvalidArgumentException if the alias references itself');
  212. } catch (\InvalidArgumentException $e) {
  213. $this->assertEquals('An alias can not reference itself, got a circular reference on "foobar".', $e->getMessage(), '->setAlias() throws an InvalidArgumentException if the alias references itself');
  214. }
  215. try {
  216. $builder->getAlias('foobar');
  217. $this->fail('->getAlias() throws an InvalidArgumentException if the alias does not exist');
  218. } catch (\InvalidArgumentException $e) {
  219. $this->assertEquals('The service alias "foobar" does not exist.', $e->getMessage(), '->getAlias() throws an InvalidArgumentException if the alias does not exist');
  220. }
  221. }
  222. public function testGetAliases()
  223. {
  224. $builder = new ContainerBuilder();
  225. $builder->setAlias('bar', 'foo');
  226. $builder->setAlias('foobar', 'foo');
  227. $builder->setAlias('moo', new Alias('foo', false));
  228. $aliases = $builder->getAliases();
  229. $this->assertEquals('foo', (string) $aliases['bar']);
  230. $this->assertTrue($aliases['bar']->isPublic());
  231. $this->assertEquals('foo', (string) $aliases['foobar']);
  232. $this->assertEquals('foo', (string) $aliases['moo']);
  233. $this->assertFalse($aliases['moo']->isPublic());
  234. $builder->register('bar', 'stdClass');
  235. $this->assertFalse($builder->hasAlias('bar'));
  236. $builder->set('foobar', 'stdClass');
  237. $builder->set('moo', 'stdClass');
  238. $this->assertCount(2, $builder->getAliases(), '->getAliases() does not return aliased services that have been overridden');
  239. }
  240. public function testSetAliases()
  241. {
  242. $builder = new ContainerBuilder();
  243. $builder->setAliases(array('bar' => 'foo', 'foobar' => 'foo'));
  244. $aliases = $builder->getAliases();
  245. $this->assertArrayHasKey('bar', $aliases);
  246. $this->assertArrayHasKey('foobar', $aliases);
  247. }
  248. public function testAddAliases()
  249. {
  250. $builder = new ContainerBuilder();
  251. $builder->setAliases(array('bar' => 'foo'));
  252. $builder->addAliases(array('foobar' => 'foo'));
  253. $aliases = $builder->getAliases();
  254. $this->assertArrayHasKey('bar', $aliases);
  255. $this->assertArrayHasKey('foobar', $aliases);
  256. }
  257. public function testSetReplacesAlias()
  258. {
  259. $builder = new ContainerBuilder();
  260. $builder->setAlias('alias', 'aliased');
  261. $builder->set('aliased', new \stdClass());
  262. $builder->set('alias', $foo = new \stdClass());
  263. $this->assertSame($foo, $builder->get('alias'), '->set() replaces an existing alias');
  264. }
  265. public function testAliasesKeepInvalidBehavior()
  266. {
  267. $builder = new ContainerBuilder();
  268. $aliased = new Definition('stdClass');
  269. $aliased->addMethodCall('setBar', array(new Reference('bar', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)));
  270. $builder->setDefinition('aliased', $aliased);
  271. $builder->setAlias('alias', 'aliased');
  272. $this->assertEquals(new \stdClass(), $builder->get('alias'));
  273. }
  274. public function testAddGetCompilerPass()
  275. {
  276. $builder = new ContainerBuilder();
  277. $builder->setResourceTracking(false);
  278. $defaultPasses = $builder->getCompiler()->getPassConfig()->getPasses();
  279. $builder->addCompilerPass($pass1 = $this->getMockBuilder('Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface')->getMock(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -5);
  280. $builder->addCompilerPass($pass2 = $this->getMockBuilder('Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface')->getMock(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 10);
  281. $passes = $builder->getCompiler()->getPassConfig()->getPasses();
  282. $this->assertCount(count($passes) - 2, $defaultPasses);
  283. // Pass 1 is executed later
  284. $this->assertTrue(array_search($pass1, $passes, true) > array_search($pass2, $passes, true));
  285. }
  286. public function testCreateService()
  287. {
  288. $builder = new ContainerBuilder();
  289. $builder->register('foo1', 'Bar\FooClass')->setFile(__DIR__.'/Fixtures/includes/foo.php');
  290. $builder->register('foo2', 'Bar\FooClass')->setFile(__DIR__.'/Fixtures/includes/%file%.php');
  291. $builder->setParameter('file', 'foo');
  292. $this->assertInstanceOf('\Bar\FooClass', $builder->get('foo1'), '->createService() requires the file defined by the service definition');
  293. $this->assertInstanceOf('\Bar\FooClass', $builder->get('foo2'), '->createService() replaces parameters in the file provided by the service definition');
  294. }
  295. public function testCreateProxyWithRealServiceInstantiator()
  296. {
  297. $builder = new ContainerBuilder();
  298. $builder->register('foo1', 'Bar\FooClass')->setFile(__DIR__.'/Fixtures/includes/foo.php');
  299. $builder->getDefinition('foo1')->setLazy(true);
  300. $foo1 = $builder->get('foo1');
  301. $this->assertSame($foo1, $builder->get('foo1'), 'The same proxy is retrieved on multiple subsequent calls');
  302. $this->assertSame('Bar\FooClass', get_class($foo1));
  303. }
  304. public function testCreateServiceClass()
  305. {
  306. $builder = new ContainerBuilder();
  307. $builder->register('foo1', '%class%');
  308. $builder->setParameter('class', 'stdClass');
  309. $this->assertInstanceOf('\stdClass', $builder->get('foo1'), '->createService() replaces parameters in the class provided by the service definition');
  310. }
  311. public function testCreateServiceArguments()
  312. {
  313. $builder = new ContainerBuilder();
  314. $builder->register('bar', 'stdClass');
  315. $builder->register('foo1', 'Bar\FooClass')->addArgument(array('foo' => '%value%', '%value%' => 'foo', new Reference('bar'), '%%unescape_it%%'));
  316. $builder->setParameter('value', 'bar');
  317. $this->assertEquals(array('foo' => 'bar', 'bar' => 'foo', $builder->get('bar'), '%unescape_it%'), $builder->get('foo1')->arguments, '->createService() replaces parameters and service references in the arguments provided by the service definition');
  318. }
  319. public function testCreateServiceFactory()
  320. {
  321. $builder = new ContainerBuilder();
  322. $builder->register('foo', 'Bar\FooClass')->setFactory('Bar\FooClass::getInstance');
  323. $builder->register('qux', 'Bar\FooClass')->setFactory(array('Bar\FooClass', 'getInstance'));
  324. $builder->register('bar', 'Bar\FooClass')->setFactory(array(new Definition('Bar\FooClass'), 'getInstance'));
  325. $builder->register('baz', 'Bar\FooClass')->setFactory(array(new Reference('bar'), 'getInstance'));
  326. $this->assertTrue($builder->get('foo')->called, '->createService() calls the factory method to create the service instance');
  327. $this->assertTrue($builder->get('qux')->called, '->createService() calls the factory method to create the service instance');
  328. $this->assertTrue($builder->get('bar')->called, '->createService() uses anonymous service as factory');
  329. $this->assertTrue($builder->get('baz')->called, '->createService() uses another service as factory');
  330. }
  331. public function testCreateServiceMethodCalls()
  332. {
  333. $builder = new ContainerBuilder();
  334. $builder->register('bar', 'stdClass');
  335. $builder->register('foo1', 'Bar\FooClass')->addMethodCall('setBar', array(array('%value%', new Reference('bar'))));
  336. $builder->setParameter('value', 'bar');
  337. $this->assertEquals(array('bar', $builder->get('bar')), $builder->get('foo1')->bar, '->createService() replaces the values in the method calls arguments');
  338. }
  339. public function testCreateServiceMethodCallsWithEscapedParam()
  340. {
  341. $builder = new ContainerBuilder();
  342. $builder->register('bar', 'stdClass');
  343. $builder->register('foo1', 'Bar\FooClass')->addMethodCall('setBar', array(array('%%unescape_it%%')));
  344. $builder->setParameter('value', 'bar');
  345. $this->assertEquals(array('%unescape_it%'), $builder->get('foo1')->bar, '->createService() replaces the values in the method calls arguments');
  346. }
  347. public function testCreateServiceProperties()
  348. {
  349. $builder = new ContainerBuilder();
  350. $builder->register('bar', 'stdClass');
  351. $builder->register('foo1', 'Bar\FooClass')->setProperty('bar', array('%value%', new Reference('bar'), '%%unescape_it%%'));
  352. $builder->setParameter('value', 'bar');
  353. $this->assertEquals(array('bar', $builder->get('bar'), '%unescape_it%'), $builder->get('foo1')->bar, '->createService() replaces the values in the properties');
  354. }
  355. public function testCreateServiceConfigurator()
  356. {
  357. $builder = new ContainerBuilder();
  358. $builder->register('foo1', 'Bar\FooClass')->setConfigurator('sc_configure');
  359. $builder->register('foo2', 'Bar\FooClass')->setConfigurator(array('%class%', 'configureStatic'));
  360. $builder->setParameter('class', 'BazClass');
  361. $builder->register('baz', 'BazClass');
  362. $builder->register('foo3', 'Bar\FooClass')->setConfigurator(array(new Reference('baz'), 'configure'));
  363. $builder->register('foo4', 'Bar\FooClass')->setConfigurator(array($builder->getDefinition('baz'), 'configure'));
  364. $builder->register('foo5', 'Bar\FooClass')->setConfigurator('foo');
  365. $this->assertTrue($builder->get('foo1')->configured, '->createService() calls the configurator');
  366. $this->assertTrue($builder->get('foo2')->configured, '->createService() calls the configurator');
  367. $this->assertTrue($builder->get('foo3')->configured, '->createService() calls the configurator');
  368. $this->assertTrue($builder->get('foo4')->configured, '->createService() calls the configurator');
  369. try {
  370. $builder->get('foo5');
  371. $this->fail('->createService() throws an InvalidArgumentException if the configure callable is not a valid callable');
  372. } catch (\InvalidArgumentException $e) {
  373. $this->assertEquals('The configure callable for class "Bar\FooClass" is not a callable.', $e->getMessage(), '->createService() throws an InvalidArgumentException if the configure callable is not a valid callable');
  374. }
  375. }
  376. public function testCreateServiceWithIteratorArgument()
  377. {
  378. $builder = new ContainerBuilder();
  379. $builder->register('bar', 'stdClass');
  380. $builder
  381. ->register('lazy_context', 'LazyContext')
  382. ->setArguments(array(
  383. new IteratorArgument(array('k1' => new Reference('bar'), new Reference('invalid', ContainerInterface::IGNORE_ON_INVALID_REFERENCE))),
  384. new IteratorArgument(array()),
  385. ))
  386. ;
  387. $lazyContext = $builder->get('lazy_context');
  388. $this->assertInstanceOf(RewindableGenerator::class, $lazyContext->lazyValues);
  389. $this->assertInstanceOf(RewindableGenerator::class, $lazyContext->lazyEmptyValues);
  390. $this->assertCount(1, $lazyContext->lazyValues);
  391. $this->assertCount(0, $lazyContext->lazyEmptyValues);
  392. $i = 0;
  393. foreach ($lazyContext->lazyValues as $k => $v) {
  394. ++$i;
  395. $this->assertEquals('k1', $k);
  396. $this->assertInstanceOf('\stdClass', $v);
  397. }
  398. // The second argument should have been ignored.
  399. $this->assertEquals(1, $i);
  400. $i = 0;
  401. foreach ($lazyContext->lazyEmptyValues as $k => $v) {
  402. ++$i;
  403. }
  404. $this->assertEquals(0, $i);
  405. }
  406. /**
  407. * @expectedException \RuntimeException
  408. */
  409. public function testCreateSyntheticService()
  410. {
  411. $builder = new ContainerBuilder();
  412. $builder->register('foo', 'Bar\FooClass')->setSynthetic(true);
  413. $builder->get('foo');
  414. }
  415. public function testCreateServiceWithExpression()
  416. {
  417. $builder = new ContainerBuilder();
  418. $builder->setParameter('bar', 'bar');
  419. $builder->register('bar', 'BarClass');
  420. $builder->register('foo', 'Bar\FooClass')->addArgument(array('foo' => new Expression('service("bar").foo ~ parameter("bar")')));
  421. $this->assertEquals('foobar', $builder->get('foo')->arguments['foo']);
  422. }
  423. public function testResolveServices()
  424. {
  425. $builder = new ContainerBuilder();
  426. $builder->register('foo', 'Bar\FooClass');
  427. $this->assertEquals($builder->get('foo'), $builder->resolveServices(new Reference('foo')), '->resolveServices() resolves service references to service instances');
  428. $this->assertEquals(array('foo' => array('foo', $builder->get('foo'))), $builder->resolveServices(array('foo' => array('foo', new Reference('foo')))), '->resolveServices() resolves service references to service instances in nested arrays');
  429. $this->assertEquals($builder->get('foo'), $builder->resolveServices(new Expression('service("foo")')), '->resolveServices() resolves expressions');
  430. }
  431. /**
  432. * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
  433. * @expectedExceptionMessage Constructing service "foo" from a parent definition is not supported at build time.
  434. */
  435. public function testResolveServicesWithDecoratedDefinition()
  436. {
  437. $builder = new ContainerBuilder();
  438. $builder->setDefinition('grandpa', new Definition('stdClass'));
  439. $builder->setDefinition('parent', new ChildDefinition('grandpa'));
  440. $builder->setDefinition('foo', new ChildDefinition('parent'));
  441. $builder->get('foo');
  442. }
  443. public function testResolveServicesWithCustomDefinitionClass()
  444. {
  445. $builder = new ContainerBuilder();
  446. $builder->setDefinition('foo', new CustomDefinition('stdClass'));
  447. $this->assertInstanceOf('stdClass', $builder->get('foo'));
  448. }
  449. public function testMerge()
  450. {
  451. $container = new ContainerBuilder(new ParameterBag(array('bar' => 'foo')));
  452. $container->setResourceTracking(false);
  453. $config = new ContainerBuilder(new ParameterBag(array('foo' => 'bar')));
  454. $container->merge($config);
  455. $this->assertEquals(array('bar' => 'foo', 'foo' => 'bar'), $container->getParameterBag()->all(), '->merge() merges current parameters with the loaded ones');
  456. $container = new ContainerBuilder(new ParameterBag(array('bar' => 'foo')));
  457. $container->setResourceTracking(false);
  458. $config = new ContainerBuilder(new ParameterBag(array('foo' => '%bar%')));
  459. $container->merge($config);
  460. $container->compile();
  461. $this->assertEquals(array('bar' => 'foo', 'foo' => 'foo'), $container->getParameterBag()->all(), '->merge() evaluates the values of the parameters towards already defined ones');
  462. $container = new ContainerBuilder(new ParameterBag(array('bar' => 'foo')));
  463. $container->setResourceTracking(false);
  464. $config = new ContainerBuilder(new ParameterBag(array('foo' => '%bar%', 'baz' => '%foo%')));
  465. $container->merge($config);
  466. $container->compile();
  467. $this->assertEquals(array('bar' => 'foo', 'foo' => 'foo', 'baz' => 'foo'), $container->getParameterBag()->all(), '->merge() evaluates the values of the parameters towards already defined ones');
  468. $container = new ContainerBuilder();
  469. $container->setResourceTracking(false);
  470. $container->register('foo', 'Bar\FooClass');
  471. $container->register('bar', 'BarClass');
  472. $config = new ContainerBuilder();
  473. $config->setDefinition('baz', new Definition('BazClass'));
  474. $config->setAlias('alias_for_foo', 'foo');
  475. $container->merge($config);
  476. $this->assertEquals(array('service_container', 'foo', 'bar', 'baz'), array_keys($container->getDefinitions()), '->merge() merges definitions already defined ones');
  477. $aliases = $container->getAliases();
  478. $this->assertArrayHasKey('alias_for_foo', $aliases);
  479. $this->assertEquals('foo', (string) $aliases['alias_for_foo']);
  480. $container = new ContainerBuilder();
  481. $container->setResourceTracking(false);
  482. $container->register('foo', 'Bar\FooClass');
  483. $config->setDefinition('foo', new Definition('BazClass'));
  484. $container->merge($config);
  485. $this->assertEquals('BazClass', $container->getDefinition('foo')->getClass(), '->merge() overrides already defined services');
  486. $container = new ContainerBuilder();
  487. $bag = new EnvPlaceholderParameterBag();
  488. $bag->get('env(Foo)');
  489. $config = new ContainerBuilder($bag);
  490. $this->assertSame(array('%env(Bar)%'), $config->resolveEnvPlaceholders(array($bag->get('env(Bar)'))));
  491. $container->merge($config);
  492. $this->assertEquals(array('Foo' => 0, 'Bar' => 1), $container->getEnvCounters());
  493. $container = new ContainerBuilder();
  494. $config = new ContainerBuilder();
  495. $childDefA = $container->registerForAutoconfiguration('AInterface');
  496. $childDefB = $config->registerForAutoconfiguration('BInterface');
  497. $container->merge($config);
  498. $this->assertSame(array('AInterface' => $childDefA, 'BInterface' => $childDefB), $container->getAutoconfiguredInstanceof());
  499. }
  500. /**
  501. * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
  502. * @expectedExceptionMessage "AInterface" has already been autoconfigured and merge() does not support merging autoconfiguration for the same class/interface.
  503. */
  504. public function testMergeThrowsExceptionForDuplicateAutomaticInstanceofDefinitions()
  505. {
  506. $container = new ContainerBuilder();
  507. $config = new ContainerBuilder();
  508. $container->registerForAutoconfiguration('AInterface');
  509. $config->registerForAutoconfiguration('AInterface');
  510. $container->merge($config);
  511. }
  512. public function testResolveEnvValues()
  513. {
  514. $_ENV['DUMMY_ENV_VAR'] = 'du%%y';
  515. $_SERVER['DUMMY_SERVER_VAR'] = 'ABC';
  516. $_SERVER['HTTP_DUMMY_VAR'] = 'DEF';
  517. $container = new ContainerBuilder();
  518. $container->setParameter('bar', '%% %env(DUMMY_ENV_VAR)% %env(DUMMY_SERVER_VAR)% %env(HTTP_DUMMY_VAR)%');
  519. $container->setParameter('env(HTTP_DUMMY_VAR)', '123');
  520. $this->assertSame('%% du%%%%y ABC 123', $container->resolveEnvPlaceholders('%bar%', true));
  521. unset($_ENV['DUMMY_ENV_VAR'], $_SERVER['DUMMY_SERVER_VAR'], $_SERVER['HTTP_DUMMY_VAR']);
  522. }
  523. public function testResolveEnvValuesWithArray()
  524. {
  525. $_ENV['ANOTHER_DUMMY_ENV_VAR'] = 'dummy';
  526. $dummyArray = array('1' => 'one', '2' => 'two');
  527. $container = new ContainerBuilder();
  528. $container->setParameter('dummy', '%env(ANOTHER_DUMMY_ENV_VAR)%');
  529. $container->setParameter('dummy2', $dummyArray);
  530. $container->resolveEnvPlaceholders('%dummy%', true);
  531. $container->resolveEnvPlaceholders('%dummy2%', true);
  532. $this->assertInternalType('array', $container->resolveEnvPlaceholders('%dummy2%', true));
  533. foreach ($dummyArray as $key => $value) {
  534. $this->assertArrayHasKey($key, $container->resolveEnvPlaceholders('%dummy2%', true));
  535. }
  536. unset($_ENV['ANOTHER_DUMMY_ENV_VAR']);
  537. }
  538. public function testCompileWithResolveEnv()
  539. {
  540. putenv('DUMMY_ENV_VAR=du%%y');
  541. $_SERVER['DUMMY_SERVER_VAR'] = 'ABC';
  542. $_SERVER['HTTP_DUMMY_VAR'] = 'DEF';
  543. $container = new ContainerBuilder();
  544. $container->setParameter('env(FOO)', 'Foo');
  545. $container->setParameter('env(DUMMY_ENV_VAR)', 'GHI');
  546. $container->setParameter('bar', '%% %env(DUMMY_ENV_VAR)% %env(DUMMY_SERVER_VAR)% %env(HTTP_DUMMY_VAR)%');
  547. $container->setParameter('foo', '%env(FOO)%');
  548. $container->setParameter('baz', '%foo%');
  549. $container->setParameter('env(HTTP_DUMMY_VAR)', '123');
  550. $container->register('teatime', 'stdClass')
  551. ->setProperty('foo', '%env(DUMMY_ENV_VAR)%')
  552. ;
  553. $container->compile(true);
  554. $this->assertSame('% du%%y ABC 123', $container->getParameter('bar'));
  555. $this->assertSame('Foo', $container->getParameter('baz'));
  556. $this->assertSame('du%%y', $container->get('teatime')->foo);
  557. unset($_SERVER['DUMMY_SERVER_VAR'], $_SERVER['HTTP_DUMMY_VAR']);
  558. putenv('DUMMY_ENV_VAR');
  559. }
  560. /**
  561. * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
  562. * @expectedExceptionMessage A string value must be composed of strings and/or numbers, but found parameter "env(ARRAY)" of type array inside string value "ABC %env(ARRAY)%".
  563. */
  564. public function testCompileWithArrayResolveEnv()
  565. {
  566. $bag = new TestingEnvPlaceholderParameterBag();
  567. $container = new ContainerBuilder($bag);
  568. $container->setParameter('foo', '%env(ARRAY)%');
  569. $container->setParameter('bar', 'ABC %env(ARRAY)%');
  570. $container->compile(true);
  571. }
  572. /**
  573. * @expectedException \Symfony\Component\DependencyInjection\Exception\EnvNotFoundException
  574. * @expectedExceptionMessage Environment variable not found: "FOO".
  575. */
  576. public function testCompileWithResolveMissingEnv()
  577. {
  578. $container = new ContainerBuilder();
  579. $container->setParameter('foo', '%env(FOO)%');
  580. $container->compile(true);
  581. }
  582. public function testEnvInId()
  583. {
  584. $container = include __DIR__.'/Fixtures/containers/container_env_in_id.php';
  585. $container->compile(true);
  586. $expected = array(
  587. 'service_container',
  588. 'foo',
  589. 'bar',
  590. 'bar_%env(BAR)%',
  591. );
  592. $this->assertSame($expected, array_keys($container->getDefinitions()));
  593. $this->assertSame(array('baz_bar'), array_keys($container->getDefinition('foo')->getArgument(1)));
  594. }
  595. /**
  596. * @expectedException \LogicException
  597. */
  598. public function testMergeLogicException()
  599. {
  600. $container = new ContainerBuilder();
  601. $container->setResourceTracking(false);
  602. $container->compile();
  603. $container->merge(new ContainerBuilder());
  604. }
  605. public function testfindTaggedServiceIds()
  606. {
  607. $builder = new ContainerBuilder();
  608. $builder
  609. ->register('foo', 'Bar\FooClass')
  610. ->addTag('foo', array('foo' => 'foo'))
  611. ->addTag('bar', array('bar' => 'bar'))
  612. ->addTag('foo', array('foofoo' => 'foofoo'))
  613. ;
  614. $this->assertEquals($builder->findTaggedServiceIds('foo'), array(
  615. 'foo' => array(
  616. array('foo' => 'foo'),
  617. array('foofoo' => 'foofoo'),
  618. ),
  619. ), '->findTaggedServiceIds() returns an array of service ids and its tag attributes');
  620. $this->assertEquals(array(), $builder->findTaggedServiceIds('foobar'), '->findTaggedServiceIds() returns an empty array if there is annotated services');
  621. }
  622. public function testFindUnusedTags()
  623. {
  624. $builder = new ContainerBuilder();
  625. $builder
  626. ->register('foo', 'Bar\FooClass')
  627. ->addTag('kernel.event_listener', array('foo' => 'foo'))
  628. ->addTag('kenrel.event_listener', array('bar' => 'bar'))
  629. ;
  630. $builder->findTaggedServiceIds('kernel.event_listener');
  631. $this->assertEquals(array('kenrel.event_listener'), $builder->findUnusedTags(), '->findUnusedTags() returns an array with unused tags');
  632. }
  633. public function testFindDefinition()
  634. {
  635. $container = new ContainerBuilder();
  636. $container->setDefinition('foo', $definition = new Definition('Bar\FooClass'));
  637. $container->setAlias('bar', 'foo');
  638. $container->setAlias('foobar', 'bar');
  639. $this->assertEquals($definition, $container->findDefinition('foobar'), '->findDefinition() returns a Definition');
  640. }
  641. public function testAddObjectResource()
  642. {
  643. $container = new ContainerBuilder();
  644. $container->setResourceTracking(false);
  645. $container->addObjectResource(new \BarClass());
  646. $this->assertEmpty($container->getResources(), 'No resources get registered without resource tracking');
  647. $container->setResourceTracking(true);
  648. $container->addObjectResource(new \BarClass());
  649. $resources = $container->getResources();
  650. $this->assertCount(2, $resources, '2 resources were registered');
  651. /* @var $resource \Symfony\Component\Config\Resource\FileResource */
  652. $resource = end($resources);
  653. $this->assertInstanceOf('Symfony\Component\Config\Resource\FileResource', $resource);
  654. $this->assertSame(realpath(__DIR__.'/Fixtures/includes/classes.php'), realpath($resource->getResource()));
  655. }
  656. /**
  657. * @group legacy
  658. */
  659. public function testAddClassResource()
  660. {
  661. $container = new ContainerBuilder();
  662. $container->setResourceTracking(false);
  663. $container->addClassResource(new \ReflectionClass('BarClass'));
  664. $this->assertEmpty($container->getResources(), 'No resources get registered without resource tracking');
  665. $container->setResourceTracking(true);
  666. $container->addClassResource(new \ReflectionClass('BarClass'));
  667. $resources = $container->getResources();
  668. $this->assertCount(2, $resources, '2 resources were registered');
  669. /* @var $resource \Symfony\Component\Config\Resource\FileResource */
  670. $resource = end($resources);
  671. $this->assertInstanceOf('Symfony\Component\Config\Resource\FileResource', $resource);
  672. $this->assertSame(realpath(__DIR__.'/Fixtures/includes/classes.php'), realpath($resource->getResource()));
  673. }
  674. public function testGetReflectionClass()
  675. {
  676. $container = new ContainerBuilder();
  677. $container->setResourceTracking(false);
  678. $r1 = $container->getReflectionClass('BarClass');
  679. $this->assertEmpty($container->getResources(), 'No resources get registered without resource tracking');
  680. $container->setResourceTracking(true);
  681. $r2 = $container->getReflectionClass('BarClass');
  682. $r3 = $container->getReflectionClass('BarClass');
  683. $this->assertNull($container->getReflectionClass('BarMissingClass'));
  684. $this->assertEquals($r1, $r2);
  685. $this->assertSame($r2, $r3);
  686. $resources = $container->getResources();
  687. $this->assertCount(3, $resources, '3 resources were registered');
  688. $this->assertSame('reflection.BarClass', (string) $resources[1]);
  689. $this->assertSame('BarMissingClass', (string) end($resources));
  690. }
  691. public function testCompilesClassDefinitionsOfLazyServices()
  692. {
  693. $container = new ContainerBuilder();
  694. $this->assertEmpty($container->getResources(), 'No resources get registered without resource tracking');
  695. $container->register('foo', 'BarClass');
  696. $container->getDefinition('foo')->setLazy(true);
  697. $container->compile();
  698. $matchingResources = array_filter(
  699. $container->getResources(),
  700. function (ResourceInterface $resource) {
  701. return 'reflection.BarClass' === (string) $resource;
  702. }
  703. );
  704. $this->assertNotEmpty($matchingResources);
  705. }
  706. public function testResources()
  707. {
  708. $container = new ContainerBuilder();
  709. $container->addResource($a = new FileResource(__DIR__.'/Fixtures/xml/services1.xml'));
  710. $container->addResource($b = new FileResource(__DIR__.'/Fixtures/xml/services2.xml'));
  711. $resources = array();
  712. foreach ($container->getResources() as $resource) {
  713. if (false === strpos($resource, '.php')) {
  714. $resources[] = $resource;
  715. }
  716. }
  717. $this->assertEquals(array($a, $b), $resources, '->getResources() returns an array of resources read for the current configuration');
  718. $this->assertSame($container, $container->setResources(array()));
  719. $this->assertEquals(array(), $container->getResources());
  720. }
  721. public function testFileExists()
  722. {
  723. $container = new ContainerBuilder();
  724. $A = new ComposerResource();
  725. $a = new FileResource(__DIR__.'/Fixtures/xml/services1.xml');
  726. $b = new FileResource(__DIR__.'/Fixtures/xml/services2.xml');
  727. $c = new DirectoryResource($dir = dirname($b));
  728. $this->assertTrue($container->fileExists((string) $a) && $container->fileExists((string) $b) && $container->fileExists($dir));
  729. $resources = array();
  730. foreach ($container->getResources() as $resource) {
  731. if (false === strpos($resource, '.php')) {
  732. $resources[] = $resource;
  733. }
  734. }
  735. $this->assertEquals(array($A, $a, $b, $c), $resources, '->getResources() returns an array of resources read for the current configuration');
  736. }
  737. public function testExtension()
  738. {
  739. $container = new ContainerBuilder();
  740. $container->setResourceTracking(false);
  741. $container->registerExtension($extension = new \ProjectExtension());
  742. $this->assertSame($container->getExtension('project'), $extension, '->registerExtension() registers an extension');
  743. $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('LogicException');
  744. $container->getExtension('no_registered');
  745. }
  746. public function testRegisteredButNotLoadedExtension()
  747. {
  748. $extension = $this->getMockBuilder('Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface')->getMock();
  749. $extension->expects($this->once())->method('getAlias')->will($this->returnValue('project'));
  750. $extension->expects($this->never())->method('load');
  751. $container = new ContainerBuilder();
  752. $container->setResourceTracking(false);
  753. $container->registerExtension($extension);
  754. $container->compile();
  755. }
  756. public function testRegisteredAndLoadedExtension()
  757. {
  758. $extension = $this->getMockBuilder('Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface')->getMock();
  759. $extension->expects($this->exactly(2))->method('getAlias')->will($this->returnValue('project'));
  760. $extension->expects($this->once())->method('load')->with(array(array('foo' => 'bar')));
  761. $container = new ContainerBuilder();
  762. $container->setResourceTracking(false);
  763. $container->registerExtension($extension);
  764. $container->loadFromExtension('project', array('foo' => 'bar'));
  765. $container->compile();
  766. }
  767. public function testPrivateServiceUser()
  768. {
  769. $fooDefinition = new Definition('BarClass');
  770. $fooUserDefinition = new Definition('BarUserClass', array(new Reference('bar')));
  771. $container = new ContainerBuilder();
  772. $container->setResourceTracking(false);
  773. $fooDefinition->setPublic(false);
  774. $container->addDefinitions(array(
  775. 'bar' => $fooDefinition,
  776. 'bar_user' => $fooUserDefinition,
  777. ));
  778. $container->compile();
  779. $this->assertInstanceOf('BarClass', $container->get('bar_user')->bar);
  780. }
  781. /**
  782. * @expectedException \BadMethodCallException
  783. */
  784. public function testThrowsExceptionWhenSetServiceOnACompiledContainer()
  785. {
  786. $container = new ContainerBuilder();
  787. $container->setResourceTracking(false);
  788. $container->setDefinition('a', new Definition('stdClass'));
  789. $container->compile();
  790. $container->set('a', new \stdClass());
  791. }
  792. public function testThrowsExceptionWhenAddServiceOnACompiledContainer()
  793. {
  794. $container = new ContainerBuilder();
  795. $container->compile();
  796. $container->set('a', $foo = new \stdClass());
  797. $this->assertSame($foo, $container->get('a'));
  798. }
  799. public function testNoExceptionWhenSetSyntheticServiceOnACompiledContainer()
  800. {
  801. $container = new ContainerBuilder();
  802. $def = new Definition('stdClass');
  803. $def->setSynthetic(true);
  804. $container->setDefinition('a', $def);
  805. $container->compile();
  806. $container->set('a', $a = new \stdClass());
  807. $this->assertEquals($a, $container->get('a'));
  808. }
  809. /**
  810. * @expectedException \BadMethodCallException
  811. */
  812. public function testThrowsExceptionWhenSetDefinitionOnACompiledContainer()
  813. {
  814. $container = new ContainerBuilder();
  815. $container->setResourceTracking(false);
  816. $container->compile();
  817. $container->setDefinition('a', new Definition());
  818. }
  819. public function testExtensionConfig()
  820. {
  821. $container = new ContainerBuilder();
  822. $configs = $container->getExtensionConfig('foo');
  823. $this->assertEmpty($configs);
  824. $first = array('foo' => 'bar');
  825. $container->prependExtensionConfig('foo', $first);
  826. $configs = $container->getExtensionConfig('foo');
  827. $this->assertEquals(array($first), $configs);
  828. $second = array('ding' => 'dong');
  829. $container->prependExtensionConfig('foo', $second);
  830. $configs = $container->getExtensionConfig('foo');
  831. $this->assertEquals(array($second, $first), $configs);
  832. }
  833. public function testAbstractAlias()
  834. {
  835. $container = new ContainerBuilder();
  836. $abstract = new Definition('AbstractClass');
  837. $abstract->setAbstract(true);
  838. $container->setDefinition('abstract_service', $abstract);
  839. $container->setAlias('abstract_alias', 'abstract_service');
  840. $container->compile();
  841. $this->assertSame('abstract_service', (string) $container->getAlias('abstract_alias'));
  842. }
  843. public function testLazyLoadedService()
  844. {
  845. $loader = new ClosureLoader($container = new ContainerBuilder());
  846. $loader->load(function (ContainerBuilder $container) {
  847. $container->set('a', new \BazClass());
  848. $definition = new Definition('BazClass');
  849. $definition->setLazy(true);
  850. $container->setDefinition('a', $definition);
  851. });
  852. $container->setResourceTracking(true);
  853. $container->compile();
  854. $r = new \ReflectionProperty($container, 'resources');
  855. $r->setAccessible(true);
  856. $resources = $r->getValue($container);
  857. $classInList = false;
  858. foreach ($resources as $resource) {
  859. if ('reflection.BazClass' === (string) $resource) {
  860. $classInList = true;
  861. break;
  862. }
  863. }
  864. $this->assertTrue($classInList);
  865. }
  866. public function testInlinedDefinitions()
  867. {
  868. $container = new ContainerBuilder();
  869. $definition = new Definition('BarClass');
  870. $container->register('bar_user', 'BarUserClass')
  871. ->addArgument($definition)
  872. ->setProperty('foo', $definition);
  873. $container->register('bar', 'BarClass')
  874. ->setProperty('foo', $definition)
  875. ->addMethodCall('setBaz', array($definition));
  876. $barUser = $container->get('bar_user');
  877. $bar = $container->get('bar');
  878. $this->assertSame($barUser->foo, $barUser->bar);
  879. $this->assertSame($bar->foo, $bar->getBaz());
  880. $this->assertNotSame($bar->foo, $barUser->foo);
  881. }
  882. /**
  883. * @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException
  884. * @expectedExceptionMessage Circular reference detected for service "app.test_class", path: "app.test_class -> App\TestClass -> app.test_class".
  885. */
  886. public function testThrowsCircularExceptionForCircularAliases()
  887. {
  888. $builder = new ContainerBuilder();
  889. $builder->setAliases(array(
  890. 'foo' => new Alias('app.test_class'),
  891. 'app.test_class' => new Alias('App\\TestClass'),
  892. 'App\\TestClass' => new Alias('app.test_class'),
  893. ));
  894. $builder->findDefinition('foo');
  895. }
  896. public function testInitializePropertiesBeforeMethodCalls()
  897. {
  898. $container = new ContainerBuilder();
  899. $container->register('foo', 'stdClass');
  900. $container->register('bar', 'MethodCallClass')
  901. ->setProperty('simple', 'bar')
  902. ->setProperty('complex', new Reference('foo'))
  903. ->addMethodCall('callMe');
  904. $container->compile();
  905. $this->assertTrue($container->get('bar')->callPassed(), '->compile() initializes properties before method calls');
  906. }
  907. public function testAutowiring()
  908. {
  909. $container = new ContainerBuilder();
  910. $container->register(A::class);
  911. $bDefinition = $container->register('b', __NAMESPACE__.'\B');
  912. $bDefinition->setAutowired(true);
  913. $container->compile();
  914. $this->assertEquals(A::class, (string) $container->getDefinition('b')->getArgument(0));
  915. }
  916. public function testClassFromId()
  917. {
  918. $container = new ContainerBuilder();
  919. $unknown = $container->register('Acme\UnknownClass');
  920. $autoloadClass = $container->register(CaseSensitiveClass::class);
  921. $container->compile();
  922. $this->assertSame('Acme\UnknownClass', $unknown->getClass());
  923. $this->assertEquals(CaseSensitiveClass::class, $autoloadClass->getClass());
  924. }
  925. /**
  926. * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
  927. * @expectedExceptionMessage The definition for "DateTime" has no class attribute, and appears to reference a class or interface in the global namespace.
  928. */
  929. public function testNoClassFromGlobalNamespaceClassId()
  930. {
  931. $container = new ContainerBuilder();
  932. $definition = $container->register(\DateTime::class);
  933. $container->compile();
  934. }
  935. /**
  936. * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
  937. * @expectedExceptionMessage The definition for "123_abc" has no class.
  938. */
  939. public function testNoClassFromNonClassId()
  940. {
  941. $container = new ContainerBuilder();
  942. $definition = $container->register('123_abc');
  943. $container->compile();
  944. }
  945. /**
  946. * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
  947. * @expectedExceptionMessage The definition for "\foo" has no class.
  948. */
  949. public function testNoClassFromNsSeparatorId()
  950. {
  951. $container = new ContainerBuilder();
  952. $definition = $container->register('\\foo');
  953. $container->compile();
  954. }
  955. public function testServiceLocator()
  956. {
  957. $container = new ContainerBuilder();
  958. $container->register('foo_service', ServiceLocator::class)
  959. ->addArgument(array(
  960. 'bar' => new ServiceClosureArgument(new Reference('bar_service')),
  961. 'baz' => new ServiceClosureArgument(new TypedReference('baz_service', 'stdClass')),
  962. ))
  963. ;
  964. $container->register('bar_service', 'stdClass')->setArguments(array(new Reference('baz_service')));
  965. $container->register('baz_service', 'stdClass')->setPublic(false);
  966. $container->compile();
  967. $this->assertInstanceOf(ServiceLocator::class, $foo = $container->get('foo_service'));
  968. $this->assertSame($container->get('bar_service'), $foo->get('bar'));
  969. }
  970. public function testRegisterForAutoconfiguration()
  971. {
  972. $container = new ContainerBuilder();
  973. $childDefA = $container->registerForAutoconfiguration('AInterface');
  974. $childDefB = $container->registerForAutoconfiguration('BInterface');
  975. $this->assertSame(array('AInterface' => $childDefA, 'BInterface' => $childDefB), $container->getAutoconfiguredInstanceof());
  976. // when called multiple times, the same instance is returned
  977. $this->assertSame($childDefA, $container->registerForAutoconfiguration('AInterface'));
  978. }
  979. /**
  980. * This test checks the trigger of a deprecation note and should not be removed in major releases.
  981. *
  982. * @group legacy
  983. * @expectedDeprecation The "foo" service is deprecated. You should stop using it, as it will soon be removed.
  984. */
  985. public function testPrivateServiceTriggersDeprecation()
  986. {
  987. $container = new ContainerBuilder();
  988. $container->register('foo', 'stdClass')
  989. ->setPublic(false)
  990. ->setDeprecated(true);
  991. $container->register('bar', 'stdClass')
  992. ->setPublic(true)
  993. ->setProperty('foo', new Reference('foo'));
  994. $container->compile();
  995. $container->get('bar');
  996. }
  997. }
  998. class FooClass
  999. {
  1000. }
  1001. class A
  1002. {
  1003. }
  1004. class B
  1005. {
  1006. public function __construct(A $a)
  1007. {
  1008. }
  1009. }
  1010. class TestingEnvPlaceholderParameterBag extends EnvPlaceholderParameterBag
  1011. {
  1012. public function get($name)
  1013. {
  1014. return 'env(array)' === strtolower($name) ? array(123) : parent::get($name);
  1015. }
  1016. }