Updated to Drupal 8.5. Core Media not yet in use.
[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     /**
669      * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
670      * @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)%".
671      */
672     public function testCompileWithArrayResolveEnv()
673     {
674         $bag = new TestingEnvPlaceholderParameterBag();
675         $container = new ContainerBuilder($bag);
676         $container->setParameter('foo', '%env(ARRAY)%');
677         $container->setParameter('bar', 'ABC %env(ARRAY)%');
678         $container->compile(true);
679     }
680
681     /**
682      * @expectedException \Symfony\Component\DependencyInjection\Exception\EnvNotFoundException
683      * @expectedExceptionMessage Environment variable not found: "FOO".
684      */
685     public function testCompileWithResolveMissingEnv()
686     {
687         $container = new ContainerBuilder();
688         $container->setParameter('foo', '%env(FOO)%');
689         $container->compile(true);
690     }
691
692     public function testDynamicEnv()
693     {
694         putenv('DUMMY_FOO=some%foo%');
695         putenv('DUMMY_BAR=%bar%');
696
697         $container = new ContainerBuilder();
698         $container->setParameter('foo', 'Foo%env(resolve:DUMMY_BAR)%');
699         $container->setParameter('bar', 'Bar');
700         $container->setParameter('baz', '%env(resolve:DUMMY_FOO)%');
701
702         $container->compile(true);
703         putenv('DUMMY_FOO');
704         putenv('DUMMY_BAR');
705
706         $this->assertSame('someFooBar', $container->getParameter('baz'));
707     }
708
709     public function testCastEnv()
710     {
711         $container = new ContainerBuilder();
712         $container->setParameter('env(FAKE)', '123');
713
714         $container->register('foo', 'stdClass')
715             ->setPublic(true)
716             ->setProperties(array(
717                 'fake' => '%env(int:FAKE)%',
718             ));
719
720         $container->compile(true);
721
722         $this->assertSame(123, $container->get('foo')->fake);
723     }
724
725     public function testEnvAreNullable()
726     {
727         $container = new ContainerBuilder();
728         $container->setParameter('env(FAKE)', null);
729
730         $container->register('foo', 'stdClass')
731             ->setPublic(true)
732             ->setProperties(array(
733             'fake' => '%env(int:FAKE)%',
734         ));
735
736         $container->compile(true);
737
738         $this->assertNull($container->get('foo')->fake);
739     }
740
741     public function testEnvInId()
742     {
743         $container = include __DIR__.'/Fixtures/containers/container_env_in_id.php';
744         $container->compile(true);
745
746         $expected = array(
747             'service_container',
748             'foo',
749             'bar',
750             'bar_%env(BAR)%',
751         );
752         $this->assertSame($expected, array_keys($container->getDefinitions()));
753
754         $expected = array(
755             PsrContainerInterface::class => true,
756             ContainerInterface::class => true,
757             'baz_%env(BAR)%' => true,
758             'bar_%env(BAR)%' => true,
759         );
760         $this->assertSame($expected, $container->getRemovedIds());
761
762         $this->assertSame(array('baz_bar'), array_keys($container->getDefinition('foo')->getArgument(1)));
763     }
764
765     /**
766      * @expectedException \Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException
767      * @expectedExceptionMessage Circular reference detected for parameter "env(resolve:DUMMY_ENV_VAR)" ("env(resolve:DUMMY_ENV_VAR)" > "env(resolve:DUMMY_ENV_VAR)").
768      */
769     public function testCircularDynamicEnv()
770     {
771         putenv('DUMMY_ENV_VAR=some%foo%');
772
773         $container = new ContainerBuilder();
774         $container->setParameter('foo', '%bar%');
775         $container->setParameter('bar', '%env(resolve:DUMMY_ENV_VAR)%');
776
777         try {
778             $container->compile(true);
779         } finally {
780             putenv('DUMMY_ENV_VAR');
781         }
782     }
783
784     /**
785      * @expectedException \LogicException
786      */
787     public function testMergeLogicException()
788     {
789         $container = new ContainerBuilder();
790         $container->setResourceTracking(false);
791         $container->compile();
792         $container->merge(new ContainerBuilder());
793     }
794
795     public function testfindTaggedServiceIds()
796     {
797         $builder = new ContainerBuilder();
798         $builder
799             ->register('foo', 'Bar\FooClass')
800             ->addTag('foo', array('foo' => 'foo'))
801             ->addTag('bar', array('bar' => 'bar'))
802             ->addTag('foo', array('foofoo' => 'foofoo'))
803         ;
804         $this->assertEquals($builder->findTaggedServiceIds('foo'), array(
805             'foo' => array(
806                 array('foo' => 'foo'),
807                 array('foofoo' => 'foofoo'),
808             ),
809         ), '->findTaggedServiceIds() returns an array of service ids and its tag attributes');
810         $this->assertEquals(array(), $builder->findTaggedServiceIds('foobar'), '->findTaggedServiceIds() returns an empty array if there is annotated services');
811     }
812
813     public function testFindUnusedTags()
814     {
815         $builder = new ContainerBuilder();
816         $builder
817             ->register('foo', 'Bar\FooClass')
818             ->addTag('kernel.event_listener', array('foo' => 'foo'))
819             ->addTag('kenrel.event_listener', array('bar' => 'bar'))
820         ;
821         $builder->findTaggedServiceIds('kernel.event_listener');
822         $this->assertEquals(array('kenrel.event_listener'), $builder->findUnusedTags(), '->findUnusedTags() returns an array with unused tags');
823     }
824
825     public function testFindDefinition()
826     {
827         $container = new ContainerBuilder();
828         $container->setDefinition('foo', $definition = new Definition('Bar\FooClass'));
829         $container->setAlias('bar', 'foo');
830         $container->setAlias('foobar', 'bar');
831         $this->assertEquals($definition, $container->findDefinition('foobar'), '->findDefinition() returns a Definition');
832     }
833
834     public function testAddObjectResource()
835     {
836         $container = new ContainerBuilder();
837
838         $container->setResourceTracking(false);
839         $container->addObjectResource(new \BarClass());
840
841         $this->assertEmpty($container->getResources(), 'No resources get registered without resource tracking');
842
843         $container->setResourceTracking(true);
844         $container->addObjectResource(new \BarClass());
845
846         $resources = $container->getResources();
847
848         $this->assertCount(2, $resources, '2 resources were registered');
849
850         /* @var $resource \Symfony\Component\Config\Resource\FileResource */
851         $resource = end($resources);
852
853         $this->assertInstanceOf('Symfony\Component\Config\Resource\FileResource', $resource);
854         $this->assertSame(realpath(__DIR__.'/Fixtures/includes/classes.php'), realpath($resource->getResource()));
855     }
856
857     /**
858      * @group legacy
859      */
860     public function testAddClassResource()
861     {
862         $container = new ContainerBuilder();
863
864         $container->setResourceTracking(false);
865         $container->addClassResource(new \ReflectionClass('BarClass'));
866
867         $this->assertEmpty($container->getResources(), 'No resources get registered without resource tracking');
868
869         $container->setResourceTracking(true);
870         $container->addClassResource(new \ReflectionClass('BarClass'));
871
872         $resources = $container->getResources();
873
874         $this->assertCount(2, $resources, '2 resources were registered');
875
876         /* @var $resource \Symfony\Component\Config\Resource\FileResource */
877         $resource = end($resources);
878
879         $this->assertInstanceOf('Symfony\Component\Config\Resource\FileResource', $resource);
880         $this->assertSame(realpath(__DIR__.'/Fixtures/includes/classes.php'), realpath($resource->getResource()));
881     }
882
883     public function testGetReflectionClass()
884     {
885         $container = new ContainerBuilder();
886
887         $container->setResourceTracking(false);
888         $r1 = $container->getReflectionClass('BarClass');
889
890         $this->assertEmpty($container->getResources(), 'No resources get registered without resource tracking');
891
892         $container->setResourceTracking(true);
893         $r2 = $container->getReflectionClass('BarClass');
894         $r3 = $container->getReflectionClass('BarClass');
895
896         $this->assertNull($container->getReflectionClass('BarMissingClass'));
897
898         $this->assertEquals($r1, $r2);
899         $this->assertSame($r2, $r3);
900
901         $resources = $container->getResources();
902
903         $this->assertCount(3, $resources, '3 resources were registered');
904
905         $this->assertSame('reflection.BarClass', (string) $resources[1]);
906         $this->assertSame('BarMissingClass', (string) end($resources));
907     }
908
909     public function testGetReflectionClassOnInternalTypes()
910     {
911         $container = new ContainerBuilder();
912
913         $this->assertNull($container->getReflectionClass('int'));
914         $this->assertNull($container->getReflectionClass('float'));
915         $this->assertNull($container->getReflectionClass('string'));
916         $this->assertNull($container->getReflectionClass('bool'));
917         $this->assertNull($container->getReflectionClass('resource'));
918         $this->assertNull($container->getReflectionClass('object'));
919         $this->assertNull($container->getReflectionClass('array'));
920         $this->assertNull($container->getReflectionClass('null'));
921         $this->assertNull($container->getReflectionClass('callable'));
922         $this->assertNull($container->getReflectionClass('iterable'));
923         $this->assertNull($container->getReflectionClass('mixed'));
924     }
925
926     public function testCompilesClassDefinitionsOfLazyServices()
927     {
928         $container = new ContainerBuilder();
929
930         $this->assertEmpty($container->getResources(), 'No resources get registered without resource tracking');
931
932         $container->register('foo', 'BarClass')->setPublic(true);
933         $container->getDefinition('foo')->setLazy(true);
934
935         $container->compile();
936
937         $matchingResources = array_filter(
938             $container->getResources(),
939             function (ResourceInterface $resource) {
940                 return 'reflection.BarClass' === (string) $resource;
941             }
942         );
943
944         $this->assertNotEmpty($matchingResources);
945     }
946
947     public function testResources()
948     {
949         $container = new ContainerBuilder();
950         $container->addResource($a = new FileResource(__DIR__.'/Fixtures/xml/services1.xml'));
951         $container->addResource($b = new FileResource(__DIR__.'/Fixtures/xml/services2.xml'));
952         $resources = array();
953         foreach ($container->getResources() as $resource) {
954             if (false === strpos($resource, '.php')) {
955                 $resources[] = $resource;
956             }
957         }
958         $this->assertEquals(array($a, $b), $resources, '->getResources() returns an array of resources read for the current configuration');
959         $this->assertSame($container, $container->setResources(array()));
960         $this->assertEquals(array(), $container->getResources());
961     }
962
963     public function testFileExists()
964     {
965         $container = new ContainerBuilder();
966         $A = new ComposerResource();
967         $a = new FileResource(__DIR__.'/Fixtures/xml/services1.xml');
968         $b = new FileResource(__DIR__.'/Fixtures/xml/services2.xml');
969         $c = new DirectoryResource($dir = dirname($b));
970
971         $this->assertTrue($container->fileExists((string) $a) && $container->fileExists((string) $b) && $container->fileExists($dir));
972
973         $resources = array();
974         foreach ($container->getResources() as $resource) {
975             if (false === strpos($resource, '.php')) {
976                 $resources[] = $resource;
977             }
978         }
979
980         $this->assertEquals(array($A, $a, $b, $c), $resources, '->getResources() returns an array of resources read for the current configuration');
981     }
982
983     public function testExtension()
984     {
985         $container = new ContainerBuilder();
986         $container->setResourceTracking(false);
987
988         $container->registerExtension($extension = new \ProjectExtension());
989         $this->assertSame($container->getExtension('project'), $extension, '->registerExtension() registers an extension');
990
991         $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('LogicException');
992         $container->getExtension('no_registered');
993     }
994
995     public function testRegisteredButNotLoadedExtension()
996     {
997         $extension = $this->getMockBuilder('Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface')->getMock();
998         $extension->expects($this->once())->method('getAlias')->will($this->returnValue('project'));
999         $extension->expects($this->never())->method('load');
1000
1001         $container = new ContainerBuilder();
1002         $container->setResourceTracking(false);
1003         $container->registerExtension($extension);
1004         $container->compile();
1005     }
1006
1007     public function testRegisteredAndLoadedExtension()
1008     {
1009         $extension = $this->getMockBuilder('Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface')->getMock();
1010         $extension->expects($this->exactly(2))->method('getAlias')->will($this->returnValue('project'));
1011         $extension->expects($this->once())->method('load')->with(array(array('foo' => 'bar')));
1012
1013         $container = new ContainerBuilder();
1014         $container->setResourceTracking(false);
1015         $container->registerExtension($extension);
1016         $container->loadFromExtension('project', array('foo' => 'bar'));
1017         $container->compile();
1018     }
1019
1020     public function testPrivateServiceUser()
1021     {
1022         $fooDefinition = new Definition('BarClass');
1023         $fooUserDefinition = new Definition('BarUserClass', array(new Reference('bar')));
1024         $container = new ContainerBuilder();
1025         $container->setResourceTracking(false);
1026
1027         $fooDefinition->setPublic(false);
1028
1029         $container->addDefinitions(array(
1030             'bar' => $fooDefinition,
1031             'bar_user' => $fooUserDefinition->setPublic(true),
1032         ));
1033
1034         $container->compile();
1035         $this->assertInstanceOf('BarClass', $container->get('bar_user')->bar);
1036     }
1037
1038     /**
1039      * @expectedException \BadMethodCallException
1040      */
1041     public function testThrowsExceptionWhenSetServiceOnACompiledContainer()
1042     {
1043         $container = new ContainerBuilder();
1044         $container->setResourceTracking(false);
1045         $container->register('a', 'stdClass')->setPublic(true);
1046         $container->compile();
1047         $container->set('a', new \stdClass());
1048     }
1049
1050     public function testThrowsExceptionWhenAddServiceOnACompiledContainer()
1051     {
1052         $container = new ContainerBuilder();
1053         $container->compile();
1054         $container->set('a', $foo = new \stdClass());
1055         $this->assertSame($foo, $container->get('a'));
1056     }
1057
1058     public function testNoExceptionWhenSetSyntheticServiceOnACompiledContainer()
1059     {
1060         $container = new ContainerBuilder();
1061         $def = new Definition('stdClass');
1062         $def->setSynthetic(true)->setPublic(true);
1063         $container->setDefinition('a', $def);
1064         $container->compile();
1065         $container->set('a', $a = new \stdClass());
1066         $this->assertEquals($a, $container->get('a'));
1067     }
1068
1069     /**
1070      * @expectedException \BadMethodCallException
1071      */
1072     public function testThrowsExceptionWhenSetDefinitionOnACompiledContainer()
1073     {
1074         $container = new ContainerBuilder();
1075         $container->setResourceTracking(false);
1076         $container->compile();
1077         $container->setDefinition('a', new Definition());
1078     }
1079
1080     public function testExtensionConfig()
1081     {
1082         $container = new ContainerBuilder();
1083
1084         $configs = $container->getExtensionConfig('foo');
1085         $this->assertEmpty($configs);
1086
1087         $first = array('foo' => 'bar');
1088         $container->prependExtensionConfig('foo', $first);
1089         $configs = $container->getExtensionConfig('foo');
1090         $this->assertEquals(array($first), $configs);
1091
1092         $second = array('ding' => 'dong');
1093         $container->prependExtensionConfig('foo', $second);
1094         $configs = $container->getExtensionConfig('foo');
1095         $this->assertEquals(array($second, $first), $configs);
1096     }
1097
1098     public function testAbstractAlias()
1099     {
1100         $container = new ContainerBuilder();
1101
1102         $abstract = new Definition('AbstractClass');
1103         $abstract->setAbstract(true)->setPublic(true);
1104
1105         $container->setDefinition('abstract_service', $abstract);
1106         $container->setAlias('abstract_alias', 'abstract_service')->setPublic(true);
1107
1108         $container->compile();
1109
1110         $this->assertSame('abstract_service', (string) $container->getAlias('abstract_alias'));
1111     }
1112
1113     public function testLazyLoadedService()
1114     {
1115         $loader = new ClosureLoader($container = new ContainerBuilder());
1116         $loader->load(function (ContainerBuilder $container) {
1117             $container->set('a', new \BazClass());
1118             $definition = new Definition('BazClass');
1119             $definition->setLazy(true);
1120             $definition->setPublic(true);
1121             $container->setDefinition('a', $definition);
1122         });
1123
1124         $container->setResourceTracking(true);
1125
1126         $container->compile();
1127
1128         $r = new \ReflectionProperty($container, 'resources');
1129         $r->setAccessible(true);
1130         $resources = $r->getValue($container);
1131
1132         $classInList = false;
1133         foreach ($resources as $resource) {
1134             if ('reflection.BazClass' === (string) $resource) {
1135                 $classInList = true;
1136                 break;
1137             }
1138         }
1139
1140         $this->assertTrue($classInList);
1141     }
1142
1143     public function testInlinedDefinitions()
1144     {
1145         $container = new ContainerBuilder();
1146
1147         $definition = new Definition('BarClass');
1148
1149         $container->register('bar_user', 'BarUserClass')
1150             ->addArgument($definition)
1151             ->setProperty('foo', $definition);
1152
1153         $container->register('bar', 'BarClass')
1154             ->setProperty('foo', $definition)
1155             ->addMethodCall('setBaz', array($definition));
1156
1157         $barUser = $container->get('bar_user');
1158         $bar = $container->get('bar');
1159
1160         $this->assertSame($barUser->foo, $barUser->bar);
1161         $this->assertSame($bar->foo, $bar->getBaz());
1162         $this->assertNotSame($bar->foo, $barUser->foo);
1163     }
1164
1165     /**
1166      * @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException
1167      * @expectedExceptionMessage Circular reference detected for service "app.test_class", path: "app.test_class -> App\TestClass -> app.test_class".
1168      */
1169     public function testThrowsCircularExceptionForCircularAliases()
1170     {
1171         $builder = new ContainerBuilder();
1172
1173         $builder->setAliases(array(
1174             'foo' => new Alias('app.test_class'),
1175             'app.test_class' => new Alias('App\\TestClass'),
1176             'App\\TestClass' => new Alias('app.test_class'),
1177         ));
1178
1179         $builder->findDefinition('foo');
1180     }
1181
1182     public function testInitializePropertiesBeforeMethodCalls()
1183     {
1184         $container = new ContainerBuilder();
1185         $container->register('foo', 'stdClass');
1186         $container->register('bar', 'MethodCallClass')
1187             ->setPublic(true)
1188             ->setProperty('simple', 'bar')
1189             ->setProperty('complex', new Reference('foo'))
1190             ->addMethodCall('callMe');
1191
1192         $container->compile();
1193
1194         $this->assertTrue($container->get('bar')->callPassed(), '->compile() initializes properties before method calls');
1195     }
1196
1197     public function testAutowiring()
1198     {
1199         $container = new ContainerBuilder();
1200
1201         $container->register(A::class)->setPublic(true);
1202         $bDefinition = $container->register('b', __NAMESPACE__.'\B');
1203         $bDefinition->setAutowired(true);
1204         $bDefinition->setPublic(true);
1205
1206         $container->compile();
1207
1208         $this->assertEquals(A::class, (string) $container->getDefinition('b')->getArgument(0));
1209     }
1210
1211     public function testClassFromId()
1212     {
1213         $container = new ContainerBuilder();
1214
1215         $unknown = $container->register('Acme\UnknownClass');
1216         $autoloadClass = $container->register(CaseSensitiveClass::class);
1217         $container->compile();
1218
1219         $this->assertSame('Acme\UnknownClass', $unknown->getClass());
1220         $this->assertEquals(CaseSensitiveClass::class, $autoloadClass->getClass());
1221     }
1222
1223     /**
1224      * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
1225      * @expectedExceptionMessage The definition for "DateTime" has no class attribute, and appears to reference a class or interface in the global namespace.
1226      */
1227     public function testNoClassFromGlobalNamespaceClassId()
1228     {
1229         $container = new ContainerBuilder();
1230
1231         $definition = $container->register(\DateTime::class);
1232         $container->compile();
1233     }
1234
1235     /**
1236      * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
1237      * @expectedExceptionMessage The definition for "123_abc" has no class.
1238      */
1239     public function testNoClassFromNonClassId()
1240     {
1241         $container = new ContainerBuilder();
1242
1243         $definition = $container->register('123_abc');
1244         $container->compile();
1245     }
1246
1247     /**
1248      * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
1249      * @expectedExceptionMessage The definition for "\foo" has no class.
1250      */
1251     public function testNoClassFromNsSeparatorId()
1252     {
1253         $container = new ContainerBuilder();
1254
1255         $definition = $container->register('\\foo');
1256         $container->compile();
1257     }
1258
1259     public function testServiceLocator()
1260     {
1261         $container = new ContainerBuilder();
1262         $container->register('foo_service', ServiceLocator::class)
1263             ->setPublic(true)
1264             ->addArgument(array(
1265                 'bar' => new ServiceClosureArgument(new Reference('bar_service')),
1266                 'baz' => new ServiceClosureArgument(new TypedReference('baz_service', 'stdClass')),
1267             ))
1268         ;
1269         $container->register('bar_service', 'stdClass')->setArguments(array(new Reference('baz_service')))->setPublic(true);
1270         $container->register('baz_service', 'stdClass')->setPublic(false);
1271         $container->compile();
1272
1273         $this->assertInstanceOf(ServiceLocator::class, $foo = $container->get('foo_service'));
1274         $this->assertSame($container->get('bar_service'), $foo->get('bar'));
1275     }
1276
1277     public function testUninitializedReference()
1278     {
1279         $container = include __DIR__.'/Fixtures/containers/container_uninitialized_ref.php';
1280         $container->compile();
1281
1282         $bar = $container->get('bar');
1283
1284         $this->assertNull($bar->foo1);
1285         $this->assertNull($bar->foo2);
1286         $this->assertNull($bar->foo3);
1287         $this->assertNull($bar->closures[0]());
1288         $this->assertNull($bar->closures[1]());
1289         $this->assertNull($bar->closures[2]());
1290         $this->assertSame(array(), iterator_to_array($bar->iter));
1291
1292         $container = include __DIR__.'/Fixtures/containers/container_uninitialized_ref.php';
1293         $container->compile();
1294
1295         $container->get('foo1');
1296         $container->get('baz');
1297
1298         $bar = $container->get('bar');
1299
1300         $this->assertEquals(new \stdClass(), $bar->foo1);
1301         $this->assertNull($bar->foo2);
1302         $this->assertEquals(new \stdClass(), $bar->foo3);
1303         $this->assertEquals(new \stdClass(), $bar->closures[0]());
1304         $this->assertNull($bar->closures[1]());
1305         $this->assertEquals(new \stdClass(), $bar->closures[2]());
1306         $this->assertEquals(array('foo1' => new \stdClass(), 'foo3' => new \stdClass()), iterator_to_array($bar->iter));
1307     }
1308
1309     /**
1310      * @dataProvider provideAlmostCircular
1311      */
1312     public function testAlmostCircular($visibility)
1313     {
1314         $container = include __DIR__.'/Fixtures/containers/container_almost_circular.php';
1315
1316         $foo = $container->get('foo');
1317         $this->assertSame($foo, $foo->bar->foobar->foo);
1318
1319         $foo2 = $container->get('foo2');
1320         $this->assertSame($foo2, $foo2->bar->foobar->foo);
1321
1322         $this->assertSame(array(), (array) $container->get('foobar4'));
1323
1324         $foo5 = $container->get('foo5');
1325         $this->assertSame($foo5, $foo5->bar->foo);
1326     }
1327
1328     public function provideAlmostCircular()
1329     {
1330         yield array('public');
1331         yield array('private');
1332     }
1333
1334     public function testRegisterForAutoconfiguration()
1335     {
1336         $container = new ContainerBuilder();
1337         $childDefA = $container->registerForAutoconfiguration('AInterface');
1338         $childDefB = $container->registerForAutoconfiguration('BInterface');
1339         $this->assertSame(array('AInterface' => $childDefA, 'BInterface' => $childDefB), $container->getAutoconfiguredInstanceof());
1340
1341         // when called multiple times, the same instance is returned
1342         $this->assertSame($childDefA, $container->registerForAutoconfiguration('AInterface'));
1343     }
1344
1345     /**
1346      * This test checks the trigger of a deprecation note and should not be removed in major releases.
1347      *
1348      * @group legacy
1349      * @expectedDeprecation The "foo" service is deprecated. You should stop using it, as it will soon be removed.
1350      */
1351     public function testPrivateServiceTriggersDeprecation()
1352     {
1353         $container = new ContainerBuilder();
1354         $container->register('foo', 'stdClass')
1355             ->setPublic(false)
1356             ->setDeprecated(true);
1357         $container->register('bar', 'stdClass')
1358             ->setPublic(true)
1359             ->setProperty('foo', new Reference('foo'));
1360
1361         $container->compile();
1362
1363         $container->get('bar');
1364     }
1365
1366     /**
1367      * @group legacy
1368      * @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "FOO" instead of "foo" is deprecated since Symfony 3.4.
1369      */
1370     public function testParameterWithMixedCase()
1371     {
1372         $container = new ContainerBuilder(new ParameterBag(array('foo' => 'bar')));
1373         $container->register('foo', 'stdClass')
1374             ->setPublic(true)
1375             ->setProperty('foo', '%FOO%');
1376
1377         $container->compile();
1378
1379         $this->assertSame('bar', $container->get('foo')->foo);
1380     }
1381
1382     public function testArgumentsHaveHigherPriorityThanBindings()
1383     {
1384         $container = new ContainerBuilder();
1385         $container->register('class.via.bindings', CaseSensitiveClass::class)->setArguments(array(
1386             'via-bindings',
1387         ));
1388         $container->register('class.via.argument', CaseSensitiveClass::class)->setArguments(array(
1389             'via-argument',
1390         ));
1391         $container->register('foo', SimilarArgumentsDummy::class)->setPublic(true)->setBindings(array(
1392             CaseSensitiveClass::class => new Reference('class.via.bindings'),
1393             '$token' => '1234',
1394         ))->setArguments(array(
1395             '$class1' => new Reference('class.via.argument'),
1396         ));
1397
1398         $this->assertSame(array('service_container', 'class.via.bindings', 'class.via.argument', 'foo', 'Psr\Container\ContainerInterface', 'Symfony\Component\DependencyInjection\ContainerInterface'), $container->getServiceIds());
1399
1400         $container->compile();
1401
1402         $this->assertSame('via-argument', $container->get('foo')->class1->identifier);
1403         $this->assertSame('via-bindings', $container->get('foo')->class2->identifier);
1404     }
1405 }
1406
1407 class FooClass
1408 {
1409 }
1410
1411 class A
1412 {
1413 }
1414
1415 class B
1416 {
1417     public function __construct(A $a)
1418     {
1419     }
1420 }
1421
1422 class TestingEnvPlaceholderParameterBag extends EnvPlaceholderParameterBag
1423 {
1424     public function get($name)
1425     {
1426         return 'env(array)' === strtolower($name) ? array(123) : parent::get($name);
1427     }
1428 }