This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
symfony/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php

1468 lines
59 KiB
PHP
Raw Normal View History

<?php
/*
2010-04-25 16:06:54 +01:00
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
2010-04-07 02:07:59 +01:00
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Tests;
require_once __DIR__.'/Fixtures/includes/classes.php';
require_once __DIR__.'/Fixtures/includes/ProjectExtension.php';
2017-02-08 07:24:27 +00:00
use PHPUnit\Framework\TestCase;
use Psr\Container\ContainerInterface as PsrContainerInterface;
use Symfony\Component\Config\Resource\ComposerResource;
2013-03-29 23:21:12 +00:00
use Symfony\Component\Config\Resource\ResourceInterface;
use Symfony\Component\Config\Resource\DirectoryResource;
2011-01-07 14:44:29 +00:00
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
2013-11-09 11:47:52 +00:00
use Symfony\Component\DependencyInjection\Loader\ClosureLoader;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Tests\Fixtures\SimilarArgumentsDummy;
use Symfony\Component\DependencyInjection\TypedReference;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition;
use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass;
use Symfony\Component\ExpressionLanguage\Expression;
2017-02-08 07:24:27 +00:00
class ContainerBuilderTest extends TestCase
{
public function testDefaultRegisteredDefinitions()
{
$builder = new ContainerBuilder();
$this->assertCount(1, $builder->getDefinitions());
$this->assertTrue($builder->hasDefinition('service_container'));
$definition = $builder->getDefinition('service_container');
$this->assertInstanceOf(Definition::class, $definition);
$this->assertTrue($definition->isSynthetic());
$this->assertSame(ContainerInterface::class, $definition->getClass());
$this->assertTrue($builder->hasAlias(PsrContainerInterface::class));
$this->assertTrue($builder->hasAlias(ContainerInterface::class));
}
public function testDefinitions()
{
$builder = new ContainerBuilder();
$definitions = array(
'foo' => new Definition('Bar\FooClass'),
'bar' => new Definition('BarClass'),
);
$builder->setDefinitions($definitions);
$this->assertEquals($definitions, $builder->getDefinitions(), '->setDefinitions() sets the service definitions');
$this->assertTrue($builder->hasDefinition('foo'), '->hasDefinition() returns true if a service definition exists');
$this->assertFalse($builder->hasDefinition('foobar'), '->hasDefinition() returns false if a service definition does not exist');
$builder->setDefinition('foobar', $foo = new Definition('FooBarClass'));
$this->assertEquals($foo, $builder->getDefinition('foobar'), '->getDefinition() returns a service definition if defined');
2017-12-11 21:55:31 +00:00
$this->assertSame($builder->setDefinition('foobar', $foo = new Definition('FooBarClass')), $foo, '->setDefinition() implements a fluid interface by returning the service reference');
$builder->addDefinitions($defs = array('foobar' => new Definition('FooBarClass')));
$this->assertEquals(array_merge($definitions, $defs), $builder->getDefinitions(), '->addDefinitions() adds the service definitions');
try {
$builder->getDefinition('baz');
$this->fail('->getDefinition() throws a ServiceNotFoundException if the service definition does not exist');
} catch (ServiceNotFoundException $e) {
$this->assertEquals('You have requested a non-existent service "baz".', $e->getMessage(), '->getDefinition() throws a ServiceNotFoundException if the service definition does not exist');
}
}
2016-07-01 07:55:04 +01:00
/**
* @group legacy
* @expectedDeprecation The "deprecated_foo" service is deprecated. You should stop using it, as it will soon be removed.
2016-07-01 07:55:04 +01:00
*/
public function testCreateDeprecatedService()
{
$definition = new Definition('stdClass');
$definition->setDeprecated(true);
$builder = new ContainerBuilder();
$builder->setDefinition('deprecated_foo', $definition);
$builder->get('deprecated_foo');
}
public function testRegister()
{
$builder = new ContainerBuilder();
$builder->register('foo', 'Bar\FooClass');
$this->assertTrue($builder->hasDefinition('foo'), '->register() registers a new service definition');
$this->assertInstanceOf('Symfony\Component\DependencyInjection\Definition', $builder->getDefinition('foo'), '->register() returns the newly created Definition instance');
}
public function testAutowire()
{
$builder = new ContainerBuilder();
$builder->autowire('foo', 'Bar\FooClass');
$this->assertTrue($builder->hasDefinition('foo'), '->autowire() registers a new service definition');
$this->assertTrue($builder->getDefinition('foo')->isAutowired(), '->autowire() creates autowired definitions');
}
2010-06-27 17:28:29 +01:00
public function testHas()
{
$builder = new ContainerBuilder();
2010-06-27 17:28:29 +01:00
$this->assertFalse($builder->has('foo'), '->has() returns false if the service does not exist');
$builder->register('foo', 'Bar\FooClass');
2010-06-27 17:28:29 +01:00
$this->assertTrue($builder->has('foo'), '->has() returns true if a service definition exists');
$builder->set('bar', new \stdClass());
$this->assertTrue($builder->has('bar'), '->has() returns true if a service exists');
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException
* @expectedExceptionMessage You have requested a non-existent service "foo".
*/
public function testGetThrowsExceptionIfServiceDoesNotExist()
{
$builder = new ContainerBuilder();
$builder->get('foo');
}
public function testGetReturnsNullIfServiceDoesNotExistAndInvalidReferenceIsUsed()
{
$builder = new ContainerBuilder();
2010-06-27 17:28:29 +01:00
$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');
}
2010-06-27 17:28:29 +01:00
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException
*/
public function testGetThrowsCircularReferenceExceptionIfServiceHasReferenceToItself()
{
$builder = new ContainerBuilder();
$builder->register('baz', 'stdClass')->setArguments(array(new Reference('baz')));
$builder->get('baz');
}
public function testGetReturnsSameInstanceWhenServiceIsShared()
{
$builder = new ContainerBuilder();
$builder->register('bar', 'stdClass');
$this->assertTrue($builder->get('bar') === $builder->get('bar'), '->get() always returns the same instance if the service is shared');
}
public function testGetCreatesServiceBasedOnDefinition()
{
$builder = new ContainerBuilder();
$builder->register('foo', 'stdClass');
$this->assertInternalType('object', $builder->get('foo'), '->get() returns the service definition associated with the id');
}
public function testGetReturnsRegisteredService()
{
$builder = new ContainerBuilder();
2010-06-27 17:28:29 +01:00
$builder->set('bar', $bar = new \stdClass());
$this->assertSame($bar, $builder->get('bar'), '->get() returns the service associated with the id');
}
public function testRegisterDoesNotOverrideExistingService()
{
$builder = new ContainerBuilder();
$builder->set('bar', $bar = new \stdClass());
$builder->register('bar', 'stdClass');
$this->assertSame($bar, $builder->get('bar'), '->get() returns the service associated with the id even if a definition has been defined');
}
public function testNonSharedServicesReturnsDifferentInstances()
{
$builder = new ContainerBuilder();
$builder->register('bar', 'stdClass')->setShared(false);
$this->assertNotSame($builder->get('bar'), $builder->get('bar'));
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage You have requested a synthetic service ("foo"). The DIC does not know how to construct this service.
*/
2013-03-06 16:55:57 +00:00
public function testGetUnsetLoadingServiceWhenCreateServiceThrowsAnException()
{
$builder = new ContainerBuilder();
$builder->register('foo', 'stdClass')->setSynthetic(true);
// we expect a RuntimeException here as foo is synthetic
try {
$builder->get('foo');
} catch (RuntimeException $e) {
}
// we must also have the same RuntimeException here
$builder->get('foo');
}
public function testGetServiceIds()
{
$builder = new ContainerBuilder();
$builder->register('foo', 'stdClass');
$builder->bar = $bar = new \stdClass();
$builder->register('bar', 'stdClass');
$this->assertEquals(
array(
'service_container',
'foo',
'bar',
'Psr\Container\ContainerInterface',
'Symfony\Component\DependencyInjection\ContainerInterface',
),
$builder->getServiceIds(),
'->getServiceIds() returns all defined service ids'
);
}
public function testAliases()
{
$builder = new ContainerBuilder();
$builder->register('foo', 'stdClass');
$builder->setAlias('bar', 'foo');
$this->assertTrue($builder->hasAlias('bar'), '->hasAlias() returns true if the alias exists');
$this->assertFalse($builder->hasAlias('foobar'), '->hasAlias() returns false if the alias does not exist');
2011-01-07 14:44:29 +00:00
$this->assertEquals('foo', (string) $builder->getAlias('bar'), '->getAlias() returns the aliased service');
2010-06-27 17:28:29 +01:00
$this->assertTrue($builder->has('bar'), '->setAlias() defines a new service');
2017-12-11 21:55:31 +00:00
$this->assertSame($builder->get('bar'), $builder->get('foo'), '->setAlias() creates a service that is an alias to another one');
try {
$builder->setAlias('foobar', 'foobar');
$this->fail('->setAlias() throws an InvalidArgumentException if the alias references itself');
} catch (\InvalidArgumentException $e) {
$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');
}
try {
$builder->getAlias('foobar');
$this->fail('->getAlias() throws an InvalidArgumentException if the alias does not exist');
} catch (\InvalidArgumentException $e) {
$this->assertEquals('The service alias "foobar" does not exist.', $e->getMessage(), '->getAlias() throws an InvalidArgumentException if the alias does not exist');
}
}
public function testGetAliases()
{
$builder = new ContainerBuilder();
$builder->setAlias('bar', 'foo');
$builder->setAlias('foobar', 'foo');
2011-01-07 14:44:29 +00:00
$builder->setAlias('moo', new Alias('foo', false));
$aliases = $builder->getAliases();
$this->assertEquals('foo', (string) $aliases['bar']);
$this->assertTrue($aliases['bar']->isPublic());
$this->assertEquals('foo', (string) $aliases['foobar']);
$this->assertEquals('foo', (string) $aliases['moo']);
$this->assertFalse($aliases['moo']->isPublic());
$builder->register('bar', 'stdClass');
2011-01-07 14:44:29 +00:00
$this->assertFalse($builder->hasAlias('bar'));
2010-06-27 17:28:29 +01:00
$builder->set('foobar', 'stdClass');
2011-01-07 14:44:29 +00:00
$builder->set('moo', 'stdClass');
$this->assertCount(2, $builder->getAliases(), '->getAliases() does not return aliased services that have been overridden');
}
2010-06-27 17:28:29 +01:00
public function testSetAliases()
{
$builder = new ContainerBuilder();
2010-06-27 17:28:29 +01:00
$builder->setAliases(array('bar' => 'foo', 'foobar' => 'foo'));
2011-01-07 14:44:29 +00:00
$aliases = $builder->getAliases();
2017-12-11 21:55:31 +00:00
$this->assertArrayHasKey('bar', $aliases);
$this->assertArrayHasKey('foobar', $aliases);
2010-06-27 17:28:29 +01:00
}
public function testAddAliases()
{
$builder = new ContainerBuilder();
2010-06-27 17:28:29 +01:00
$builder->setAliases(array('bar' => 'foo'));
$builder->addAliases(array('foobar' => 'foo'));
2011-01-07 14:44:29 +00:00
$aliases = $builder->getAliases();
2017-12-11 21:55:31 +00:00
$this->assertArrayHasKey('bar', $aliases);
$this->assertArrayHasKey('foobar', $aliases);
2010-06-27 17:28:29 +01:00
}
public function testSetReplacesAlias()
{
$builder = new ContainerBuilder();
$builder->setAlias('alias', 'aliased');
$builder->set('aliased', new \stdClass());
$builder->set('alias', $foo = new \stdClass());
$this->assertSame($foo, $builder->get('alias'), '->set() replaces an existing alias');
}
public function testAliasesKeepInvalidBehavior()
{
$builder = new ContainerBuilder();
$aliased = new Definition('stdClass');
$aliased->addMethodCall('setBar', array(new Reference('bar', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)));
$builder->setDefinition('aliased', $aliased);
$builder->setAlias('alias', 'aliased');
$this->assertEquals(new \stdClass(), $builder->get('alias'));
}
public function testAddGetCompilerPass()
{
$builder = new ContainerBuilder();
$builder->setResourceTracking(false);
$defaultPasses = $builder->getCompiler()->getPassConfig()->getPasses();
2016-12-19 16:09:34 +00:00
$builder->addCompilerPass($pass1 = $this->getMockBuilder('Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface')->getMock(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -5);
$builder->addCompilerPass($pass2 = $this->getMockBuilder('Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface')->getMock(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 10);
$passes = $builder->getCompiler()->getPassConfig()->getPasses();
$this->assertCount(\count($passes) - 2, $defaultPasses);
// Pass 1 is executed later
$this->assertTrue(array_search($pass1, $passes, true) > array_search($pass2, $passes, true));
}
public function testCreateService()
{
$builder = new ContainerBuilder();
$builder->register('foo1', 'Bar\FooClass')->setFile(__DIR__.'/Fixtures/includes/foo.php');
$builder->register('foo2', 'Bar\FooClass')->setFile(__DIR__.'/Fixtures/includes/%file%.php');
$builder->setParameter('file', 'foo');
$this->assertInstanceOf('\Bar\FooClass', $builder->get('foo1'), '->createService() requires the file defined by the service definition');
$this->assertInstanceOf('\Bar\FooClass', $builder->get('foo2'), '->createService() replaces parameters in the file provided by the service definition');
}
2013-03-29 23:21:12 +00:00
public function testCreateProxyWithRealServiceInstantiator()
{
$builder = new ContainerBuilder();
$builder->register('foo1', 'Bar\FooClass')->setFile(__DIR__.'/Fixtures/includes/foo.php');
2013-03-29 23:21:12 +00:00
$builder->getDefinition('foo1')->setLazy(true);
$foo1 = $builder->get('foo1');
$this->assertSame($foo1, $builder->get('foo1'), 'The same proxy is retrieved on multiple subsequent calls');
$this->assertSame('Bar\FooClass', \get_class($foo1));
2013-03-29 23:21:12 +00:00
}
public function testCreateServiceClass()
{
$builder = new ContainerBuilder();
$builder->register('foo1', '%class%');
$builder->setParameter('class', 'stdClass');
2010-06-27 17:28:29 +01:00
$this->assertInstanceOf('\stdClass', $builder->get('foo1'), '->createService() replaces parameters in the class provided by the service definition');
}
public function testCreateServiceArguments()
{
$builder = new ContainerBuilder();
$builder->register('bar', 'stdClass');
$builder->register('foo1', 'Bar\FooClass')->addArgument(array('foo' => '%value%', '%value%' => 'foo', new Reference('bar'), '%%unescape_it%%'));
$builder->setParameter('value', 'bar');
$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');
}
public function testCreateServiceFactory()
{
$builder = new ContainerBuilder();
$builder->register('foo', 'Bar\FooClass')->setFactory('Bar\FooClass::getInstance');
$builder->register('qux', 'Bar\FooClass')->setFactory(array('Bar\FooClass', 'getInstance'));
$builder->register('bar', 'Bar\FooClass')->setFactory(array(new Definition('Bar\FooClass'), 'getInstance'));
$builder->register('baz', 'Bar\FooClass')->setFactory(array(new Reference('bar'), 'getInstance'));
$this->assertTrue($builder->get('foo')->called, '->createService() calls the factory method to create the service instance');
$this->assertTrue($builder->get('qux')->called, '->createService() calls the factory method to create the service instance');
$this->assertTrue($builder->get('bar')->called, '->createService() uses anonymous service as factory');
$this->assertTrue($builder->get('baz')->called, '->createService() uses another service as factory');
}
public function testCreateServiceMethodCalls()
{
$builder = new ContainerBuilder();
$builder->register('bar', 'stdClass');
$builder->register('foo1', 'Bar\FooClass')->addMethodCall('setBar', array(array('%value%', new Reference('bar'))));
$builder->setParameter('value', 'bar');
2010-06-27 17:28:29 +01:00
$this->assertEquals(array('bar', $builder->get('bar')), $builder->get('foo1')->bar, '->createService() replaces the values in the method calls arguments');
}
public function testCreateServiceMethodCallsWithEscapedParam()
{
$builder = new ContainerBuilder();
$builder->register('bar', 'stdClass');
2015-11-23 10:17:36 +00:00
$builder->register('foo1', 'Bar\FooClass')->addMethodCall('setBar', array(array('%%unescape_it%%')));
$builder->setParameter('value', 'bar');
$this->assertEquals(array('%unescape_it%'), $builder->get('foo1')->bar, '->createService() replaces the values in the method calls arguments');
}
public function testCreateServiceProperties()
{
$builder = new ContainerBuilder();
$builder->register('bar', 'stdClass');
2015-11-23 10:17:36 +00:00
$builder->register('foo1', 'Bar\FooClass')->setProperty('bar', array('%value%', new Reference('bar'), '%%unescape_it%%'));
$builder->setParameter('value', 'bar');
$this->assertEquals(array('bar', $builder->get('bar'), '%unescape_it%'), $builder->get('foo1')->bar, '->createService() replaces the values in the properties');
}
public function testCreateServiceConfigurator()
{
$builder = new ContainerBuilder();
$builder->register('foo1', 'Bar\FooClass')->setConfigurator('sc_configure');
$builder->register('foo2', 'Bar\FooClass')->setConfigurator(array('%class%', 'configureStatic'));
$builder->setParameter('class', 'BazClass');
$builder->register('baz', 'BazClass');
$builder->register('foo3', 'Bar\FooClass')->setConfigurator(array(new Reference('baz'), 'configure'));
$builder->register('foo4', 'Bar\FooClass')->setConfigurator(array($builder->getDefinition('baz'), 'configure'));
$builder->register('foo5', 'Bar\FooClass')->setConfigurator('foo');
$this->assertTrue($builder->get('foo1')->configured, '->createService() calls the configurator');
$this->assertTrue($builder->get('foo2')->configured, '->createService() calls the configurator');
$this->assertTrue($builder->get('foo3')->configured, '->createService() calls the configurator');
$this->assertTrue($builder->get('foo4')->configured, '->createService() calls the configurator');
try {
$builder->get('foo5');
$this->fail('->createService() throws an InvalidArgumentException if the configure callable is not a valid callable');
} catch (\InvalidArgumentException $e) {
$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');
}
}
public function testCreateServiceWithIteratorArgument()
{
$builder = new ContainerBuilder();
$builder->register('bar', 'stdClass');
$builder
->register('lazy_context', 'LazyContext')
->setArguments(array(
new IteratorArgument(array('k1' => new Reference('bar'), new Reference('invalid', ContainerInterface::IGNORE_ON_INVALID_REFERENCE))),
new IteratorArgument(array()),
))
;
$lazyContext = $builder->get('lazy_context');
$this->assertInstanceOf(RewindableGenerator::class, $lazyContext->lazyValues);
$this->assertInstanceOf(RewindableGenerator::class, $lazyContext->lazyEmptyValues);
$this->assertCount(1, $lazyContext->lazyValues);
$this->assertCount(0, $lazyContext->lazyEmptyValues);
$i = 0;
foreach ($lazyContext->lazyValues as $k => $v) {
++$i;
$this->assertEquals('k1', $k);
$this->assertInstanceOf('\stdClass', $v);
}
// The second argument should have been ignored.
$this->assertEquals(1, $i);
$i = 0;
foreach ($lazyContext->lazyEmptyValues as $k => $v) {
++$i;
}
$this->assertEquals(0, $i);
}
/**
* @expectedException \RuntimeException
*/
public function testCreateSyntheticService()
{
$builder = new ContainerBuilder();
$builder->register('foo', 'Bar\FooClass')->setSynthetic(true);
$builder->get('foo');
}
public function testCreateServiceWithExpression()
{
$builder = new ContainerBuilder();
$builder->setParameter('bar', 'bar');
$builder->register('bar', 'BarClass');
$builder->register('foo', 'Bar\FooClass')->addArgument(array('foo' => new Expression('service("bar").foo ~ parameter("bar")')));
$this->assertEquals('foobar', $builder->get('foo')->arguments['foo']);
}
public function testResolveServices()
{
$builder = new ContainerBuilder();
$builder->register('foo', 'Bar\FooClass');
2010-06-27 17:28:29 +01:00
$this->assertEquals($builder->get('foo'), $builder->resolveServices(new Reference('foo')), '->resolveServices() resolves service references to service instances');
$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');
$this->assertEquals($builder->get('foo'), $builder->resolveServices(new Expression('service("foo")')), '->resolveServices() resolves expressions');
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage Constructing service "foo" from a parent definition is not supported at build time.
*/
public function testResolveServicesWithDecoratedDefinition()
{
$builder = new ContainerBuilder();
$builder->setDefinition('grandpa', new Definition('stdClass'));
$builder->setDefinition('parent', new ChildDefinition('grandpa'));
$builder->setDefinition('foo', new ChildDefinition('parent'));
$builder->get('foo');
}
public function testResolveServicesWithCustomDefinitionClass()
{
$builder = new ContainerBuilder();
$builder->setDefinition('foo', new CustomDefinition('stdClass'));
$this->assertInstanceOf('stdClass', $builder->get('foo'));
}
public function testMerge()
{
$container = new ContainerBuilder(new ParameterBag(array('bar' => 'foo')));
$container->setResourceTracking(false);
$config = new ContainerBuilder(new ParameterBag(array('foo' => 'bar')));
$container->merge($config);
2010-06-27 17:28:29 +01:00
$this->assertEquals(array('bar' => 'foo', 'foo' => 'bar'), $container->getParameterBag()->all(), '->merge() merges current parameters with the loaded ones');
$container = new ContainerBuilder(new ParameterBag(array('bar' => 'foo')));
$container->setResourceTracking(false);
$config = new ContainerBuilder(new ParameterBag(array('foo' => '%bar%')));
$container->merge($config);
$container->compile();
2010-06-27 17:28:29 +01:00
$this->assertEquals(array('bar' => 'foo', 'foo' => 'foo'), $container->getParameterBag()->all(), '->merge() evaluates the values of the parameters towards already defined ones');
$container = new ContainerBuilder(new ParameterBag(array('bar' => 'foo')));
$container->setResourceTracking(false);
$config = new ContainerBuilder(new ParameterBag(array('foo' => '%bar%', 'baz' => '%foo%')));
$container->merge($config);
$container->compile();
2010-06-27 17:28:29 +01:00
$this->assertEquals(array('bar' => 'foo', 'foo' => 'foo', 'baz' => 'foo'), $container->getParameterBag()->all(), '->merge() evaluates the values of the parameters towards already defined ones');
$container = new ContainerBuilder();
$container->setResourceTracking(false);
$container->register('foo', 'Bar\FooClass');
$container->register('bar', 'BarClass');
$config = new ContainerBuilder();
$config->setDefinition('baz', new Definition('BazClass'));
$config->setAlias('alias_for_foo', 'foo');
$container->merge($config);
$this->assertEquals(array('service_container', 'foo', 'bar', 'baz'), array_keys($container->getDefinitions()), '->merge() merges definitions already defined ones');
2011-01-07 14:44:29 +00:00
$aliases = $container->getAliases();
2017-12-11 21:55:31 +00:00
$this->assertArrayHasKey('alias_for_foo', $aliases);
2011-01-07 14:44:29 +00:00
$this->assertEquals('foo', (string) $aliases['alias_for_foo']);
$container = new ContainerBuilder();
$container->setResourceTracking(false);
$container->register('foo', 'Bar\FooClass');
$config->setDefinition('foo', new Definition('BazClass'));
$container->merge($config);
$this->assertEquals('BazClass', $container->getDefinition('foo')->getClass(), '->merge() overrides already defined services');
$container = new ContainerBuilder();
$bag = new EnvPlaceholderParameterBag();
$bag->get('env(Foo)');
$config = new ContainerBuilder($bag);
$this->assertSame(array('%env(Bar)%'), $config->resolveEnvPlaceholders(array($bag->get('env(Bar)'))));
$container->merge($config);
$this->assertEquals(array('Foo' => 0, 'Bar' => 1), $container->getEnvCounters());
$container = new ContainerBuilder();
$config = new ContainerBuilder();
$childDefA = $container->registerForAutoconfiguration('AInterface');
$childDefB = $config->registerForAutoconfiguration('BInterface');
$container->merge($config);
Not allowing autoconfigure, instanceofConditionals or defaults for ChildDefinition Also, not allowing arguments or method calls for autoconfigure. This is a safety mechanism, since we don't have merging logic. It will allow us to add this in the future if we want to. The reason is that parent-child definitions are a different mechanism for "inheritance" than instanceofConditionas and defaults... creating some edge cases when trying to figure out which settings "win". For example: Suppose a child and parent definitions are defined in different YAML files. The child receives public: false from its _defaults, and the parent receives public: true from its _defaults. Should the final child definition be public: true (so the parent overrides the child, even though it only came from _defaults) or public: false (where the child wins... even though it was only set from its _defaults). Or, if the parent is explicitly set to public: true, should that override the public: false of the child (which it got from its _defaults)? On one hand, the parent is being explicitly set. On the other hand, the child is explicitly in a file settings _defaults public to false. There's no correct answer. There are also problems with instanceof. The importance goes: defaults < instanceof < service definition But how does parent-child relationships fit into that? If a child has public: false from an _instanceof, but the parent explicitly sets public: true, which wins? Should we assume the parent definition wins because it's explicitly set? Or would the _instanceof win, because that's being explicitly applied to the child definition's class by an _instanceof that lives in the same file as that class (whereas the parent definition may live in a different file). Because of this, @nicolas-grekas and I (we also talked a bit to Fabien) decided that the complexity was growing too much. The solution is to not allow any of these new feature to be used by ChildDefinition objects. In other words, when you want some sort of "inheritance" for your service, you should *either* giving your service a parent *or* using defaults and instanceof. And instead of silently not applying defaults and instanceof to child definitions, I think it's better to scream that it's not supported.
2017-04-27 16:48:07 +01:00
$this->assertSame(array('AInterface' => $childDefA, 'BInterface' => $childDefB), $container->getAutoconfiguredInstanceof());
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
2017-04-20 18:21:47 +01:00
* @expectedExceptionMessage "AInterface" has already been autoconfigured and merge() does not support merging autoconfiguration for the same class/interface.
*/
public function testMergeThrowsExceptionForDuplicateAutomaticInstanceofDefinitions()
{
$container = new ContainerBuilder();
$config = new ContainerBuilder();
$container->registerForAutoconfiguration('AInterface');
$config->registerForAutoconfiguration('AInterface');
$container->merge($config);
}
public function testResolveEnvValues()
{
$_ENV['DUMMY_ENV_VAR'] = 'du%%y';
$_SERVER['DUMMY_SERVER_VAR'] = 'ABC';
$_SERVER['HTTP_DUMMY_VAR'] = 'DEF';
$container = new ContainerBuilder();
$container->setParameter('bar', '%% %env(DUMMY_ENV_VAR)% %env(DUMMY_SERVER_VAR)% %env(HTTP_DUMMY_VAR)%');
$container->setParameter('env(HTTP_DUMMY_VAR)', '123');
$this->assertSame('%% du%%%%y ABC 123', $container->resolveEnvPlaceholders('%bar%', true));
unset($_ENV['DUMMY_ENV_VAR'], $_SERVER['DUMMY_SERVER_VAR'], $_SERVER['HTTP_DUMMY_VAR']);
}
public function testResolveEnvValuesWithArray()
{
$_ENV['ANOTHER_DUMMY_ENV_VAR'] = 'dummy';
$dummyArray = array('1' => 'one', '2' => 'two');
$container = new ContainerBuilder();
$container->setParameter('dummy', '%env(ANOTHER_DUMMY_ENV_VAR)%');
$container->setParameter('dummy2', $dummyArray);
$container->resolveEnvPlaceholders('%dummy%', true);
$container->resolveEnvPlaceholders('%dummy2%', true);
$this->assertInternalType('array', $container->resolveEnvPlaceholders('%dummy2%', true));
foreach ($dummyArray as $key => $value) {
$this->assertArrayHasKey($key, $container->resolveEnvPlaceholders('%dummy2%', true));
}
unset($_ENV['ANOTHER_DUMMY_ENV_VAR']);
}
public function testCompileWithResolveEnv()
{
putenv('DUMMY_ENV_VAR=du%%y');
$_SERVER['DUMMY_SERVER_VAR'] = 'ABC';
$_SERVER['HTTP_DUMMY_VAR'] = 'DEF';
$container = new ContainerBuilder();
$container->setParameter('env(FOO)', 'Foo');
$container->setParameter('env(DUMMY_ENV_VAR)', 'GHI');
$container->setParameter('bar', '%% %env(DUMMY_ENV_VAR)% %env(DUMMY_SERVER_VAR)% %env(HTTP_DUMMY_VAR)%');
$container->setParameter('foo', '%env(FOO)%');
$container->setParameter('baz', '%foo%');
$container->setParameter('env(HTTP_DUMMY_VAR)', '123');
$container->register('teatime', 'stdClass')
->setProperty('foo', '%env(DUMMY_ENV_VAR)%')
2017-09-19 21:53:21 +01:00
->setPublic(true)
;
$container->compile(true);
$this->assertSame('% du%%y ABC 123', $container->getParameter('bar'));
$this->assertSame('Foo', $container->getParameter('baz'));
$this->assertSame('du%%y', $container->get('teatime')->foo);
unset($_SERVER['DUMMY_SERVER_VAR'], $_SERVER['HTTP_DUMMY_VAR']);
putenv('DUMMY_ENV_VAR');
}
public function testCompileWithArrayResolveEnv()
{
putenv('ARRAY={"foo":"bar"}');
$container = new ContainerBuilder();
$container->setParameter('foo', '%env(json:ARRAY)%');
$container->compile(true);
$this->assertSame(array('foo' => 'bar'), $container->getParameter('foo'));
putenv('ARRAY');
}
public function testCompileWithArrayAndAnotherResolveEnv()
{
putenv('DUMMY_ENV_VAR=abc');
putenv('ARRAY={"foo":"bar"}');
$container = new ContainerBuilder();
$container->setParameter('foo', '%env(json:ARRAY)%');
$container->setParameter('bar', '%env(DUMMY_ENV_VAR)%');
$container->compile(true);
$this->assertSame(array('foo' => 'bar'), $container->getParameter('foo'));
$this->assertSame('abc', $container->getParameter('bar'));
putenv('DUMMY_ENV_VAR');
putenv('ARRAY');
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @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)%".
*/
public function testCompileWithArrayInStringResolveEnv()
{
putenv('ARRAY={"foo":"bar"}');
$container = new ContainerBuilder();
$container->setParameter('foo', 'ABC %env(json:ARRAY)%');
$container->compile(true);
putenv('ARRAY');
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\EnvNotFoundException
* @expectedExceptionMessage Environment variable not found: "FOO".
*/
public function testCompileWithResolveMissingEnv()
{
$container = new ContainerBuilder();
$container->setParameter('foo', '%env(FOO)%');
$container->compile(true);
}
2016-10-22 17:25:15 +01:00
public function testDynamicEnv()
{
putenv('DUMMY_FOO=some%foo%');
putenv('DUMMY_BAR=%bar%');
$container = new ContainerBuilder();
$container->setParameter('foo', 'Foo%env(resolve:DUMMY_BAR)%');
$container->setParameter('bar', 'Bar');
$container->setParameter('baz', '%env(resolve:DUMMY_FOO)%');
$container->compile(true);
putenv('DUMMY_FOO');
putenv('DUMMY_BAR');
$this->assertSame('someFooBar', $container->getParameter('baz'));
}
public function testCastEnv()
{
$container = new ContainerBuilder();
$container->setParameter('env(FAKE)', '123');
2017-09-19 21:53:21 +01:00
$container->register('foo', 'stdClass')
->setPublic(true)
->setProperties(array(
'fake' => '%env(int:FAKE)%',
));
2016-10-22 17:25:15 +01:00
$container->compile(true);
$this->assertSame(123, $container->get('foo')->fake);
}
public function testEnvAreNullable()
{
$container = new ContainerBuilder();
$container->setParameter('env(FAKE)', null);
2017-09-19 21:53:21 +01:00
$container->register('foo', 'stdClass')
->setPublic(true)
->setProperties(array(
2016-10-22 17:25:15 +01:00
'fake' => '%env(int:FAKE)%',
));
$container->compile(true);
$this->assertNull($container->get('foo')->fake);
}
2017-11-24 11:48:20 +00:00
public function testEnvInId()
{
$container = include __DIR__.'/Fixtures/containers/container_env_in_id.php';
$container->compile(true);
$expected = array(
'service_container',
'foo',
'bar',
'bar_%env(BAR)%',
);
$this->assertSame($expected, array_keys($container->getDefinitions()));
$expected = array(
PsrContainerInterface::class => true,
ContainerInterface::class => true,
'baz_%env(BAR)%' => true,
'bar_%env(BAR)%' => true,
);
$this->assertSame($expected, $container->getRemovedIds());
2017-11-24 11:48:20 +00:00
$this->assertSame(array('baz_bar'), array_keys($container->getDefinition('foo')->getArgument(1)));
}
2016-10-22 17:25:15 +01:00
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException
* @expectedExceptionMessage Circular reference detected for parameter "env(resolve:DUMMY_ENV_VAR)" ("env(resolve:DUMMY_ENV_VAR)" > "env(resolve:DUMMY_ENV_VAR)").
*/
public function testCircularDynamicEnv()
{
putenv('DUMMY_ENV_VAR=some%foo%');
$container = new ContainerBuilder();
$container->setParameter('foo', '%bar%');
$container->setParameter('bar', '%env(resolve:DUMMY_ENV_VAR)%');
try {
$container->compile(true);
} finally {
putenv('DUMMY_ENV_VAR');
}
}
/**
2013-11-25 08:44:14 +00:00
* @expectedException \LogicException
*/
public function testMergeLogicException()
{
$container = new ContainerBuilder();
$container->setResourceTracking(false);
$container->compile();
$container->merge(new ContainerBuilder());
}
2010-08-05 06:34:53 +01:00
public function testfindTaggedServiceIds()
{
$builder = new ContainerBuilder();
$builder
->register('foo', 'Bar\FooClass')
2010-08-05 06:34:53 +01:00
->addTag('foo', array('foo' => 'foo'))
->addTag('bar', array('bar' => 'bar'))
->addTag('foo', array('foofoo' => 'foofoo'))
;
2010-08-05 06:34:53 +01:00
$this->assertEquals($builder->findTaggedServiceIds('foo'), array(
'foo' => array(
array('foo' => 'foo'),
array('foofoo' => 'foofoo'),
2014-09-21 19:53:12 +01:00
),
2010-08-05 06:34:53 +01:00
), '->findTaggedServiceIds() returns an array of service ids and its tag attributes');
$this->assertEquals(array(), $builder->findTaggedServiceIds('foobar'), '->findTaggedServiceIds() returns an empty array if there is annotated services');
}
public function testFindUnusedTags()
{
$builder = new ContainerBuilder();
$builder
->register('foo', 'Bar\FooClass')
->addTag('kernel.event_listener', array('foo' => 'foo'))
->addTag('kenrel.event_listener', array('bar' => 'bar'))
;
$builder->findTaggedServiceIds('kernel.event_listener');
$this->assertEquals(array('kenrel.event_listener'), $builder->findUnusedTags(), '->findUnusedTags() returns an array with unused tags');
}
public function testFindDefinition()
{
$container = new ContainerBuilder();
$container->setDefinition('foo', $definition = new Definition('Bar\FooClass'));
$container->setAlias('bar', 'foo');
$container->setAlias('foobar', 'bar');
$this->assertEquals($definition, $container->findDefinition('foobar'), '->findDefinition() returns a Definition');
}
2013-03-29 23:21:12 +00:00
public function testAddObjectResource()
{
$container = new ContainerBuilder();
$container->setResourceTracking(false);
$container->addObjectResource(new \BarClass());
$this->assertEmpty($container->getResources(), 'No resources get registered without resource tracking');
$container->setResourceTracking(true);
$container->addObjectResource(new \BarClass());
$resources = $container->getResources();
$this->assertCount(2, $resources, '2 resources were registered');
2013-03-29 23:21:12 +00:00
/* @var $resource \Symfony\Component\Config\Resource\FileResource */
$resource = end($resources);
$this->assertInstanceOf('Symfony\Component\Config\Resource\FileResource', $resource);
$this->assertSame(realpath(__DIR__.'/Fixtures/includes/classes.php'), realpath($resource->getResource()));
}
/**
* @group legacy
*/
2013-03-29 23:21:12 +00:00
public function testAddClassResource()
{
$container = new ContainerBuilder();
$container->setResourceTracking(false);
$container->addClassResource(new \ReflectionClass('BarClass'));
$this->assertEmpty($container->getResources(), 'No resources get registered without resource tracking');
$container->setResourceTracking(true);
$container->addClassResource(new \ReflectionClass('BarClass'));
$resources = $container->getResources();
$this->assertCount(2, $resources, '2 resources were registered');
2013-03-29 23:21:12 +00:00
/* @var $resource \Symfony\Component\Config\Resource\FileResource */
$resource = end($resources);
$this->assertInstanceOf('Symfony\Component\Config\Resource\FileResource', $resource);
$this->assertSame(realpath(__DIR__.'/Fixtures/includes/classes.php'), realpath($resource->getResource()));
}
public function testGetReflectionClass()
{
$container = new ContainerBuilder();
$container->setResourceTracking(false);
$r1 = $container->getReflectionClass('BarClass');
$this->assertEmpty($container->getResources(), 'No resources get registered without resource tracking');
$container->setResourceTracking(true);
$r2 = $container->getReflectionClass('BarClass');
$r3 = $container->getReflectionClass('BarClass');
$this->assertNull($container->getReflectionClass('BarMissingClass'));
$this->assertEquals($r1, $r2);
$this->assertSame($r2, $r3);
$resources = $container->getResources();
$this->assertCount(3, $resources, '3 resources were registered');
$this->assertSame('reflection.BarClass', (string) $resources[1]);
$this->assertSame('BarMissingClass', (string) end($resources));
}
public function testGetReflectionClassOnInternalTypes()
{
$container = new ContainerBuilder();
$this->assertNull($container->getReflectionClass('int'));
$this->assertNull($container->getReflectionClass('float'));
$this->assertNull($container->getReflectionClass('string'));
$this->assertNull($container->getReflectionClass('bool'));
$this->assertNull($container->getReflectionClass('resource'));
$this->assertNull($container->getReflectionClass('object'));
$this->assertNull($container->getReflectionClass('array'));
$this->assertNull($container->getReflectionClass('null'));
$this->assertNull($container->getReflectionClass('callable'));
$this->assertNull($container->getReflectionClass('iterable'));
$this->assertNull($container->getReflectionClass('mixed'));
}
2013-03-29 23:21:12 +00:00
public function testCompilesClassDefinitionsOfLazyServices()
{
$container = new ContainerBuilder();
$this->assertEmpty($container->getResources(), 'No resources get registered without resource tracking');
2017-09-19 21:53:21 +01:00
$container->register('foo', 'BarClass')->setPublic(true);
2013-03-29 23:21:12 +00:00
$container->getDefinition('foo')->setLazy(true);
$container->compile();
$matchingResources = array_filter(
$container->getResources(),
function (ResourceInterface $resource) {
return 'reflection.BarClass' === (string) $resource;
2013-03-29 23:21:12 +00:00
}
);
$this->assertNotEmpty($matchingResources);
}
public function testResources()
{
$container = new ContainerBuilder();
$container->addResource($a = new FileResource(__DIR__.'/Fixtures/xml/services1.xml'));
$container->addResource($b = new FileResource(__DIR__.'/Fixtures/xml/services2.xml'));
$resources = array();
foreach ($container->getResources() as $resource) {
if (false === strpos($resource, '.php')) {
$resources[] = $resource;
}
}
$this->assertEquals(array($a, $b), $resources, '->getResources() returns an array of resources read for the current configuration');
2011-09-16 12:43:09 +01:00
$this->assertSame($container, $container->setResources(array()));
$this->assertEquals(array(), $container->getResources());
}
public function testFileExists()
{
$container = new ContainerBuilder();
$A = new ComposerResource();
$a = new FileResource(__DIR__.'/Fixtures/xml/services1.xml');
$b = new FileResource(__DIR__.'/Fixtures/xml/services2.xml');
$c = new DirectoryResource($dir = \dirname($b));
$this->assertTrue($container->fileExists((string) $a) && $container->fileExists((string) $b) && $container->fileExists($dir));
$resources = array();
foreach ($container->getResources() as $resource) {
if (false === strpos($resource, '.php')) {
$resources[] = $resource;
}
}
$this->assertEquals(array($A, $a, $b, $c), $resources, '->getResources() returns an array of resources read for the current configuration');
}
public function testExtension()
{
$container = new ContainerBuilder();
$container->setResourceTracking(false);
$container->registerExtension($extension = new \ProjectExtension());
2017-12-11 21:55:31 +00:00
$this->assertSame($container->getExtension('project'), $extension, '->registerExtension() registers an extension');
$this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('LogicException');
$container->getExtension('no_registered');
}
public function testRegisteredButNotLoadedExtension()
{
2016-12-19 16:09:34 +00:00
$extension = $this->getMockBuilder('Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface')->getMock();
$extension->expects($this->once())->method('getAlias')->will($this->returnValue('project'));
$extension->expects($this->never())->method('load');
$container = new ContainerBuilder();
$container->setResourceTracking(false);
$container->registerExtension($extension);
$container->compile();
}
public function testRegisteredAndLoadedExtension()
{
2016-12-19 16:09:34 +00:00
$extension = $this->getMockBuilder('Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface')->getMock();
$extension->expects($this->exactly(2))->method('getAlias')->will($this->returnValue('project'));
$extension->expects($this->once())->method('load')->with(array(array('foo' => 'bar')));
$container = new ContainerBuilder();
$container->setResourceTracking(false);
$container->registerExtension($extension);
$container->loadFromExtension('project', array('foo' => 'bar'));
$container->compile();
}
public function testPrivateServiceUser()
{
2014-10-22 19:27:13 +01:00
$fooDefinition = new Definition('BarClass');
$fooUserDefinition = new Definition('BarUserClass', array(new Reference('bar')));
2014-10-22 19:27:13 +01:00
$container = new ContainerBuilder();
$container->setResourceTracking(false);
$fooDefinition->setPublic(false);
$container->addDefinitions(array(
2014-10-22 19:27:13 +01:00
'bar' => $fooDefinition,
2017-09-19 21:53:21 +01:00
'bar_user' => $fooUserDefinition->setPublic(true),
));
$container->compile();
$this->assertInstanceOf('BarClass', $container->get('bar_user')->bar);
}
/**
2013-11-25 08:44:14 +00:00
* @expectedException \BadMethodCallException
*/
public function testThrowsExceptionWhenSetServiceOnACompiledContainer()
{
$container = new ContainerBuilder();
$container->setResourceTracking(false);
2017-09-19 21:53:21 +01:00
$container->register('a', 'stdClass')->setPublic(true);
$container->compile();
$container->set('a', new \stdClass());
}
public function testThrowsExceptionWhenAddServiceOnACompiledContainer()
{
$container = new ContainerBuilder();
$container->compile();
$container->set('a', $foo = new \stdClass());
$this->assertSame($foo, $container->get('a'));
}
public function testNoExceptionWhenSetSyntheticServiceOnACompiledContainer()
{
$container = new ContainerBuilder();
$def = new Definition('stdClass');
2017-09-19 21:53:21 +01:00
$def->setSynthetic(true)->setPublic(true);
$container->setDefinition('a', $def);
$container->compile();
$container->set('a', $a = new \stdClass());
$this->assertEquals($a, $container->get('a'));
}
/**
2013-11-25 08:44:14 +00:00
* @expectedException \BadMethodCallException
*/
public function testThrowsExceptionWhenSetDefinitionOnACompiledContainer()
{
$container = new ContainerBuilder();
$container->setResourceTracking(false);
$container->compile();
$container->setDefinition('a', new Definition());
}
public function testExtensionConfig()
{
$container = new ContainerBuilder();
$configs = $container->getExtensionConfig('foo');
$this->assertEmpty($configs);
$first = array('foo' => 'bar');
$container->prependExtensionConfig('foo', $first);
$configs = $container->getExtensionConfig('foo');
$this->assertEquals(array($first), $configs);
$second = array('ding' => 'dong');
$container->prependExtensionConfig('foo', $second);
$configs = $container->getExtensionConfig('foo');
$this->assertEquals(array($second, $first), $configs);
}
2013-11-09 11:47:52 +00:00
public function testAbstractAlias()
{
$container = new ContainerBuilder();
$abstract = new Definition('AbstractClass');
2017-09-19 21:53:21 +01:00
$abstract->setAbstract(true)->setPublic(true);
$container->setDefinition('abstract_service', $abstract);
2017-09-19 21:53:21 +01:00
$container->setAlias('abstract_alias', 'abstract_service')->setPublic(true);
$container->compile();
$this->assertSame('abstract_service', (string) $container->getAlias('abstract_alias'));
}
2013-11-09 11:47:52 +00:00
public function testLazyLoadedService()
{
$loader = new ClosureLoader($container = new ContainerBuilder());
$loader->load(function (ContainerBuilder $container) {
2016-10-30 09:34:06 +00:00
$container->set('a', new \BazClass());
$definition = new Definition('BazClass');
$definition->setLazy(true);
2017-09-19 21:53:21 +01:00
$definition->setPublic(true);
2016-10-30 09:34:06 +00:00
$container->setDefinition('a', $definition);
});
2013-11-09 11:47:52 +00:00
$container->setResourceTracking(true);
$container->compile();
$r = new \ReflectionProperty($container, 'resources');
$r->setAccessible(true);
$resources = $r->getValue($container);
$classInList = false;
foreach ($resources as $resource) {
if ('reflection.BazClass' === (string) $resource) {
2013-11-09 11:47:52 +00:00
$classInList = true;
break;
}
}
2014-03-27 14:19:35 +00:00
$this->assertTrue($classInList);
2013-11-09 11:47:52 +00:00
}
public function testInlinedDefinitions()
{
$container = new ContainerBuilder();
$definition = new Definition('BarClass');
$container->register('bar_user', 'BarUserClass')
->addArgument($definition)
->setProperty('foo', $definition);
$container->register('bar', 'BarClass')
->setProperty('foo', $definition)
->addMethodCall('setBaz', array($definition));
$barUser = $container->get('bar_user');
$bar = $container->get('bar');
$this->assertSame($barUser->foo, $barUser->bar);
$this->assertSame($bar->foo, $bar->getBaz());
$this->assertNotSame($bar->foo, $barUser->foo);
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException
2017-12-07 17:06:18 +00:00
* @expectedExceptionMessage Circular reference detected for service "app.test_class", path: "app.test_class -> App\TestClass -> app.test_class".
*/
public function testThrowsCircularExceptionForCircularAliases()
{
$builder = new ContainerBuilder();
$builder->setAliases(array(
2017-12-07 17:06:18 +00:00
'foo' => new Alias('app.test_class'),
'app.test_class' => new Alias('App\\TestClass'),
'App\\TestClass' => new Alias('app.test_class'),
));
2017-12-07 17:06:18 +00:00
$builder->findDefinition('foo');
}
public function testInitializePropertiesBeforeMethodCalls()
{
$container = new ContainerBuilder();
$container->register('foo', 'stdClass');
$container->register('bar', 'MethodCallClass')
2017-09-19 21:53:21 +01:00
->setPublic(true)
->setProperty('simple', 'bar')
->setProperty('complex', new Reference('foo'))
->addMethodCall('callMe');
$container->compile();
$this->assertTrue($container->get('bar')->callPassed(), '->compile() initializes properties before method calls');
}
public function testAutowiring()
{
$container = new ContainerBuilder();
2017-09-19 21:53:21 +01:00
$container->register(A::class)->setPublic(true);
$bDefinition = $container->register('b', __NAMESPACE__.'\B');
$bDefinition->setAutowired(true);
2017-09-19 21:53:21 +01:00
$bDefinition->setPublic(true);
$container->compile();
$this->assertEquals(A::class, (string) $container->getDefinition('b')->getArgument(0));
}
public function testClassFromId()
{
$container = new ContainerBuilder();
$unknown = $container->register('Acme\UnknownClass');
$autoloadClass = $container->register(CaseSensitiveClass::class);
$container->compile();
$this->assertSame('Acme\UnknownClass', $unknown->getClass());
$this->assertEquals(CaseSensitiveClass::class, $autoloadClass->getClass());
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage The definition for "DateTime" has no class attribute, and appears to reference a class or interface in the global namespace.
*/
public function testNoClassFromGlobalNamespaceClassId()
{
$container = new ContainerBuilder();
$definition = $container->register(\DateTime::class);
$container->compile();
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage The definition for "123_abc" has no class.
*/
public function testNoClassFromNonClassId()
{
$container = new ContainerBuilder();
$definition = $container->register('123_abc');
$container->compile();
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExceptionMessage The definition for "\foo" has no class.
*/
public function testNoClassFromNsSeparatorId()
{
$container = new ContainerBuilder();
$definition = $container->register('\\foo');
$container->compile();
}
public function testServiceLocator()
{
$container = new ContainerBuilder();
$container->register('foo_service', ServiceLocator::class)
2017-09-19 21:53:21 +01:00
->setPublic(true)
->addArgument(array(
'bar' => new ServiceClosureArgument(new Reference('bar_service')),
'baz' => new ServiceClosureArgument(new TypedReference('baz_service', 'stdClass')),
))
;
2017-09-19 21:53:21 +01:00
$container->register('bar_service', 'stdClass')->setArguments(array(new Reference('baz_service')))->setPublic(true);
$container->register('baz_service', 'stdClass')->setPublic(false);
$container->compile();
$this->assertInstanceOf(ServiceLocator::class, $foo = $container->get('foo_service'));
$this->assertSame($container->get('bar_service'), $foo->get('bar'));
}
public function testUninitializedReference()
{
$container = include __DIR__.'/Fixtures/containers/container_uninitialized_ref.php';
$container->compile();
$bar = $container->get('bar');
$this->assertNull($bar->foo1);
$this->assertNull($bar->foo2);
$this->assertNull($bar->foo3);
$this->assertNull($bar->closures[0]());
$this->assertNull($bar->closures[1]());
$this->assertNull($bar->closures[2]());
$this->assertSame(array(), iterator_to_array($bar->iter));
$container = include __DIR__.'/Fixtures/containers/container_uninitialized_ref.php';
$container->compile();
$container->get('foo1');
$container->get('baz');
$bar = $container->get('bar');
$this->assertEquals(new \stdClass(), $bar->foo1);
$this->assertNull($bar->foo2);
$this->assertEquals(new \stdClass(), $bar->foo3);
$this->assertEquals(new \stdClass(), $bar->closures[0]());
$this->assertNull($bar->closures[1]());
$this->assertEquals(new \stdClass(), $bar->closures[2]());
$this->assertEquals(array('foo1' => new \stdClass(), 'foo3' => new \stdClass()), iterator_to_array($bar->iter));
}
/**
* @dataProvider provideAlmostCircular
*/
public function testAlmostCircular($visibility)
{
$container = include __DIR__.'/Fixtures/containers/container_almost_circular.php';
$foo = $container->get('foo');
$this->assertSame($foo, $foo->bar->foobar->foo);
$foo2 = $container->get('foo2');
$this->assertSame($foo2, $foo2->bar->foobar->foo);
$this->assertSame(array(), (array) $container->get('foobar4'));
$foo5 = $container->get('foo5');
$this->assertSame($foo5, $foo5->bar->foo);
}
public function provideAlmostCircular()
{
yield array('public');
yield array('private');
}
public function testRegisterForAutoconfiguration()
{
$container = new ContainerBuilder();
$childDefA = $container->registerForAutoconfiguration('AInterface');
$childDefB = $container->registerForAutoconfiguration('BInterface');
Not allowing autoconfigure, instanceofConditionals or defaults for ChildDefinition Also, not allowing arguments or method calls for autoconfigure. This is a safety mechanism, since we don't have merging logic. It will allow us to add this in the future if we want to. The reason is that parent-child definitions are a different mechanism for "inheritance" than instanceofConditionas and defaults... creating some edge cases when trying to figure out which settings "win". For example: Suppose a child and parent definitions are defined in different YAML files. The child receives public: false from its _defaults, and the parent receives public: true from its _defaults. Should the final child definition be public: true (so the parent overrides the child, even though it only came from _defaults) or public: false (where the child wins... even though it was only set from its _defaults). Or, if the parent is explicitly set to public: true, should that override the public: false of the child (which it got from its _defaults)? On one hand, the parent is being explicitly set. On the other hand, the child is explicitly in a file settings _defaults public to false. There's no correct answer. There are also problems with instanceof. The importance goes: defaults < instanceof < service definition But how does parent-child relationships fit into that? If a child has public: false from an _instanceof, but the parent explicitly sets public: true, which wins? Should we assume the parent definition wins because it's explicitly set? Or would the _instanceof win, because that's being explicitly applied to the child definition's class by an _instanceof that lives in the same file as that class (whereas the parent definition may live in a different file). Because of this, @nicolas-grekas and I (we also talked a bit to Fabien) decided that the complexity was growing too much. The solution is to not allow any of these new feature to be used by ChildDefinition objects. In other words, when you want some sort of "inheritance" for your service, you should *either* giving your service a parent *or* using defaults and instanceof. And instead of silently not applying defaults and instanceof to child definitions, I think it's better to scream that it's not supported.
2017-04-27 16:48:07 +01:00
$this->assertSame(array('AInterface' => $childDefA, 'BInterface' => $childDefB), $container->getAutoconfiguredInstanceof());
// when called multiple times, the same instance is returned
$this->assertSame($childDefA, $container->registerForAutoconfiguration('AInterface'));
}
2017-07-17 10:57:18 +01:00
/**
* This test checks the trigger of a deprecation note and should not be removed in major releases.
*
* @group legacy
* @expectedDeprecation The "foo" service is deprecated. You should stop using it, as it will soon be removed.
*/
public function testPrivateServiceTriggersDeprecation()
{
$container = new ContainerBuilder();
$container->register('foo', 'stdClass')
->setPublic(false)
->setDeprecated(true);
$container->register('bar', 'stdClass')
->setPublic(true)
->setProperty('foo', new Reference('foo'));
$container->compile();
$container->get('bar');
}
2017-08-12 10:16:19 +01:00
/**
* @group legacy
2017-12-31 06:25:36 +00:00
* @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "FOO" instead of "foo" is deprecated since Symfony 3.4.
2017-08-12 10:16:19 +01:00
*/
public function testParameterWithMixedCase()
{
$container = new ContainerBuilder(new ParameterBag(array('foo' => 'bar')));
$container->register('foo', 'stdClass')
2017-09-19 21:53:21 +01:00
->setPublic(true)
2017-08-12 10:16:19 +01:00
->setProperty('foo', '%FOO%');
$container->compile();
$this->assertSame('bar', $container->get('foo')->foo);
}
public function testArgumentsHaveHigherPriorityThanBindings()
{
$container = new ContainerBuilder();
$container->register('class.via.bindings', CaseSensitiveClass::class)->setArguments(array(
'via-bindings',
));
$container->register('class.via.argument', CaseSensitiveClass::class)->setArguments(array(
'via-argument',
));
$container->register('foo', SimilarArgumentsDummy::class)->setPublic(true)->setBindings(array(
CaseSensitiveClass::class => new Reference('class.via.bindings'),
'$token' => '1234',
))->setArguments(array(
'$class1' => new Reference('class.via.argument'),
));
$this->assertSame(array('service_container', 'class.via.bindings', 'class.via.argument', 'foo', 'Psr\Container\ContainerInterface', 'Symfony\Component\DependencyInjection\ContainerInterface'), $container->getServiceIds());
$container->compile();
$this->assertSame('via-argument', $container->get('foo')->class1->identifier);
$this->assertSame('via-bindings', $container->get('foo')->class2->identifier);
}
public function testUninitializedSyntheticReference()
{
$container = new ContainerBuilder();
$container->register('foo', 'stdClass')->setPublic(true)->setSynthetic(true);
$container->register('bar', 'stdClass')->setPublic(true)->setShared(false)
->setProperty('foo', new Reference('foo', ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE));
$container->compile();
$this->assertEquals((object) array('foo' => null), $container->get('bar'));
$container->set('foo', (object) array(123));
$this->assertEquals((object) array('foo' => (object) array(123)), $container->get('bar'));
}
}
2014-09-21 19:53:12 +01:00
class FooClass
{
}
2014-03-27 14:19:35 +00:00
class A
{
}
class B
{
public function __construct(A $a)
{
}
}