Skip to content

Commit

Permalink
feature #23712 [DependencyInjection] Deprecate autowiring service aut…
Browse files Browse the repository at this point in the history
…o-registration (GuilhemN)

This PR was squashed before being merged into the 3.4 branch (closes #23712).

Discussion
----------

[DependencyInjection] Deprecate autowiring service auto-registration

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | no
| New feature?  | no <!-- don't forget updating src/**/CHANGELOG.md files -->
| BC breaks?    | no
| Deprecations? | yes <!-- don't forget updating UPGRADE-*.md files -->
| Tests pass?   | yes
| Fixed tickets | #23350
| License       | MIT
| Doc PR        |

Fix #23350, to make autowiring more predictable.

Commits
-------

969a207 [DependencyInjection] Deprecate autowiring service auto-registration
  • Loading branch information
nicolas-grekas committed Aug 3, 2017
2 parents 4860b3e + 969a207 commit 2454a4f
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 19 deletions.
58 changes: 51 additions & 7 deletions UPGRADE-3.4.md
Expand Up @@ -4,6 +4,50 @@ UPGRADE FROM 3.3 to 3.4
DependencyInjection
-------------------

* Relying on service auto-registration while autowiring is deprecated and won't be supported
in Symfony 4.0. Explicitly inject your dependencies or create services
whose ids are their fully-qualified class name.

Before:

```php
namespace App\Controller;

use App\Mailer;

class DefaultController
{
public function __construct(Mailer $mailer) {
// ...
}

// ...
}
```
```yml
services:
App\Controller\DefaultController:
autowire: true
```

After:

```php
// same PHP code
```
```yml
services:
App\Controller\DefaultController:
autowire: true

# or
# App\Controller\DefaultController:
# arguments: { $mailer: "@App\Mailer" }

App\Mailer:
autowire: true
```

* Top-level anonymous services in XML are deprecated and will throw an exception in Symfony 4.0.

Debug
Expand Down Expand Up @@ -37,13 +81,13 @@ FrameworkBundle
require symfony/stopwatch` in your `dev` environment.

* Using the `KERNEL_DIR` environment variable or the automatic guessing based
on the `phpunit.xml` / `phpunit.xml.dist` file location is deprecated since 3.4.
on the `phpunit.xml` / `phpunit.xml.dist` file location is deprecated since 3.4.
Set the `KERNEL_CLASS` environment variable to the fully-qualified class name
of your Kernel instead. Not setting the `KERNEL_CLASS` environment variable
will throw an exception on 4.0 unless you override the `KernelTestCase::createKernel()`
of your Kernel instead. Not setting the `KERNEL_CLASS` environment variable
will throw an exception on 4.0 unless you override the `KernelTestCase::createKernel()`
or `KernelTestCase::getKernelClass()` method.
* The `KernelTestCase::getPhpUnitXmlDir()` and `KernelTestCase::getPhpUnitCliConfigArgument()`

* The `KernelTestCase::getPhpUnitXmlDir()` and `KernelTestCase::getPhpUnitCliConfigArgument()`
methods are deprecated since 3.4 and will be removed in 4.0.

* The `--no-prefix` option of the `translation:update` command is deprecated and
Expand Down Expand Up @@ -90,7 +134,7 @@ TwigBridge
* deprecated the `Symfony\Bridge\Twig\Form\TwigRenderer` class, use the `FormRenderer`
class from the Form component instead

* deprecated `Symfony\Bridge\Twig\Command\DebugCommand::set/getTwigEnvironment` and the ability
* deprecated `Symfony\Bridge\Twig\Command\DebugCommand::set/getTwigEnvironment` and the ability
to pass a command name as first argument

* deprecated `Symfony\Bridge\Twig\Command\LintCommand::set/getTwigEnvironment` and the ability
Expand All @@ -102,7 +146,7 @@ TwigBundle
* deprecated the `Symfony\Bundle\TwigBundle\Command\DebugCommand` class, use the `DebugCommand`
class from the Twig bridge instead

* deprecated relying on the `ContainerAwareInterface` implementation for
* deprecated relying on the `ContainerAwareInterface` implementation for
`Symfony\Bundle\TwigBundle\Command\LintCommand`

Validator
Expand Down
54 changes: 49 additions & 5 deletions UPGRADE-4.0.md
Expand Up @@ -77,6 +77,50 @@ Debug
DependencyInjection
-------------------

* Relying on service auto-registration while autowiring is not supported anymore.
Explicitly inject your dependencies or create services whose ids are
their fully-qualified class name.

Before:

```php
namespace App\Controller;

use App\Mailer;

class DefaultController
{
public function __construct(Mailer $mailer) {
// ...
}

// ...
}
```
```yml
services:
App\Controller\DefaultController:
autowire: true
```

After:

```php
// same PHP code
```
```yml
services:
App\Controller\DefaultController:
autowire: true

# or
# App\Controller\DefaultController:
# arguments: { $mailer: "@App\Mailer" }

App\Mailer:
autowire: true
```

* Autowiring services based on the types they implement is not supported anymore. Rename (or alias) your services to their FQCN id to make them autowirable.

* `_defaults` and `_instanceof` are now reserved service names in Yaml configurations. Please rename any services with that names.
Expand Down Expand Up @@ -345,9 +389,9 @@ FrameworkBundle
class instead.

* Using the `KERNEL_DIR` environment variable and the automatic guessing based
on the `phpunit.xml` file location have been removed from the `KernelTestCase::getKernelClass()`
on the `phpunit.xml` file location have been removed from the `KernelTestCase::getKernelClass()`
method implementation. Set the `KERNEL_CLASS` environment variable to the
fully-qualified class name of your Kernel or override the `KernelTestCase::createKernel()`
fully-qualified class name of your Kernel or override the `KernelTestCase::createKernel()`
or `KernelTestCase::getKernelClass()` method instead.

* The `Symfony\Bundle\FrameworkBundle\Validator\ConstraintValidatorFactory` class has been removed.
Expand All @@ -356,10 +400,10 @@ FrameworkBundle
* The `--no-prefix` option of the `translation:update` command has
been removed.

* The `Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddCacheClearerPass` class has been removed.
* The `Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddCacheClearerPass` class has been removed.
Use the `Symfony\Component\HttpKernel\DependencyInjection\AddCacheClearerPass` class instead.

* The `Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddCacheWarmerPass` class has been removed.
* The `Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddCacheWarmerPass` class has been removed.
Use the `Symfony\Component\HttpKernel\DependencyInjection\AddCacheWarmerPass` class instead.

* The `Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslationDumperPass`
Expand Down Expand Up @@ -561,7 +605,7 @@ TwigBridge
* The `TwigRendererEngine::setEnvironment()` method has been removed.
Pass the Twig Environment as second argument of the constructor instead.

* Removed `Symfony\Bridge\Twig\Command\DebugCommand::set/getTwigEnvironment` and the ability
* Removed `Symfony\Bridge\Twig\Command\DebugCommand::set/getTwigEnvironment` and the ability
to pass a command name as first argument.

* Removed `Symfony\Bridge\Twig\Command\LintCommand::set/getTwigEnvironment` and the ability
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Component/DependencyInjection/CHANGELOG.md
Expand Up @@ -4,6 +4,7 @@ CHANGELOG
3.4.0
-----

* deprecated service auto-registration while autowiring
* deprecated the ability to check for the initialization of a private service with the `Container::initialized()` method
* deprecated support for top-level anonymous services in XML

Expand Down
Expand Up @@ -477,6 +477,8 @@ private function createAutowiredDefinition($type)
$this->currentId = $currentId;
}

@trigger_error(sprintf('Relying on service auto-registration for type "%s" is deprecated since version 3.4 and won\'t be supported in 4.0. Create a service named "%s" instead.', $type, $type), E_USER_DEPRECATED);

$this->container->log($this, sprintf('Type "%s" has been auto-registered for service "%s".', $type, $this->currentId));

return new TypedReference($argumentId, $type);
Expand Down
Expand Up @@ -287,6 +287,11 @@ public function testWithTypeSet()
$this->assertEquals(CollisionInterface::class, (string) $container->getDefinition('a')->getArgument(0));
}

/**
* @group legacy
* @expectedDeprecation Relying on service auto-registration for type "Symfony\Component\DependencyInjection\Tests\Compiler\Lille" is deprecated since version 3.4 and won't be supported in 4.0. Create a service named "Symfony\Component\DependencyInjection\Tests\Compiler\Lille" instead.
* @expectedDeprecation Relying on service auto-registration for type "Symfony\Component\DependencyInjection\Tests\Compiler\Dunglas" is deprecated since version 3.4 and won't be supported in 4.0. Create a service named "Symfony\Component\DependencyInjection\Tests\Compiler\Dunglas" instead.
*/
public function testCreateDefinition()
{
$container = new ContainerBuilder();
Expand Down Expand Up @@ -368,6 +373,8 @@ public function testClassNotFoundThrowsException()
$aDefinition = $container->register('a', __NAMESPACE__.'\BadTypeHintedArgument');
$aDefinition->setAutowired(true);

$container->register(Dunglas::class, Dunglas::class);

$pass = new AutowirePass();
$pass->process($container);
}
Expand All @@ -383,6 +390,8 @@ public function testParentClassNotFoundThrowsException()
$aDefinition = $container->register('a', __NAMESPACE__.'\BadParentTypeHintedArgument');
$aDefinition->setAutowired(true);

$container->register(Dunglas::class, Dunglas::class);

$pass = new AutowirePass();
$pass->process($container);
}
Expand Down Expand Up @@ -595,6 +604,10 @@ public function testExplicitMethodInjection()
);
}

/**
* @group legacy
* @expectedDeprecation Relying on service auto-registration for type "Symfony\Component\DependencyInjection\Tests\Compiler\A" is deprecated since version 3.4 and won't be supported in 4.0. Create a service named "Symfony\Component\DependencyInjection\Tests\Compiler\A" instead.
*/
public function testTypedReference()
{
$container = new ContainerBuilder();
Expand Down Expand Up @@ -653,6 +666,8 @@ public function testIgnoreServiceWithClassNotExisting()
$barDefinition = $container->register('bar', __NAMESPACE__.'\Bar');
$barDefinition->setAutowired(true);

$container->register(Foo::class, Foo::class);

$pass = new AutowirePass();
$pass->process($container);

Expand Down
Expand Up @@ -28,6 +28,7 @@
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition;
use Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber;
use Symfony\Component\DependencyInjection\Variable;
use Symfony\Component\ExpressionLanguage\Expression;
Expand Down Expand Up @@ -560,6 +561,9 @@ public function testServiceSubscriber()
))
;
$container->register(TestServiceSubscriber::class, TestServiceSubscriber::class);

$container->register(CustomDefinition::class, CustomDefinition::class)
->setPublic(false);
$container->compile();

$dumper = new PhpDumper($container);
Expand Down
Expand Up @@ -28,16 +28,16 @@ public function __construct()
{
$this->services = array();
$this->normalizedIds = array(
'autowired.symfony\\component\\dependencyinjection\\tests\\fixtures\\customdefinition' => 'autowired.Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition',
'symfony\\component\\dependencyinjection\\tests\\fixtures\\customdefinition' => 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition',
'symfony\\component\\dependencyinjection\\tests\\fixtures\\testservicesubscriber' => 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber',
);
$this->methodMap = array(
'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition' => 'getCustomDefinitionService',
'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber' => 'getTestServiceSubscriberService',
'autowired.Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition' => 'getCustomDefinitionService',
'foo_service' => 'getFooServiceService',
);
$this->privates = array(
'autowired.Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition' => true,
'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition' => true,
);

$this->aliases = array();
Expand Down Expand Up @@ -87,23 +87,23 @@ protected function getTestServiceSubscriberService()
protected function getFooServiceService()
{
return $this->services['foo_service'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber(new \Symfony\Component\DependencyInjection\ServiceLocator(array('Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition' => function () {
$f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition $v) { return $v; }; return $f(${($_ = isset($this->services['autowired.Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition']) ? $this->services['autowired.Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] : $this->getCustomDefinitionService()) && false ?: '_'});
$f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition $v = null) { return $v; }; return $f(${($_ = isset($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition']) ? $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] : $this->getCustomDefinitionService()) && false ?: '_'});
}, 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber' => function () {
$f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber $v) { return $v; }; return $f(${($_ = isset($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber']) ? $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber'] : $this->get('Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber')) && false ?: '_'});
}, 'bar' => function () {
$f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition $v) { return $v; }; return $f(${($_ = isset($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber']) ? $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber'] : $this->get('Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber')) && false ?: '_'});
}, 'baz' => function () {
$f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition $v) { return $v; }; return $f(${($_ = isset($this->services['autowired.Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition']) ? $this->services['autowired.Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] : $this->getCustomDefinitionService()) && false ?: '_'});
$f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition $v = null) { return $v; }; return $f(${($_ = isset($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition']) ? $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] : $this->getCustomDefinitionService()) && false ?: '_'});
})));
}

/**
* Gets the private 'autowired.Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition' shared autowired service.
* Gets the private 'Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition' shared service.
*
* @return \Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition
*/
protected function getCustomDefinitionService()
{
return $this->services['autowired.Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition();
return $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition();
}
}

0 comments on commit 2454a4f

Please sign in to comment.