f2e8368455f6676cca74bd11210549661fb43bd5
[yaffs-website] / vendor / symfony / dependency-injection / Tests / ContainerBuilderTest.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Symfony\Component\DependencyInjection\Tests;
13
14 require_once __DIR__.'/Fixtures/includes/classes.php';
15 require_once __DIR__.'/Fixtures/includes/ProjectExtension.php';
16
17 use PHPUnit\Framework\TestCase;
18 use Psr\Container\ContainerInterface as PsrContainerInterface;
19 use Symfony\Component\Config\Resource\ComposerResource;
20 use Symfony\Component\Config\Resource\ResourceInterface;
21 use Symfony\Component\Config\Resource\DirectoryResource;
22 use Symfony\Component\DependencyInjection\Alias;
23 use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
24 use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
25 use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
26 use Symfony\Component\DependencyInjection\ChildDefinition;
27 use Symfony\Component\DependencyInjection\Compiler\PassConfig;
28 use Symfony\Component\DependencyInjection\ContainerBuilder;
29 use Symfony\Component\DependencyInjection\ContainerInterface;
30 use Symfony\Component\DependencyInjection\Definition;
31 use Symfony\Component\DependencyInjection\Exception\RuntimeException;
32 use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
33 use Symfony\Component\DependencyInjection\Loader\ClosureLoader;
34 use Symfony\Component\DependencyInjection\Reference;
35 use Symfony\Component\DependencyInjection\Tests\Fixtures\SimilarArgumentsDummy;
36 use Symfony\Component\DependencyInjection\TypedReference;
37 use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
38 use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
39 use Symfony\Component\Config\Resource\FileResource;
40 use Symfony\Component\DependencyInjection\ServiceLocator;
41 use Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition;
42 use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass;
43 use Symfony\Component\ExpressionLanguage\Expression;
44
45 class ContainerBuilderTest extends TestCase
46 {
47     public function testDefaultRegisteredDefinitions()
48     {
49         $builder = new ContainerBuilder();
50
51         $this->assertCount(1, $builder->getDefinitions());
52         $this->assertTrue($builder->hasDefinition('service_container'));
53
54         $definition = $builder->getDefinition('service_container');
55         $this->assertInstanceOf(Definition::class, $definition);
56         $this->assertTrue($definition->isSynthetic());
57         $this->assertSame(ContainerInterface::class, $definition->getClass());
58         $this->assertTrue($builder->hasAlias(PsrContainerInterface::class));
59         $this->assertTrue($builder->hasAlias(ContainerInterface::class));
60     }
61
62     public function testDefinitions()
63     {
64         $builder = new ContainerBuilder();
65         $definitions = array(
66             'foo' => new Definition('Bar\FooClass'),
67             'bar' => new Definition('BarClass'),
68         );
69         $builder->setDefinitions($definitions);
70         $this->assertEquals($definitions, $builder->getDefinitions(), '->setDefinitions() sets the service definitions');
71         $this->assertTrue($builder->hasDefinition('foo'), '->hasDefinition() returns true if a service definition exists');
72         $this->assertFalse($builder->hasDefinition('foobar'), '->hasDefinition() returns false if a service definition does not exist');
73
74         $builder->setDefinition('foobar', $foo = new Definition('FooBarClass'));
75         $this->assertEquals($foo, $builder->getDefinition('foobar'), '->getDefinition() returns a service definition if defined');
76         $this->assertSame($builder->setDefinition('foobar', $foo = new Definition('FooBarClass')), $foo, '->setDefinition() implements a fluid interface by returning the service reference');
77
78         $builder->addDefinitions($defs = array('foobar' => new Definition('FooBarClass')));
79         $this->assertEquals(array_merge($definitions, $defs), $builder->getDefinitions(), '->addDefinitions() adds the service definitions');
80
81         try {
82             $builder->getDefinition('baz');
83             $this->fail('->getDefinition() throws a ServiceNotFoundException if the service definition does not exist');
84         } catch (ServiceNotFoundException $e) {
85             $this->assertEquals('You have requested a non-existent service "baz".', $e->getMessage(), '->getDefinition() throws a ServiceNotFoundException if the service definition does not exist');
86         }
87     }
88
89     /**
90      * @group legacy
91      * @expectedDeprecation The "deprecated_foo" service is deprecated. You should stop using it, as it will soon be removed.
92      */
93     public function testCreateDeprecatedService()
94     {
95         $definition = new Definition('stdClass');
96         $definition->setDeprecated(true);
97
98         $builder = new ContainerBuilder();
99         $builder->setDefinition('deprecated_foo', $definition);
100         $builder->get('deprecated_foo');
101     }
102
103     public function testRegister()
104     {
105         $builder = new ContainerBuilder();
106         $builder->register('foo', 'Bar\FooClass');
107         $this->assertTrue($builder->hasDefinition('foo'), '->register() registers a new service definition');
108         $this->assertInstanceOf('Symfony\Component\DependencyInjection\Definition', $builder->getDefinition('foo'), '->register() returns the newly created Definition instance');
109     }
110
111     public function testAutowire()
112     {
113         $builder = new ContainerBuilder();
114         $builder->autowire('foo', 'Bar\FooClass');
115
116         $this->assertTrue($builder->hasDefinition('foo'), '->autowire() registers a new service definition');
117         $this->assertTrue($builder->getDefinition('foo')->isAutowired(), '->autowire() creates autowired definitions');
118     }
119
120     public function testHas()
121     {
122         $builder = new ContainerBuilder();
123         $this->assertFalse($builder->has('foo'), '->has() returns false if the service does not exist');
124         $builder->register('foo', 'Bar\FooClass');
125         $this->assertTrue($builder->has('foo'), '->has() returns true if a service definition exists');
126         $builder->set('bar', new \stdClass());
127         $this->assertTrue($builder->has('bar'), '->has() returns true if a service exists');
128     }
129
130     /**
131      * @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException
132      * @expectedExceptionMessage You have requested a non-existent service "foo".
133      */
134     public function testGetThrowsExceptionIfServiceDoesNotExist()
135     {
136         $builder = new ContainerBuilder();
137         $builder->get('foo');
138     }
139
140     public function testGetReturnsNullIfServiceDoesNotExistAndInvalidReferenceIsUsed()
141     {
142         $builder = new ContainerBuilder();
143
144         $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');
145     }
146
147     /**
148      * @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException
149      */
150     public function testGetThrowsCircularReferenceExceptionIfServiceHasReferenceToItself()
151     {
152         $builder = new ContainerBuilder();
153         $builder->register('baz', 'stdClass')->setArguments(array(new Reference('baz')));
154         $builder->get('baz');
155     }
156
157     public function testGetReturnsSameInstanceWhenServiceIsShared()
158     {
159         $builder = new ContainerBuilder();
160         $builder->register('bar', 'stdClass');
161
162         $this->assertTrue($builder->get('bar') === $builder->get('bar'), '->get() always returns the same instance if the service is shared');
163     }
164
165     public function testGetCreatesServiceBasedOnDefinition()
166     {
167         $builder = new ContainerBuilder();
168         $builder->register('foo', 'stdClass');
169
170         $this->assertInternalType('object', $builder->get('foo'), '->get() returns the service definition associated with the id');
171     }
172
173     public function testGetReturnsRegisteredService()
174     {
175         $builder = new ContainerBuilder();
176         $builder->set('bar', $bar = new \stdClass());
177
178         $this->assertSame($bar, $builder->get('bar'), '->get() returns the service associated with the id');
179     }
180
181     public function testRegisterDoesNotOverrideExistingService()
182     {
183         $builder = new ContainerBuilder();
184         $builder->set('bar', $bar = new \stdClass());
185         $builder->register('bar', 'stdClass');
186
187         $this->assertSame($bar, $builder->get('bar'), '->get() returns the service associated with the id even if a definition has been defined');
188     }
189
190     public function testNonSharedServicesReturnsDifferentInstances()
191     {
192         $builder = new ContainerBuilder();
193         $builder->register('bar', 'stdClass')->setShared(false);
194
195         $this->assertNotSame($builder->get('bar'), $builder->get('bar'));
196     }
197
198     /**
199      * @expectedException        \Symfony\Component\DependencyInjection\Exception\RuntimeException
200      * @expectedExceptionMessage You have requested a synthetic service ("foo"). The DIC does not know how to construct this service.
201      */
202     public function testGetUnsetLoadingServiceWhenCreateServiceThrowsAnException()
203     {
204         $builder = new ContainerBuilder();
205         $builder->register('foo', 'stdClass')->setSynthetic(true);
206
207         // we expect a RuntimeException here as foo is synthetic
208         try {
209             $builder->get('foo');
210         } catch (RuntimeException $e) {
211         }
212
213         // we must also have the same RuntimeException here
214         $builder->get('foo');
215     }
216
217     public function testGetServiceIds()
218     {
219         $builder = new ContainerBuilder();
220         $builder->register('foo', 'stdClass');
221         $builder->bar = $bar = new \stdClass();
222         $builder->register('bar', 'stdClass');
223         $this->assertEquals(
224             array(
225                 'service_container',
226                 'foo',
227                 'bar',
228                 'Psr\Container\ContainerInterface',
229                 'Symfony\Component\DependencyInjection\ContainerInterface',
230             ),
231             $builder->getServiceIds(),
232             '->getServiceIds() returns all defined service ids'
233         );
234     }
235
236     public function testAliases()
237     {
238         $builder = new ContainerBuilder();
239         $builder->register('foo', 'stdClass');
240         $builder->setAlias('bar', 'foo');
241         $this->assertTrue($builder->hasAlias('bar'), '->hasAlias() returns true if the alias exists');
242         $this->assertFalse($builder->hasAlias('foobar'), '->hasAlias() returns false if the alias does not exist');
243         $this->assertEquals('foo', (string) $builder->getAlias('bar'), '->getAlias() returns the aliased service');
244         $this->assertTrue($builder->has('bar'), '->setAlias() defines a new service');
245         $this->assertSame($builder->get('bar'), $builder->get('foo'), '->setAlias() creates a service that is an alias to another one');
246
247         try {
248             $builder->setAlias('foobar', 'foobar');
249             $this->fail('->setAlias() throws an InvalidArgumentException if the alias references itself');
250         } catch (\InvalidArgumentException $e) {
251             $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');
252         }
253
254         try {
255             $builder->getAlias('foobar');
256             $this->fail('->getAlias() throws an InvalidArgumentException if the alias does not exist');
257         } catch (\InvalidArgumentException $e) {
258             $this->assertEquals('The service alias "foobar" does not exist.', $e->getMessage(), '->getAlias() throws an InvalidArgumentException if the alias does not exist');
259         }
260     }
261
262     public function testGetAliases()
263     {
264         $builder = new ContainerBuilder();
265         $builder->setAlias('bar', 'foo');
266         $builder->setAlias('foobar', 'foo');
267         $builder->setAlias('moo', new Alias('foo', false));
268
269         $aliases = $builder->getAliases();
270         $this->assertEquals('foo', (string) $aliases['bar']);
271         $this->assertTrue($aliases['bar']->isPublic());
272         $this->assertEquals('foo', (string) $aliases['foobar']);
273         $this->assertEquals('foo', (string) $aliases['moo']);
274         $this->assertFalse($aliases['moo']->isPublic());
275
276         $builder->register('bar', 'stdClass');
277         $this->assertFalse($builder->hasAlias('bar'));
278
279         $builder->set('foobar', 'stdClass');
280         $builder->set('moo', 'stdClass');
281         $this->assertCount(2, $builder->getAliases(), '->getAliases() does not return aliased services that have been overridden');
282     }
283
284     public function testSetAliases()
285     {
286         $builder = new ContainerBuilder();
287         $builder->setAliases(array('bar' => 'foo', 'foobar' => 'foo'));
288
289         $aliases = $builder->getAliases();
290         $this->assertArrayHasKey('bar', $aliases);
291         $this->assertArrayHasKey('foobar', $aliases);
292     }
293
294     public function testAddAliases()
295     {
296         $builder = new ContainerBuilder();
297         $builder->setAliases(array('bar' => 'foo'));
298         $builder->addAliases(array('foobar' => 'foo'));
299
300         $aliases = $builder->getAliases();
301         $this->assertArrayHasKey('bar', $aliases);
302         $this->assertArrayHasKey('foobar', $aliases);
303     }
304
305     public function testSetReplacesAlias()
306     {
307         $builder = new ContainerBuilder();
308         $builder->setAlias('alias', 'aliased');
309         $builder->set('aliased', new \stdClass());
310
311         $builder->set('alias', $foo = new \stdClass());
312         $this->assertSame($foo, $builder->get('alias'), '->set() replaces an existing alias');
313     }
314
315     public function testAliasesKeepInvalidBehavior()
316     {
317         $builder = new ContainerBuilder();
318
319         $aliased = new Definition('stdClass');
320         $aliased->addMethodCall('setBar', array(new Reference('bar', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)));
321         $builder->setDefinition('aliased', $aliased);
322         $builder->setAlias('alias', 'aliased');
323
324         $this->assertEquals(new \stdClass(), $builder->get('alias'));
325     }
326
327     public function testAddGetCompilerPass()
328     {
329         $builder = new ContainerBuilder();
330         $builder->setResourceTracking(false);
331         $defaultPasses = $builder->getCompiler()->getPassConfig()->getPasses();
332         $builder->addCompilerPass($pass1 = $this->getMockBuilder('Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface')->getMock(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -5);
333         $builder->addCompilerPass($pass2 = $this->getMockBuilder('Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface')->getMock(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 10);
334
335         $passes = $builder->getCompiler()->getPassConfig()->getPasses();
336         $this->assertCount(count($passes) - 2, $defaultPasses);
337         // Pass 1 is executed later
338         $this->assertTrue(array_search($pass1, $passes, true) > array_search($pass2, $passes, true));
339     }
340
341     public function testCreateService()
342     {
343         $builder = new ContainerBuilder();
344         $builder->register('foo1', 'Bar\FooClass')->setFile(__DIR__.'/Fixtures/includes/foo.php');
345         $builder->register('foo2', 'Bar\FooClass')->setFile(__DIR__.'/Fixtures/includes/%file%.php');
346         $builder->setParameter('file', 'foo');
347         $this->assertInstanceOf('\Bar\FooClass', $builder->get('foo1'), '->createService() requires the file defined by the service definition');
348         $this->assertInstanceOf('\Bar\FooClass', $builder->get('foo2'), '->createService() replaces parameters in the file provided by the service definition');
349     }
350
351     public function testCreateProxyWithRealServiceInstantiator()
352     {
353         $builder = new ContainerBuilder();
354
355         $builder->register('foo1', 'Bar\FooClass')->setFile(__DIR__.'/Fixtures/includes/foo.php');
356         $builder->getDefinition('foo1')->setLazy(true);
357
358         $foo1 = $builder->get('foo1');
359
360         $this->assertSame($foo1, $builder->get('foo1'), 'The same proxy is retrieved on multiple subsequent calls');
361         $this->assertSame('Bar\FooClass', get_class($foo1));
362     }
363
364     public function testCreateServiceClass()
365     {
366         $builder = new ContainerBuilder();
367         $builder->register('foo1', '%class%');
368         $builder->setParameter('class', 'stdClass');
369         $this->assertInstanceOf('\stdClass', $builder->get('foo1'), '->createService() replaces parameters in the class provided by the service definition');
370     }
371
372     public function testCreateServiceArguments()
373     {
374         $builder = new ContainerBuilder();
375         $builder->register('bar', 'stdClass');
376         $builder->register('foo1', 'Bar\FooClass')->addArgument(array('foo' => '%value%', '%value%' => 'foo', new Reference('bar'), '%%unescape_it%%'));
377         $builder->setParameter('value', 'bar');
378         $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');
379     }
380
381     public function testCreateServiceFactory()
382     {
383         $builder = new ContainerBuilder();
384         $builder->register('foo', 'Bar\FooClass')->setFactory('Bar\FooClass::getInstance');
385         $builder->register('qux', 'Bar\FooClass')->setFactory(array('Bar\FooClass', 'getInstance'));
386         $builder->register('bar', 'Bar\FooClass')->setFactory(array(new Definition('Bar\FooClass'), 'getInstance'));
387         $builder->register('baz', 'Bar\FooClass')->setFactory(array(new Reference('bar'), 'getInstance'));
388
389         $this->assertTrue($builder->get('foo')->called, '->createService() calls the factory method to create the service instance');
390         $this->assertTrue($builder->get('qux')->called, '->createService() calls the factory method to create the service instance');
391         $this->assertTrue($builder->get('bar')->called, '->createService() uses anonymous service as factory');
392         $this->assertTrue($builder->get('baz')->called, '->createService() uses another service as factory');
393     }
394
395     public function testCreateServiceMethodCalls()
396     {
397         $builder = new ContainerBuilder();
398         $builder->register('bar', 'stdClass');
399         $builder->register('foo1', 'Bar\FooClass')->addMethodCall('setBar', array(array('%value%', new Reference('bar'))));
400         $builder->setParameter('value', 'bar');
401         $this->assertEquals(array('bar', $builder->get('bar')), $builder->get('foo1')->bar, '->createService() replaces the values in the method calls arguments');
402     }
403
404     public function testCreateServiceMethodCallsWithEscapedParam()
405     {
406         $builder = new ContainerBuilder();
407         $builder->register('bar', 'stdClass');
408         $builder->register('foo1', 'Bar\FooClass')->addMethodCall('setBar', array(array('%%unescape_it%%')));
409         $builder->setParameter('value', 'bar');
410         $this->assertEquals(array('%unescape_it%'), $builder->get('foo1')->bar, '->createService() replaces the values in the method calls arguments');
411     }
412
413     public function testCreateServiceProperties()
414     {
415         $builder = new ContainerBuilder();
416         $builder->register('bar', 'stdClass');
417         $builder->register('foo1', 'Bar\FooClass')->setProperty('bar', array('%value%', new Reference('bar'), '%%unescape_it%%'));
418         $builder->setParameter('value', 'bar');
419         $this->assertEquals(array('bar', $builder->get('bar'), '%unescape_it%'), $builder->get('foo1')->bar, '->createService() replaces the values in the properties');
420     }
421
422     public function testCreateServiceConfigurator()
423     {
424         $builder = new ContainerBuilder();
425         $builder->register('foo1', 'Bar\FooClass')->setConfigurator('sc_configure');
426         $builder->register('foo2', 'Bar\FooClass')->setConfigurator(array('%class%', 'configureStatic'));
427         $builder->setParameter('class', 'BazClass');
428         $builder->register('baz', 'BazClass');
429         $builder->register('foo3', 'Bar\FooClass')->setConfigurator(array(new Reference('baz'), 'configure'));
430         $builder->register('foo4', 'Bar\FooClass')->setConfigurator(array($builder->getDefinition('baz'), 'configure'));
431         $builder->register('foo5', 'Bar\FooClass')->setConfigurator('foo');
432
433         $this->assertTrue($builder->get('foo1')->configured, '->createService() calls the configurator');
434         $this->assertTrue($builder->get('foo2')->configured, '->createService() calls the configurator');
435         $this->assertTrue($builder->get('foo3')->configured, '->createService() calls the configurator');
436         $this->assertTrue($builder->get('foo4')->configured, '->createService() calls the configurator');
437
438         try {
439             $builder->get('foo5');
440             $this->fail('->createService() throws an InvalidArgumentException if the configure callable is not a valid callable');
441         } catch (\InvalidArgumentException $e) {
442             $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');
443         }
444     }
445
446     public function testCreateServiceWithIteratorArgument()
447     {
448         $builder = new ContainerBuilder();
449         $builder->register('bar', 'stdClass');
450         $builder
451             ->register('lazy_context', 'LazyContext')
452             ->setArguments(array(
453                 new IteratorArgument(array('k1' => new Reference('bar'), new Reference('invalid', ContainerInterface::IGNORE_ON_INVALID_REFERENCE))),
454                 new IteratorArgument(array()),
455             ))
456         ;
457
458         $lazyContext = $builder->get('lazy_context');
459         $this->assertInstanceOf(RewindableGenerator::class, $lazyContext->lazyValues);
460         $this->assertInstanceOf(RewindableGenerator::class, $lazyContext->lazyEmptyValues);
461         $this->assertCount(1, $lazyContext->lazyValues);
462         $this->assertCount(0, $lazyContext->lazyEmptyValues);
463
464         $i = 0;
465         foreach ($lazyContext->lazyValues as $k => $v) {
466             ++$i;
467             $this->assertEquals('k1', $k);
468             $this->assertInstanceOf('\stdClass', $v);
469         }
470
471         // The second argument should have been ignored.
472         $this->assertEquals(1, $i);
473
474         $i = 0;
475         foreach ($lazyContext->lazyEmptyValues as $k => $v) {
476             ++$i;
477         }
478
479         $this->assertEquals(0, $i);
480     }
481
482     /**
483      * @expectedException \RuntimeException
484      */
485     public function testCreateSyntheticService()
486     {
487         $builder = new ContainerBuilder();
488         $builder->register('foo', 'Bar\FooClass')->setSynthetic(true);
489         $builder->get('foo');
490     }
491
492     public function testCreateServiceWithExpression()
493     {
494         $builder = new ContainerBuilder();
495         $builder->setParameter('bar', 'bar');
496         $builder->register('bar', 'BarClass');
497         $builder->register('foo', 'Bar\FooClass')->addArgument(array('foo' => new Expression('service("bar").foo ~ parameter("bar")')));
498         $this->assertEquals('foobar', $builder->get('foo')->arguments['foo']);
499     }
500
501     public function testResolveServices()
502     {
503         $builder = new ContainerBuilder();
504         $builder->register('foo', 'Bar\FooClass');
505         $this->assertEquals($builder->get('foo'), $builder->resolveServices(new Reference('foo')), '->resolveServices() resolves service references to service instances');
506         $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');
507         $this->assertEquals($builder->get('foo'), $builder->resolveServices(new Expression('service("foo")')), '->resolveServices() resolves expressions');
508     }
509
510     /**
511      * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
512      * @expectedExceptionMessage Constructing service "foo" from a parent definition is not supported at build time.
513      */
514     public function testResolveServicesWithDecoratedDefinition()
515     {
516         $builder = new ContainerBuilder();
517         $builder->setDefinition('grandpa', new Definition('stdClass'));
518         $builder->setDefinition('parent', new ChildDefinition('grandpa'));
519         $builder->setDefinition('foo', new ChildDefinition('parent'));
520
521         $builder->get('foo');
522     }
523
524     public function testResolveServicesWithCustomDefinitionClass()
525     {
526         $builder = new ContainerBuilder();
527         $builder->setDefinition('foo', new CustomDefinition('stdClass'));
528
529         $this->assertInstanceOf('stdClass', $builder->get('foo'));
530     }
531
532     public function testMerge()
533     {
534         $container = new ContainerBuilder(new ParameterBag(array('bar' => 'foo')));
535         $container->setResourceTracking(false);
536         $config = new ContainerBuilder(new ParameterBag(array('foo' => 'bar')));
537         $container->merge($config);
538         $this->assertEquals(array('bar' => 'foo', 'foo' => 'bar'), $container->getParameterBag()->all(), '->merge() merges current parameters with the loaded ones');
539
540         $container = new ContainerBuilder(new ParameterBag(array('bar' => 'foo')));
541         $container->setResourceTracking(false);
542         $config = new ContainerBuilder(new ParameterBag(array('foo' => '%bar%')));
543         $container->merge($config);
544         $container->compile();
545         $this->assertEquals(array('bar' => 'foo', 'foo' => 'foo'), $container->getParameterBag()->all(), '->merge() evaluates the values of the parameters towards already defined ones');
546
547         $container = new ContainerBuilder(new ParameterBag(array('bar' => 'foo')));
548         $container->setResourceTracking(false);
549         $config = new ContainerBuilder(new ParameterBag(array('foo' => '%bar%', 'baz' => '%foo%')));
550         $container->merge($config);
551         $container->compile();
552         $this->assertEquals(array('bar' => 'foo', 'foo' => 'foo', 'baz' => 'foo'), $container->getParameterBag()->all(), '->merge() evaluates the values of the parameters towards already defined ones');
553
554         $container = new ContainerBuilder();
555         $container->setResourceTracking(false);
556         $container->register('foo', 'Bar\FooClass');
557         $container->register('bar', 'BarClass');
558         $config = new ContainerBuilder();
559         $config->setDefinition('baz', new Definition('BazClass'));
560         $config->setAlias('alias_for_foo', 'foo');
561         $container->merge($config);
562         $this->assertEquals(array('service_container', 'foo', 'bar', 'baz'), array_keys($container->getDefinitions()), '->merge() merges definitions already defined ones');
563
564         $aliases = $container->getAliases();
565         $this->assertArrayHasKey('alias_for_foo', $aliases);
566         $this->assertEquals('foo', (string) $aliases['alias_for_foo']);
567
568         $container = new ContainerBuilder();
569         $container->setResourceTracking(false);
570         $container->register('foo', 'Bar\FooClass');
571         $config->setDefinition('foo', new Definition('BazClass'));
572         $container->merge($config);
573         $this->assertEquals('BazClass', $container->getDefinition('foo')->getClass(), '->merge() overrides already defined services');
574
575         $container = new ContainerBuilder();
576         $bag = new EnvPlaceholderParameterBag();
577         $bag->get('env(Foo)');
578         $config = new ContainerBuilder($bag);
579         $this->assertSame(array('%env(Bar)%'), $config->resolveEnvPlaceholders(array($bag->get('env(Bar)'))));
580         $container->merge($config);
581         $this->assertEquals(array('Foo' => 0, 'Bar' => 1), $container->getEnvCounters());
582
583         $container = new ContainerBuilder();
584         $config = new ContainerBuilder();
585         $childDefA = $container->registerForAutoconfiguration('AInterface');
586         $childDefB = $config->registerForAutoconfiguration('BInterface');
587         $container->merge($config);
588         $this->assertSame(array('AInterface' => $childDefA, 'BInterface' => $childDefB), $container->getAutoconfiguredInstanceof());
589     }
590
591     /**
592      * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
593      * @expectedExceptionMessage "AInterface" has already been autoconfigured and merge() does not support merging autoconfiguration for the same class/interface.
594      */
595     public function testMergeThrowsExceptionForDuplicateAutomaticInstanceofDefinitions()
596     {
597         $container = new ContainerBuilder();
598         $config = new ContainerBuilder();
599         $container->registerForAutoconfiguration('AInterface');
600         $config->registerForAutoconfiguration('AInterface');
601         $container->merge($config);
602     }
603
604     public function testResolveEnvValues()
605     {
606         $_ENV['DUMMY_ENV_VAR'] = 'du%%y';
607         $_SERVER['DUMMY_SERVER_VAR'] = 'ABC';
608         $_SERVER['HTTP_DUMMY_VAR'] = 'DEF';
609
610         $container = new ContainerBuilder();
611         $container->setParameter('bar', '%% %env(DUMMY_ENV_VAR)% %env(DUMMY_SERVER_VAR)% %env(HTTP_DUMMY_VAR)%');
612         $container->setParameter('env(HTTP_DUMMY_VAR)', '123');
613
614         $this->assertSame('%% du%%%%y ABC 123', $container->resolveEnvPlaceholders('%bar%', true));
615
616         unset($_ENV['DUMMY_ENV_VAR'], $_SERVER['DUMMY_SERVER_VAR'], $_SERVER['HTTP_DUMMY_VAR']);
617     }
618
619     public function testResolveEnvValuesWithArray()
620     {
621         $_ENV['ANOTHER_DUMMY_ENV_VAR'] = 'dummy';
622
623         $dummyArray = array('1' => 'one', '2' => 'two');
624
625         $container = new ContainerBuilder();
626         $container->setParameter('dummy', '%env(ANOTHER_DUMMY_ENV_VAR)%');
627         $container->setParameter('dummy2', $dummyArray);
628
629         $container->resolveEnvPlaceholders('%dummy%', true);
630         $container->resolveEnvPlaceholders('%dummy2%', true);
631
632         $this->assertInternalType('array', $container->resolveEnvPlaceholders('%dummy2%', true));
633
634         foreach ($dummyArray as $key => $value) {
635             $this->assertArrayHasKey($key, $container->resolveEnvPlaceholders('%dummy2%', true));
636         }
637
638         unset($_ENV['ANOTHER_DUMMY_ENV_VAR']);
639     }
640
641     public function testCompileWithResolveEnv()
642     {
643         putenv('DUMMY_ENV_VAR=du%%y');
644         $_SERVER['DUMMY_SERVER_VAR'] = 'ABC';
645         $_SERVER['HTTP_DUMMY_VAR'] = 'DEF';
646
647         $container = new ContainerBuilder();
648         $container->setParameter('env(FOO)', 'Foo');
649         $container->setParameter('env(DUMMY_ENV_VAR)', 'GHI');
650         $container->setParameter('bar', '%% %env(DUMMY_ENV_VAR)% %env(DUMMY_SERVER_VAR)% %env(HTTP_DUMMY_VAR)%');
651         $container->setParameter('foo', '%env(FOO)%');
652         $container->setParameter('baz', '%foo%');
653         $container->setParameter('env(HTTP_DUMMY_VAR)', '123');
654         $container->register('teatime', 'stdClass')
655             ->setProperty('foo', '%env(DUMMY_ENV_VAR)%')
656             ->setPublic(true)
657         ;
658         $container->compile(true);
659
660         $this->assertSame('% du%%y ABC 123', $container->getParameter('bar'));
661         $this->assertSame('Foo', $container->getParameter('baz'));
662         $this->assertSame('du%%y', $container->get('teatime')->foo);
663
664         unset($_SERVER['DUMMY_SERVER_VAR'], $_SERVER['HTTP_DUMMY_VAR']);
665         putenv('DUMMY_ENV_VAR');
666     }
667
668     public function testCompileWithArrayResolveEnv()
669     {
670         putenv('ARRAY={"foo":"bar"}');
671
672         $container = new ContainerBuilder();
673         $container->setParameter('foo', '%env(json:ARRAY)%');
674         $container->compile(true);
675
676         $this->assertSame(array('foo' => 'bar'), $container->getParameter('foo'));
677
678         putenv('ARRAY');
679     }
680
681     public function testCompileWithArrayAndAnotherResolveEnv()
682     {
683         putenv('DUMMY_ENV_VAR=abc');
684         putenv('ARRAY={"foo":"bar"}');
685
686         $container = new ContainerBuilder();
687         $container->setParameter('foo', '%env(json:ARRAY)%');
688         $container->setParameter('bar', '%env(DUMMY_ENV_VAR)%');
689         $container->compile(true);
690
691         $this->assertSame(array('foo' => 'bar'), $container->getParameter('foo'));
692         $this->assertSame('abc', $container->getParameter('bar'));
693
694         putenv('DUMMY_ENV_VAR');
695         putenv('ARRAY');
696     }
697
698     /**
699      * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
700      * @expectedExceptionMessage A string value must be composed of strings and/or numbers, but found parameter "env(json:ARRAY)" of type array inside string value "ABC %env(json:ARRAY)%".
701      */
702     public function testCompileWithArrayInStringResolveEnv()
703     {
704         putenv('ARRAY={"foo":"bar"}');
705
706         $container = new ContainerBuilder();
707         $container->setParameter('foo', 'ABC %env(json:ARRAY)%');
708         $container->compile(true);
709
710         putenv('ARRAY');
711     }
712
713     /**
714      * @expectedException \Symfony\Component\DependencyInjection\Exception\EnvNotFoundException
715      * @expectedExceptionMessage Environment variable not found: "FOO".
716      */
717     public function testCompileWithResolveMissingEnv()
718     {
719         $container = new ContainerBuilder();
720         $container->setParameter('foo', '%env(FOO)%');
721         $container->compile(true);
722     }
723
724     public function testDynamicEnv()
725     {
726         putenv('DUMMY_FOO=some%foo%');
727         putenv('DUMMY_BAR=%bar%');
728
729         $container = new ContainerBuilder();
730         $container->setParameter('foo', 'Foo%env(resolve:DUMMY_BAR)%');
731         $container->setParameter('bar', 'Bar');
732         $container->setParameter('baz', '%env(resolve:DUMMY_FOO)%');
733
734         $container->compile(true);
735         putenv('DUMMY_FOO');
736         putenv('DUMMY_BAR');
737
738         $this->assertSame('someFooBar', $container->getParameter('baz'));
739     }
740
741     public function testCastEnv()
742     {
743         $container = new ContainerBuilder();
744         $container->setParameter('env(FAKE)', '123');
745
746         $container->register('foo', 'stdClass')
747             ->setPublic(true)
748             ->setProperties(array(
749                 'fake' => '%env(int:FAKE)%',
750             ));
751
752         $container->compile(true);
753
754         $this->assertSame(123, $container->get('foo')->fake);
755     }
756
757     public function testEnvAreNullable()
758     {
759         $container = new ContainerBuilder();
760         $container->setParameter('env(FAKE)', null);
761
762         $container->register('foo', 'stdClass')
763             ->setPublic(true)
764             ->setProperties(array(
765             'fake' => '%env(int:FAKE)%',
766         ));
767
768         $container->compile(true);
769
770         $this->assertNull($container->get('foo')->fake);
771     }
772
773     public function testEnvInId()
774     {
775         $container = include __DIR__.'/Fixtures/containers/container_env_in_id.php';
776         $container->compile(true);
777
778         $expected = array(
779             'service_container',
780             'foo',
781             'bar',
782             'bar_%env(BAR)%',
783         );
784         $this->assertSame($expected, array_keys($container->getDefinitions()));
785
786         $expected = array(
787             PsrContainerInterface::class => true,
788             ContainerInterface::class => true,
789             'baz_%env(BAR)%' => true,
790             'bar_%env(BAR)%' => true,
791         );
792         $this->assertSame($expected, $container->getRemovedIds());
793
794         $this->assertSame(array('baz_bar'), array_keys($container->getDefinition('foo')->getArgument(1)));
795     }
796
797     /**
798      * @expectedException \Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException
799      * @expectedExceptionMessage Circular reference detected for parameter "env(resolve:DUMMY_ENV_VAR)" ("env(resolve:DUMMY_ENV_VAR)" > "env(resolve:DUMMY_ENV_VAR)").
800      */
801     public function testCircularDynamicEnv()
802     {
803         putenv('DUMMY_ENV_VAR=some%foo%');
804
805         $container = new ContainerBuilder();
806         $container->setParameter('foo', '%bar%');
807         $container->setParameter('bar', '%env(resolve:DUMMY_ENV_VAR)%');
808
809         try {
810             $container->compile(true);
811         } finally {
812             putenv('DUMMY_ENV_VAR');
813         }
814     }
815
816     /**
817      * @expectedException \LogicException
818      */
819     public function testMergeLogicException()
820     {
821         $container = new ContainerBuilder();
822         $container->setResourceTracking(false);
823         $container->compile();
824         $container->merge(new ContainerBuilder());
825     }
826
827     public function testfindTaggedServiceIds()
828     {
829         $builder = new ContainerBuilder();
830         $builder
831             ->register('foo', 'Bar\FooClass')
832             ->addTag('foo', array('foo' => 'foo'))
833             ->addTag('bar', array('bar' => 'bar'))
834             ->addTag('foo', array('foofoo' => 'foofoo'))
835         ;
836         $this->assertEquals($builder->findTaggedServiceIds('foo'), array(
837             'foo' => array(
838                 array('foo' => 'foo'),
839                 array('foofoo' => 'foofoo'),
840             ),
841         ), '->findTaggedServiceIds() returns an array of service ids and its tag attributes');
842         $this->assertEquals(array(), $builder->findTaggedServiceIds('foobar'), '->findTaggedServiceIds() returns an empty array if there is annotated services');
843     }
844
845     public function testFindUnusedTags()
846     {
847         $builder = new ContainerBuilder();
848         $builder
849             ->register('foo', 'Bar\FooClass')
850             ->addTag('kernel.event_listener', array('foo' => 'foo'))
851             ->addTag('kenrel.event_listener', array('bar' => 'bar'))
852         ;
853         $builder->findTaggedServiceIds('kernel.event_listener');
854         $this->assertEquals(array('kenrel.event_listener'), $builder->findUnusedTags(), '->findUnusedTags() returns an array with unused tags');
855     }
856
857     public function testFindDefinition()
858     {
859         $container = new ContainerBuilder();
860         $container->setDefinition('foo', $definition = new Definition('Bar\FooClass'));
861         $container->setAlias('bar', 'foo');
862         $container->setAlias('foobar', 'bar');
863         $this->assertEquals($definition, $container->findDefinition('foobar'), '->findDefinition() returns a Definition');
864     }
865
866     public function testAddObjectResource()
867     {
868         $container = new ContainerBuilder();
869
870         $container->setResourceTracking(false);
871         $container->addObjectResource(new \BarClass());
872
873         $this->assertEmpty($container->getResources(), 'No resources get registered without resource tracking');
874
875         $container->setResourceTracking(true);
876         $container->addObjectResource(new \BarClass());
877
878         $resources = $container->getResources();
879
880         $this->assertCount(2, $resources, '2 resources were registered');
881
882         /* @var $resource \Symfony\Component\Config\Resource\FileResource */
883         $resource = end($resources);
884
885         $this->assertInstanceOf('Symfony\Component\Config\Resource\FileResource', $resource);
886         $this->assertSame(realpath(__DIR__.'/Fixtures/includes/classes.php'), realpath($resource->getResource()));
887     }
888
889     /**
890      * @group legacy
891      */
892     public function testAddClassResource()
893     {
894         $container = new ContainerBuilder();
895
896         $container->setResourceTracking(false);
897         $container->addClassResource(new \ReflectionClass('BarClass'));
898
899         $this->assertEmpty($container->getResources(), 'No resources get registered without resource tracking');
900
901         $container->setResourceTracking(true);
902         $container->addClassResource(new \ReflectionClass('BarClass'));
903
904         $resources = $container->getResources();
905
906         $this->assertCount(2, $resources, '2 resources were registered');
907
908         /* @var $resource \Symfony\Component\Config\Resource\FileResource */
909         $resource = end($resources);
910
911         $this->assertInstanceOf('Symfony\Component\Config\Resource\FileResource', $resource);
912         $this->assertSame(realpath(__DIR__.'/Fixtures/includes/classes.php'), realpath($resource->getResource()));
913     }
914
915     public function testGetReflectionClass()
916     {
917         $container = new ContainerBuilder();
918
919         $container->setResourceTracking(false);
920         $r1 = $container->getReflectionClass('BarClass');
921
922         $this->assertEmpty($container->getResources(), 'No resources get registered without resource tracking');
923
924         $container->setResourceTracking(true);
925         $r2 = $container->getReflectionClass('BarClass');
926         $r3 = $container->getReflectionClass('BarClass');
927
928         $this->assertNull($container->getReflectionClass('BarMissingClass'));
929
930         $this->assertEquals($r1, $r2);
931         $this->assertSame($r2, $r3);
932
933         $resources = $container->getResources();
934
935         $this->assertCount(3, $resources, '3 resources were registered');
936
937         $this->assertSame('reflection.BarClass', (string) $resources[1]);
938         $this->assertSame('BarMissingClass', (string) end($resources));
939     }
940
941     public function testGetReflectionClassOnInternalTypes()
942     {
943         $container = new ContainerBuilder();
944
945         $this->assertNull($container->getReflectionClass('int'));
946         $this->assertNull($container->getReflectionClass('float'));
947         $this->assertNull($container->getReflectionClass('string'));
948         $this->assertNull($container->getReflectionClass('bool'));
949         $this->assertNull($container->getReflectionClass('resource'));
950         $this->assertNull($container->getReflectionClass('object'));
951         $this->assertNull($container->getReflectionClass('array'));
952         $this->assertNull($container->getReflectionClass('null'));
953         $this->assertNull($container->getReflectionClass('callable'));
954         $this->assertNull($container->getReflectionClass('iterable'));
955         $this->assertNull($container->getReflectionClass('mixed'));
956     }
957
958     public function testCompilesClassDefinitionsOfLazyServices()
959     {
960         $container = new ContainerBuilder();
961
962         $this->assertEmpty($container->getResources(), 'No resources get registered without resource tracking');
963
964         $container->register('foo', 'BarClass')->setPublic(true);
965         $container->getDefinition('foo')->setLazy(true);
966
967         $container->compile();
968
969         $matchingResources = array_filter(
970             $container->getResources(),
971             function (ResourceInterface $resource) {
972                 return 'reflection.BarClass' === (string) $resource;
973             }
974         );
975
976         $this->assertNotEmpty($matchingResources);
977     }
978
979     public function testResources()
980     {
981         $container = new ContainerBuilder();
982         $container->addResource($a = new FileResource(__DIR__.'/Fixtures/xml/services1.xml'));
983         $container->addResource($b = new FileResource(__DIR__.'/Fixtures/xml/services2.xml'));
984         $resources = array();
985         foreach ($container->getResources() as $resource) {
986             if (false === strpos($resource, '.php')) {
987                 $resources[] = $resource;
988             }
989         }
990         $this->assertEquals(array($a, $b), $resources, '->getResources() returns an array of resources read for the current configuration');
991         $this->assertSame($container, $container->setResources(array()));
992         $this->assertEquals(array(), $container->getResources());
993     }
994
995     public function testFileExists()
996     {
997         $container = new ContainerBuilder();
998         $A = new ComposerResource();
999         $a = new FileResource(__DIR__.'/Fixtures/xml/services1.xml');
1000         $b = new FileResource(__DIR__.'/Fixtures/xml/services2.xml');
1001         $c = new DirectoryResource($dir = dirname($b));
1002
1003         $this->assertTrue($container->fileExists((string) $a) && $container->fileExists((string) $b) && $container->fileExists($dir));
1004
1005         $resources = array();
1006         foreach ($container->getResources() as $resource) {
1007             if (false === strpos($resource, '.php')) {
1008                 $resources[] = $resource;
1009             }
1010         }
1011
1012         $this->assertEquals(array($A, $a, $b, $c), $resources, '->getResources() returns an array of resources read for the current configuration');
1013     }
1014
1015     public function testExtension()
1016     {
1017         $container = new ContainerBuilder();
1018         $container->setResourceTracking(false);
1019
1020         $container->registerExtension($extension = new \ProjectExtension());
1021         $this->assertSame($container->getExtension('project'), $extension, '->registerExtension() registers an extension');
1022
1023         $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('LogicException');
1024         $container->getExtension('no_registered');
1025     }
1026
1027     public function testRegisteredButNotLoadedExtension()
1028     {
1029         $extension = $this->getMockBuilder('Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface')->getMock();
1030         $extension->expects($this->once())->method('getAlias')->will($this->returnValue('project'));
1031         $extension->expects($this->never())->method('load');
1032
1033         $container = new ContainerBuilder();
1034         $container->setResourceTracking(false);
1035         $container->registerExtension($extension);
1036         $container->compile();
1037     }
1038
1039     public function testRegisteredAndLoadedExtension()
1040     {
1041         $extension = $this->getMockBuilder('Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface')->getMock();
1042         $extension->expects($this->exactly(2))->method('getAlias')->will($this->returnValue('project'));
1043         $extension->expects($this->once())->method('load')->with(array(array('foo' => 'bar')));
1044
1045         $container = new ContainerBuilder();
1046         $container->setResourceTracking(false);
1047         $container->registerExtension($extension);
1048         $container->loadFromExtension('project', array('foo' => 'bar'));
1049         $container->compile();
1050     }
1051
1052     public function testPrivateServiceUser()
1053     {
1054         $fooDefinition = new Definition('BarClass');
1055         $fooUserDefinition = new Definition('BarUserClass', array(new Reference('bar')));
1056         $container = new ContainerBuilder();
1057         $container->setResourceTracking(false);
1058
1059         $fooDefinition->setPublic(false);
1060
1061         $container->addDefinitions(array(
1062             'bar' => $fooDefinition,
1063             'bar_user' => $fooUserDefinition->setPublic(true),
1064         ));
1065
1066         $container->compile();
1067         $this->assertInstanceOf('BarClass', $container->get('bar_user')->bar);
1068     }
1069
1070     /**
1071      * @expectedException \BadMethodCallException
1072      */
1073     public function testThrowsExceptionWhenSetServiceOnACompiledContainer()
1074     {
1075         $container = new ContainerBuilder();
1076         $container->setResourceTracking(false);
1077         $container->register('a', 'stdClass')->setPublic(true);
1078         $container->compile();
1079         $container->set('a', new \stdClass());
1080     }
1081
1082     public function testThrowsExceptionWhenAddServiceOnACompiledContainer()
1083     {
1084         $container = new ContainerBuilder();
1085         $container->compile();
1086         $container->set('a', $foo = new \stdClass());
1087         $this->assertSame($foo, $container->get('a'));
1088     }
1089
1090     public function testNoExceptionWhenSetSyntheticServiceOnACompiledContainer()
1091     {
1092         $container = new ContainerBuilder();
1093         $def = new Definition('stdClass');
1094         $def->setSynthetic(true)->setPublic(true);
1095         $container->setDefinition('a', $def);
1096         $container->compile();
1097         $container->set('a', $a = new \stdClass());
1098         $this->assertEquals($a, $container->get('a'));
1099     }
1100
1101     /**
1102      * @expectedException \BadMethodCallException
1103      */
1104     public function testThrowsExceptionWhenSetDefinitionOnACompiledContainer()
1105     {
1106         $container = new ContainerBuilder();
1107         $container->setResourceTracking(false);
1108         $container->compile();
1109         $container->setDefinition('a', new Definition());
1110     }
1111
1112     public function testExtensionConfig()
1113     {
1114         $container = new ContainerBuilder();
1115
1116         $configs = $container->getExtensionConfig('foo');
1117         $this->assertEmpty($configs);
1118
1119         $first = array('foo' => 'bar');
1120         $container->prependExtensionConfig('foo', $first);
1121         $configs = $container->getExtensionConfig('foo');
1122         $this->assertEquals(array($first), $configs);
1123
1124         $second = array('ding' => 'dong');
1125         $container->prependExtensionConfig('foo', $second);
1126         $configs = $container->getExtensionConfig('foo');
1127         $this->assertEquals(array($second, $first), $configs);
1128     }
1129
1130     public function testAbstractAlias()
1131     {
1132         $container = new ContainerBuilder();
1133
1134         $abstract = new Definition('AbstractClass');
1135         $abstract->setAbstract(true)->setPublic(true);
1136
1137         $container->setDefinition('abstract_service', $abstract);
1138         $container->setAlias('abstract_alias', 'abstract_service')->setPublic(true);
1139
1140         $container->compile();
1141
1142         $this->assertSame('abstract_service', (string) $container->getAlias('abstract_alias'));
1143     }
1144
1145     public function testLazyLoadedService()
1146     {
1147         $loader = new ClosureLoader($container = new ContainerBuilder());
1148         $loader->load(function (ContainerBuilder $container) {
1149             $container->set('a', new \BazClass());
1150             $definition = new Definition('BazClass');
1151             $definition->setLazy(true);
1152             $definition->setPublic(true);
1153             $container->setDefinition('a', $definition);
1154         });
1155
1156         $container->setResourceTracking(true);
1157
1158         $container->compile();
1159
1160         $r = new \ReflectionProperty($container, 'resources');
1161         $r->setAccessible(true);
1162         $resources = $r->getValue($container);
1163
1164         $classInList = false;
1165         foreach ($resources as $resource) {
1166             if ('reflection.BazClass' === (string) $resource) {
1167                 $classInList = true;
1168                 break;
1169             }
1170         }
1171
1172         $this->assertTrue($classInList);
1173     }
1174
1175     public function testInlinedDefinitions()
1176     {
1177         $container = new ContainerBuilder();
1178
1179         $definition = new Definition('BarClass');
1180
1181         $container->register('bar_user', 'BarUserClass')
1182             ->addArgument($definition)
1183             ->setProperty('foo', $definition);
1184
1185         $container->register('bar', 'BarClass')
1186             ->setProperty('foo', $definition)
1187             ->addMethodCall('setBaz', array($definition));
1188
1189         $barUser = $container->get('bar_user');
1190         $bar = $container->get('bar');
1191
1192         $this->assertSame($barUser->foo, $barUser->bar);
1193         $this->assertSame($bar->foo, $bar->getBaz());
1194         $this->assertNotSame($bar->foo, $barUser->foo);
1195     }
1196
1197     /**
1198      * @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException
1199      * @expectedExceptionMessage Circular reference detected for service "app.test_class", path: "app.test_class -> App\TestClass -> app.test_class".
1200      */
1201     public function testThrowsCircularExceptionForCircularAliases()
1202     {
1203         $builder = new ContainerBuilder();
1204
1205         $builder->setAliases(array(
1206             'foo' => new Alias('app.test_class'),
1207             'app.test_class' => new Alias('App\\TestClass'),
1208             'App\\TestClass' => new Alias('app.test_class'),
1209         ));
1210
1211         $builder->findDefinition('foo');
1212     }
1213
1214     public function testInitializePropertiesBeforeMethodCalls()
1215     {
1216         $container = new ContainerBuilder();
1217         $container->register('foo', 'stdClass');
1218         $container->register('bar', 'MethodCallClass')
1219             ->setPublic(true)
1220             ->setProperty('simple', 'bar')
1221             ->setProperty('complex', new Reference('foo'))
1222             ->addMethodCall('callMe');
1223
1224         $container->compile();
1225
1226         $this->assertTrue($container->get('bar')->callPassed(), '->compile() initializes properties before method calls');
1227     }
1228
1229     public function testAutowiring()
1230     {
1231         $container = new ContainerBuilder();
1232
1233         $container->register(A::class)->setPublic(true);
1234         $bDefinition = $container->register('b', __NAMESPACE__.'\B');
1235         $bDefinition->setAutowired(true);
1236         $bDefinition->setPublic(true);
1237
1238         $container->compile();
1239
1240         $this->assertEquals(A::class, (string) $container->getDefinition('b')->getArgument(0));
1241     }
1242
1243     public function testClassFromId()
1244     {
1245         $container = new ContainerBuilder();
1246
1247         $unknown = $container->register('Acme\UnknownClass');
1248         $autoloadClass = $container->register(CaseSensitiveClass::class);
1249         $container->compile();
1250
1251         $this->assertSame('Acme\UnknownClass', $unknown->getClass());
1252         $this->assertEquals(CaseSensitiveClass::class, $autoloadClass->getClass());
1253     }
1254
1255     /**
1256      * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
1257      * @expectedExceptionMessage The definition for "DateTime" has no class attribute, and appears to reference a class or interface in the global namespace.
1258      */
1259     public function testNoClassFromGlobalNamespaceClassId()
1260     {
1261         $container = new ContainerBuilder();
1262
1263         $definition = $container->register(\DateTime::class);
1264         $container->compile();
1265     }
1266
1267     /**
1268      * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
1269      * @expectedExceptionMessage The definition for "123_abc" has no class.
1270      */
1271     public function testNoClassFromNonClassId()
1272     {
1273         $container = new ContainerBuilder();
1274
1275         $definition = $container->register('123_abc');
1276         $container->compile();
1277     }
1278
1279     /**
1280      * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
1281      * @expectedExceptionMessage The definition for "\foo" has no class.
1282      */
1283     public function testNoClassFromNsSeparatorId()
1284     {
1285         $container = new ContainerBuilder();
1286
1287         $definition = $container->register('\\foo');
1288         $container->compile();
1289     }
1290
1291     public function testServiceLocator()
1292     {
1293         $container = new ContainerBuilder();
1294         $container->register('foo_service', ServiceLocator::class)
1295             ->setPublic(true)
1296             ->addArgument(array(
1297                 'bar' => new ServiceClosureArgument(new Reference('bar_service')),
1298                 'baz' => new ServiceClosureArgument(new TypedReference('baz_service', 'stdClass')),
1299             ))
1300         ;
1301         $container->register('bar_service', 'stdClass')->setArguments(array(new Reference('baz_service')))->setPublic(true);
1302         $container->register('baz_service', 'stdClass')->setPublic(false);
1303         $container->compile();
1304
1305         $this->assertInstanceOf(ServiceLocator::class, $foo = $container->get('foo_service'));
1306         $this->assertSame($container->get('bar_service'), $foo->get('bar'));
1307     }
1308
1309     public function testUninitializedReference()
1310     {
1311         $container = include __DIR__.'/Fixtures/containers/container_uninitialized_ref.php';
1312         $container->compile();
1313
1314         $bar = $container->get('bar');
1315
1316         $this->assertNull($bar->foo1);
1317         $this->assertNull($bar->foo2);
1318         $this->assertNull($bar->foo3);
1319         $this->assertNull($bar->closures[0]());
1320         $this->assertNull($bar->closures[1]());
1321         $this->assertNull($bar->closures[2]());
1322         $this->assertSame(array(), iterator_to_array($bar->iter));
1323
1324         $container = include __DIR__.'/Fixtures/containers/container_uninitialized_ref.php';
1325         $container->compile();
1326
1327         $container->get('foo1');
1328         $container->get('baz');
1329
1330         $bar = $container->get('bar');
1331
1332         $this->assertEquals(new \stdClass(), $bar->foo1);
1333         $this->assertNull($bar->foo2);
1334         $this->assertEquals(new \stdClass(), $bar->foo3);
1335         $this->assertEquals(new \stdClass(), $bar->closures[0]());
1336         $this->assertNull($bar->closures[1]());
1337         $this->assertEquals(new \stdClass(), $bar->closures[2]());
1338         $this->assertEquals(array('foo1' => new \stdClass(), 'foo3' => new \stdClass()), iterator_to_array($bar->iter));
1339     }
1340
1341     /**
1342      * @dataProvider provideAlmostCircular
1343      */
1344     public function testAlmostCircular($visibility)
1345     {
1346         $container = include __DIR__.'/Fixtures/containers/container_almost_circular.php';
1347
1348         $foo = $container->get('foo');
1349         $this->assertSame($foo, $foo->bar->foobar->foo);
1350
1351         $foo2 = $container->get('foo2');
1352         $this->assertSame($foo2, $foo2->bar->foobar->foo);
1353
1354         $this->assertSame(array(), (array) $container->get('foobar4'));
1355
1356         $foo5 = $container->get('foo5');
1357         $this->assertSame($foo5, $foo5->bar->foo);
1358     }
1359
1360     public function provideAlmostCircular()
1361     {
1362         yield array('public');
1363         yield array('private');
1364     }
1365
1366     public function testRegisterForAutoconfiguration()
1367     {
1368         $container = new ContainerBuilder();
1369         $childDefA = $container->registerForAutoconfiguration('AInterface');
1370         $childDefB = $container->registerForAutoconfiguration('BInterface');
1371         $this->assertSame(array('AInterface' => $childDefA, 'BInterface' => $childDefB), $container->getAutoconfiguredInstanceof());
1372
1373         // when called multiple times, the same instance is returned
1374         $this->assertSame($childDefA, $container->registerForAutoconfiguration('AInterface'));
1375     }
1376
1377     /**
1378      * This test checks the trigger of a deprecation note and should not be removed in major releases.
1379      *
1380      * @group legacy
1381      * @expectedDeprecation The "foo" service is deprecated. You should stop using it, as it will soon be removed.
1382      */
1383     public function testPrivateServiceTriggersDeprecation()
1384     {
1385         $container = new ContainerBuilder();
1386         $container->register('foo', 'stdClass')
1387             ->setPublic(false)
1388             ->setDeprecated(true);
1389         $container->register('bar', 'stdClass')
1390             ->setPublic(true)
1391             ->setProperty('foo', new Reference('foo'));
1392
1393         $container->compile();
1394
1395         $container->get('bar');
1396     }
1397
1398     /**
1399      * @group legacy
1400      * @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "FOO" instead of "foo" is deprecated since Symfony 3.4.
1401      */
1402     public function testParameterWithMixedCase()
1403     {
1404         $container = new ContainerBuilder(new ParameterBag(array('foo' => 'bar')));
1405         $container->register('foo', 'stdClass')
1406             ->setPublic(true)
1407             ->setProperty('foo', '%FOO%');
1408
1409         $container->compile();
1410
1411         $this->assertSame('bar', $container->get('foo')->foo);
1412     }
1413
1414     public function testArgumentsHaveHigherPriorityThanBindings()
1415     {
1416         $container = new ContainerBuilder();
1417         $container->register('class.via.bindings', CaseSensitiveClass::class)->setArguments(array(
1418             'via-bindings',
1419         ));
1420         $container->register('class.via.argument', CaseSensitiveClass::class)->setArguments(array(
1421             'via-argument',
1422         ));
1423         $container->register('foo', SimilarArgumentsDummy::class)->setPublic(true)->setBindings(array(
1424             CaseSensitiveClass::class => new Reference('class.via.bindings'),
1425             '$token' => '1234',
1426         ))->setArguments(array(
1427             '$class1' => new Reference('class.via.argument'),
1428         ));
1429
1430         $this->assertSame(array('service_container', 'class.via.bindings', 'class.via.argument', 'foo', 'Psr\Container\ContainerInterface', 'Symfony\Component\DependencyInjection\ContainerInterface'), $container->getServiceIds());
1431
1432         $container->compile();
1433
1434         $this->assertSame('via-argument', $container->get('foo')->class1->identifier);
1435         $this->assertSame('via-bindings', $container->get('foo')->class2->identifier);
1436     }
1437 }
1438
1439 class FooClass
1440 {
1441 }
1442
1443 class A
1444 {
1445 }
1446
1447 class B
1448 {
1449     public function __construct(A $a)
1450     {
1451     }
1452 }