diff --git a/UPGRADE-3.4.md b/UPGRADE-3.4.md index 1619ec95adf0..970ae230a60e 100644 --- a/UPGRADE-3.4.md +++ b/UPGRADE-3.4.md @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/UPGRADE-4.0.md b/UPGRADE-4.0.md index aabaed1c3c18..1c6fd928af22 100644 --- a/UPGRADE-4.0.md +++ b/UPGRADE-4.0.md @@ -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. @@ -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. @@ -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` @@ -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 diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index 3037dad65cc5..1fc26be27ea1 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -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 diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index a59444fcac37..8cb1978ef675 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -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); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php index 757db3f229c9..94666df60839 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php @@ -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(); @@ -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); } @@ -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); } @@ -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(); @@ -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); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index 6e7889725ec0..4afb445c68ca 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -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; @@ -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); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php index f5d94836dd1d..0f87da56175d 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php @@ -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(); @@ -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(); } }