8000 deprecate get() for uncompiled container builders by xabbuh · Pull Request #18728 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

deprecate get() for uncompiled container builders #18728

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
deprecate get() for uncompiled container builders
  • Loading branch information
xabbuh committed May 9, 2016
commit cd7e6c496a477615f8e0adeb545b3d9360e3472b
8 changes: 8 additions & 0 deletions UPGRADE-3.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
UPGRADE FROM 3.1 to 3.2
=======================

DependencyInjection
-------------------

* Calling `get()` on a `ContainerBuilder` instance before compiling the
container is deprecated and will throw an exception in Symfony 4.0.
3 changes: 3 additions & 0 deletions UPGRADE-4.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ UPGRADE FROM 3.x to 4.0
DependencyInjection
-------------------

* Calling `get()` on a `ContainerBuilder` instance before compiling the
container is not supported anymore and will throw an exception.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wdyt about replacing and will throw by and throws ?


* Using unsupported configuration keys in YAML configuration files raises an
exception.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
*/
private $usedTags = array();

private $compiled = false;

/**
* Sets the track resources flag.
*
Expand Down Expand Up @@ -409,6 +411,10 @@ public function has($id)
*/
public function get($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE)
{
if (!$this->compiled) {
@trigger_error(sprintf('Calling %s before compiling the container is deprecated since version 3.2 and will throw an exception in 4.0.', __METHOD__), E_USER_DEPRECATED);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error message will be displayed like this:

Calling get before compiling the container is ...

get here may be confusing. What if we add the ( and ) to the method name?

Calling get() before compiling the container is ...

Or wrap the method name with quotes:

Calling "get" before compiling the container is ...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch, I added parentheses after the method name

}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may want to think about moving this down after the call to the parent class' get() method (so you would be able to retrieve services that have been added using set() before). Alternatively, deprecating set() too might be another way to go.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #19192


$id = strtolower($id);

if ($service = parent::get($id, ContainerInterface::NULL_ON_INVALID_REFERENCE)) {
Expand Down Expand Up @@ -543,6 +549,7 @@ public function compile()
}

$compiler->compile($this);
$this->compiled = true;

if ($this->trackResources) {
foreach ($this->definitions as $definition) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,14 +180,17 @@ private function findNodes()
}

foreach ($container->getServiceIds() as $id) {
$service = $container->get($id);

if (array_key_exists($id, $container->getAliases())) {
continue;
}

if (!$container->hasDefinition($id)) {
$class = ('service_container' === $id) ? get_class($this->container) : get_class($service);
if ('service_container' === $id) {
$class = get_class($this->container);
} else {
$class = get_class($container->get($id));
}

$nodes[$id] = array('class' => str_replace('\\', '\\\\', $class), 'attributes' => $this->options['node.instance']);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ public function testProcessWithNonExistingAlias()
$pass->process($container);

$this->assertEquals('Symfony\Component\DependencyInjection\Tests\Compiler\ServiceClassDefault', $container->getDefinition('example')->getClass());
$this->assertInstanceOf('Symfony\Component\DependencyInjection\Tests\Compiler\ServiceClassDefault', $container->get('example'));
}

public function testProcessWithExistingAlias()
Expand All @@ -75,7 +74,7 @@ public function testProcessWithExistingAlias()

$this->assertTrue($container->hasAlias('example'));
$this->assertEquals('mysql.example', $container->getAlias('example'));
$this->assertInstanceOf('Symfony\Component\DependencyInjection\Tests\Compiler\ServiceClassMysql', $container->get('example'));
$this->assertSame('Symfony\Component\DependencyInjection\Tests\Compiler\ServiceClassMysql', $container->getDefinition('mysql.example')->getClass());
}

public function testProcessWithManualAlias()
Expand All @@ -86,7 +85,7 @@ public function testProcessWithManualAlias()
->addTag('auto_alias', array('format' => '%existing%.example'));

$container->register('mysql.example', 'Symfony\Component\DependencyInjection\Tests\Compiler\ServiceClassMysql');
$container->register('mariadb.example', 'Symfony\Component\DependencyInjection\Tests\Compiler\ServiceClassMariadb');
$container->register('mariadb.example', 'Symfony\Component\DependencyInjection\Tests\Compiler\ServiceClassMariaDb');
$container->setAlias('example', 'mariadb.example');
$container->setParameter('existing', 'mysql');

Expand All @@ -95,7 +94,7 @@ public function testProcessWithManualAlias()

$this->assertTrue($container->hasAlias('example'));
$this->assertEquals('mariadb.example', $container->getAlias('example'));
$this->assertInstanceOf('Symfony\Component\DependencyInjection\Tests\Compiler\ServiceClassMariaDb', $container->get('example'));
$this->assertSame('Symfony\Component\DependencyInjection\Tests\Compiler\ServiceClassMariaDb', $container->getDefinition('mariadb.example')->getClass());
}
}

Expand Down
134 changes: 106 additions & 28 deletions src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\DependencyInjection\Loader\ClosureLoader;
use Symfony\Component\DependencyInjection\Reference;
Expand Down Expand Up @@ -76,6 +74,9 @@ public function testCreateDeprecatedService()

$builder = new ContainerBuilder();
$builder->setDefinition('deprecated_foo', $definition);

$builder->compile();

$builder->get('deprecated_foo');

restore_error_handler();
Expand All @@ -102,41 +103,80 @@ public function testHas()
$this->assertTrue($builder->has('bar'), '->has() returns true if a service exists');
}

public function testGet()
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException
* @expectedExceptionMessage You have requested a non-existent service "foo".
*/
public function testGetThrowsExceptionIfServiceDoesNotExist()
{
$builder = new ContainerBuilder();
try {
$builder->get('foo');
$this->fail('->get() throws a ServiceNotFoundException if the service does not exist');
} catch (ServiceNotFoundException $e) {
$this->assertEquals('You have requested a non-existent service "foo".', $e->getMessage(), '->get() throws a ServiceNotFoundException if the service does not exist');
}
$builder->compile();
$builder->get('foo');
}

public function testGetReturnsNullIfServiceDoesNotExistAndInvalidReferenceIsUsed()
{
$builder = new ContainerBuilder();
$builder->compile();

$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');
}

/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException
*/
public function testGetThrowsCircularReferenceExceptionIfServiceHasReferenceToItself()
{
$builder = new ContainerBuilder();
10000 $builder->register('baz', 'stdClass')->setArguments(array(new Reference('baz')));
$builder->compile();
$builder->get('baz');
}

public function testGetReturnsSameInstanceWhenServiceIsShared()
{
$builder = new ContainerBuilder();
$builder->register('bar', 'stdClass');
$builder->compile();

$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');
$builder->compile();

$this->assertInternalType('object', $builder->get('foo'), '->get() returns the service definition associated with the id');
}

public function testGetReturnsRegisteredService()
{
$builder = new ContainerBuilder();
$builder->set('bar', $bar = new \stdClass());
$this->assertEquals($bar, $builder->get('bar'), '->get() returns the service associated with the id');
$builder->register('bar', 'stdClass');
$this->assertEquals($bar, $builder->get('bar'), '->get() returns the service associated with the id even if a definition has been defined');
$builder->compile();

$builder->register('baz', 'stdClass')->setArguments(array(new Reference('baz')));
try {
@$builder->get('baz');
$this->fail('->get() throws a ServiceCircularReferenceException if the service has a circular reference to itself');
} catch (\Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException $e) {
$this->assertEquals('Circular reference detected for service "baz", path: "baz".', $e->getMessage(), '->get() throws a LogicException if the service has a circular reference to itself');
}
$this->assertSame($bar, $builder->get('bar'), '->get() returns the service associated with the id');
}

$this->assertTrue($builder->get('bar') === $builder->get('bar'), '->get() always returns the same instance if the service is shared');
public function testRegisterDoesNotOverrideExistingService()
{
$builder = new ContainerBuilder();
$builder->set('bar', $bar = new \stdClass());
$builder->register('bar', 'stdClass');
$builder->compile();

$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);

$builder->compile();

$this->assertNotSame($builder->get('bar'), $builder->get('bar'));
}

Expand All @@ -149,6 +189,8 @@ public function testGetUnsetLoadingServiceWhenCreateServiceThrowsAnException()
$builder = new ContainerBuilder();
$builder->register('foo', 'stdClass')->setSynthetic(true);

$builder->compile();

// we expect a RuntimeException here as foo is synthetic
try {
$builder->get('foo');
Expand Down Expand Up @@ -177,6 +219,9 @@ public function testAliases()
$this->assertFalse($builder->hasAlias('foobar'), '->hasAlias() returns false if the alias does not exist');
$this->assertEquals('foo', (string) $builder->getAlias('bar'), '->getAlias() returns the aliased service');
$this->assertTrue($builder->has('bar'), '->setAlias() defines a new service');

$builder->compile();

$this->assertTrue($builder->get('bar') === $builder->get('foo'), '->setAlias() creates a service that is an alias to another one');

try {
Expand Down Expand Up @@ -244,6 +289,9 @@ public function testSetReplacesAlias()
$builder->set('aliased', new \stdClass());

$builder->set('alias', $foo = new \stdClass());

$builder->compile();

$this->assertSame($foo, $builder->get('alias'), '->set() replaces an existing alias');
}

Expand All @@ -261,9 +309,12 @@ public function testCreateService()
{
$builder = new ContainerBuilder();
$builder->register('foo1', 'Bar\FooClass')->setFile(__DIR__.'/Fixtures/includes/foo.php');
$this->assertInstanceOf('\Bar\FooClass', $builder->get('foo1'), '->createService() requires the file defined by the service definition');
$builder->register('foo2', 'Bar\FooClass')->setFile(__DIR__.'/Fixtures/includes/%file%.php');
$builder->setParameter('file', 'foo');

$builder->compile();

$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');
}

Expand All @@ -274,6 +325,8 @@ public function testCreateProxyWithRealServiceInstantiator()
$builder->register('foo1', 'Bar\FooClass')->setFile(__DIR__.'/Fixtures/includes/foo.php');
$builder->getDefinition('foo1')->setLazy(true);

$builder->compile();

$foo1 = $builder->get('foo1');

$this->assertSame($foo1, $builder->get('foo1'), 'The same proxy is retrieved on multiple subsequent calls');
Expand All @@ -285,6 +338,9 @@ public function testCreateServiceClass()
$builder = new ContainerBuilder();
$builder->register('foo1', '%class%');
$builder->setParameter('class', 'stdClass');

$builder->compile();

$this->assertInstanceOf('\stdClass', $builder->get('foo1'), '->createService() replaces parameters in the class provided by the service definition');
}

Expand All @@ -294,6 +350,9 @@ public function testCreateServiceArguments()
$builder->register('bar', 'stdClass');
$builder->register('foo1', 'Bar\FooClass')->addArgument(array('foo' => '%value%', '%value%' => 'foo', new Reference('bar'), '%%unescape_it%%'));
$builder->setParameter('value', 'bar');

$builder->compile();

$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');
}

Expand All @@ -305,6 +364,8 @@ public function testCreateServiceFactory()
$builder->register('bar', 'Bar\FooClass')->setFactory(array(new Definition('Bar\FooClass'), 'getInstance'));
$builder->register('baz', 'Bar\FooClass')->setFactory(array(new Reference('bar'), 'getInstance'));

$builder->compile();

$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');
Expand All @@ -317,6 +378,9 @@ public function testCreateServiceMethodCalls()
$builder->register('bar', 'stdClass');
$builder->register('foo1', 'Bar\FooClass')->addMethodCall('setBar', array(array('%value%', new Reference('bar'))));
$builder->setParameter('value', 'bar');

$builder->compile();

$this->assertEquals(array('bar', $builder->get('bar')), $builder->get('foo1')->bar, '->createService() replaces the values in the method calls arguments');
}

Expand All @@ -326,6 +390,9 @@ public function testCreateServiceMethodCallsWithEscapedParam()
$builder->register('bar', 'stdClass');
$builder->register('foo1', 'Bar\FooClass')->addMethodCall('setBar', array(array('%%unescape_it%%')));
$builder->setParameter('value', 'bar');

$builder->compile();

$this->assertEquals(array('%unescape_it%'), $builder->get('foo1')->bar, '->createService() replaces the values in the method calls arguments');
}

Expand All @@ -335,27 +402,30 @@ public function testCreateServiceProperties()
$builder->register('bar', 'stdClass');
$builder->register('foo1', 'Bar\FooClass')->setProperty('bar', array('%value%', new Reference('bar'), '%%unescape_it%%'));
$builder->setParameter('value', 'bar');

$builder->compile();

$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');
$this->assertTrue($builder->get('foo1')->configured, '->createService() calls the configurator');

$builder->register('foo2', 'Bar\FooClass')->setConfigurator(array('%class%', 'configureStatic'));
$builder->setParameter('class', 'BazClass');
$this->assertTrue($builder->get('foo2')->configured, '->createService() calls the configurator');

$builder->register('baz', 'BazClass');
$builder->register('foo3', 'Bar\FooClass')->setConfigurator(array(new Reference('baz'), 'configure'));
$this->assertTrue($builder->get('foo3')->configured, '->createService() calls the configurator');

$builder->register('foo4', 'Bar\FooClass')->setConfigurator(array($builder->getDefinition('baz'), 'configure'));
$builder->register('foo5', 'Bar\FooClass')->setConfigurator('foo');

$builder->compile();

$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');

$builder->register('foo5', 'Bar\FooClass')->setConfigurator('foo');
try {
$builder->get('foo5');
$this->fail('->createService() throws an InvalidArgumentException if the configure callable is not a valid callable');
Expand All @@ -371,6 +441,9 @@ public function testCreateSyntheticService()
{
$builder = new ContainerBuilder();
$builder->register('foo', 'Bar\FooClass')->setSynthetic(true);

$builder->compile();

$builder->get('foo');
}

Expand All @@ -380,13 +453,18 @@ public function testCreateServiceWithExpression()
$builder->setParameter('bar', 'bar');
$builder->register('bar', 'BarClass');
$builder->register('foo', 'Bar\FooClass')->addArgument(array('foo' => new Expression('service("bar").foo ~ parameter("bar")')));

$builder->compile();

$this->assertEquals('foobar', $builder->get('foo')->arguments['foo']);
}

public function testResolveServices()
{
$builder = new ContainerBuilder();
$builder->register('foo', 'Bar\FooClass');
$builder->compile();

$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');
Expand Down
0