diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
index 79086dbbb8..5a6e3cd425 100644
--- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
+++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
@@ -13,6 +13,7 @@ CHANGELOG
* The `TemplateController` now accepts context argument
* Deprecated *not* setting the "framework.router.utf8" configuration option as it will default to `true` in Symfony 6.0
* Added tag `routing.expression_language_function` to define functions available in route conditions
+ * Added `debug:container --deprecations` command to see compile-time deprecations.
5.0.0
-----
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php
index 50a8b821f4..43945d3555 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php
@@ -62,12 +62,17 @@ class ContainerDebugCommand extends Command
new InputOption('env-vars', null, InputOption::VALUE_NONE, 'Displays environment variables used in the container'),
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw description'),
+ new InputOption('deprecations', null, InputOption::VALUE_NONE, 'To output the deprecations generated when compiling and warming the cache'),
])
->setDescription('Displays current services for an application')
->setHelp(<<<'EOF'
The %command.name% command displays all configured public services:
php %command.full_name%
+
+To see deprecations generated during container compilation and cache warmup, use the --deprecations flag:
+
+ php %command.full_name% --deprecations
To get specific information about a service, specify its name:
@@ -149,6 +154,8 @@ EOF
} elseif ($name = $input->getArgument('name')) {
$name = $this->findProperServiceName($input, $errorIo, $object, $name, $input->getOption('show-hidden'));
$options = ['id' => $name];
+ } elseif ($input->getOption('deprecations')) {
+ $options = ['deprecations' => true];
} else {
$options = [];
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php
index fb89768bf5..a1794c350c 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php
@@ -64,6 +64,9 @@ abstract class Descriptor implements DescriptorInterface
case $object instanceof ContainerBuilder && isset($options['parameter']):
$this->describeContainerParameter($object->resolveEnvPlaceholders($object->getParameter($options['parameter'])), $options);
break;
+ case $object instanceof ContainerBuilder && isset($options['deprecations']):
+ $this->describeContainerDeprecations($object, $options);
+ break;
case $object instanceof ContainerBuilder:
$this->describeContainerServices($object, $options);
break;
@@ -120,6 +123,8 @@ abstract class Descriptor implements DescriptorInterface
*/
abstract protected function describeContainerServices(ContainerBuilder $builder, array $options = []);
+ abstract protected function describeContainerDeprecations(ContainerBuilder $builder, array $options = []);
+
abstract protected function describeContainerDefinition(Definition $definition, array $options = []);
abstract protected function describeContainerAlias(Alias $alias, array $options = [], ContainerBuilder $builder = null);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php
index b9e5bad0f5..84697e7c91 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php
@@ -154,6 +154,11 @@ class JsonDescriptor extends Descriptor
throw new LogicException('Using the JSON format to debug environment variables is not supported.');
}
+ protected function describeContainerDeprecations(ContainerBuilder $builder, array $options = []): void
+ {
+ throw new LogicException('Using the JSON format to print the deprecations is not supported.');
+ }
+
private function writeData(array $data, array $options)
{
$flags = isset($options['json_encoding']) ? $options['json_encoding'] : 0;
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php
index a04402796b..33bf650e2b 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php
@@ -104,6 +104,11 @@ class MarkdownDescriptor extends Descriptor
}
}
+ protected function describeContainerDeprecations(ContainerBuilder $builder, array $options = []): void
+ {
+ throw new LogicException('Using the Markdown format to print the deprecations is not supported.');
+ }
+
protected function describeContainerServices(ContainerBuilder $builder, array $options = [])
{
$showHidden = isset($options['show_hidden']) && $options['show_hidden'];
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php
index 45c995a467..ddcaaa0336 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php
@@ -353,6 +353,32 @@ class TextDescriptor extends Descriptor
$options['output']->table($tableHeaders, $tableRows);
}
+ protected function describeContainerDeprecations(ContainerBuilder $builder, array $options = []): void
+ {
+ $containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $builder->getParameter('kernel.cache_dir'), $builder->getParameter('kernel.container_class'));
+ if (!file_exists($containerDeprecationFilePath)) {
+ $options['output']->warning('The deprecation file does not exist, please try warming the cache first.');
+
+ return;
+ }
+
+ $logs = unserialize(file_get_contents($containerDeprecationFilePath));
+ if (0 === \count($logs)) {
+ $options['output']->success('There are no deprecations in the logs!');
+
+ return;
+ }
+
+ $formattedLogs = [];
+ $remainingCount = 0;
+ foreach ($logs as $log) {
+ $formattedLogs[] = sprintf("%sx: %s \n in %s:%s", $log['count'], $log['message'], $log['file'], $log['line']);
+ $remainingCount += $log['count'];
+ }
+ $options['output']->title(sprintf('Remaining deprecations (%s)', $remainingCount));
+ $options['output']->listing($formattedLogs);
+ }
+
protected function describeContainerAlias(Alias $alias, array $options = [], ContainerBuilder $builder = null)
{
if ($alias->isPublic()) {
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php
index a7f348e76d..3e6708ce86 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php
@@ -106,6 +106,11 @@ class XmlDescriptor extends Descriptor
throw new LogicException('Using the XML format to debug environment variables is not supported.');
}
+ protected function describeContainerDeprecations(ContainerBuilder $builder, array $options = []): void
+ {
+ throw new LogicException('Using the XML format to print the deprecations is not supported.');
+ }
+
private function writeDocument(\DOMDocument $dom)
{
$dom->formatOutput = true;
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php
index 537ee77174..f4e199da89 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php
@@ -136,6 +136,88 @@ TXT
$this->assertStringContainsString(file_get_contents(__DIR__.'/Fixtures/describe_env_vars.txt'), $tester->getDisplay(true));
}
+ public function testGetDeprecation()
+ {
+ static::bootKernel(['test_case' => 'ContainerDebug', 'root_config' => 'config.yml', 'debug' => true]);
+ $path = sprintf('%s/%sDeprecations.log', static::$kernel->getContainer()->getParameter('kernel.cache_dir'), static::$kernel->getContainer()->getParameter('kernel.container_class'));
+ touch($path);
+ file_put_contents($path, serialize([[
+ 'type' => 16384,
+ 'message' => 'The "Symfony\Bundle\FrameworkBundle\Controller\Controller" class is deprecated since Symfony 4.2, use Symfony\Bundle\FrameworkBundle\Controller\AbstractController instead.',
+ 'file' => '/home/hamza/projet/contrib/sf/vendor/symfony/framework-bundle/Controller/Controller.php',
+ 'line' => 17,
+ 'trace' => [[
+ 'file' => '/home/hamza/projet/contrib/sf/src/Controller/DefaultController.php',
+ 'line' => 9,
+ 'function' => 'spl_autoload_call',
+ ]],
+ 'count' => 1,
+ ]]));
+ $application = new Application(static::$kernel);
+ $application->setAutoExit(false);
+
+ @unlink(static::$container->getParameter('debug.container.dump'));
+
+ $tester = new ApplicationTester($application);
+ $tester->run(['command' => 'debug:container', '--deprecations' => true]);
+
+ $this->assertSame(0, $tester->getStatusCode());
+ $this->assertContains('Symfony\Bundle\FrameworkBundle\Controller\Controller', $tester->getDisplay());
+ $this->assertContains('/home/hamza/projet/contrib/sf/vendor/symfony/framework-bundle/Controller/Controller.php', $tester->getDisplay());
+ }
+
+ public function testGetDeprecationNone()
+ {
+ static::bootKernel(['test_case' => 'ContainerDebug', 'root_config' => 'config.yml', 'debug' => true]);
+ $path = sprintf('%s/%sDeprecations.log', static::$kernel->getContainer()->getParameter('kernel.cache_dir'), static::$kernel->getContainer()->getParameter('kernel.container_class'));
+ touch($path);
+ file_put_contents($path, serialize([]));
+
+ $application = new Application(static::$kernel);
+ $application->setAutoExit(false);
+
+ @unlink(static::$container->getParameter('debug.container.dump'));
+
+ $tester = new ApplicationTester($application);
+ $tester->run(['command' => 'debug:container', '--deprecations' => true]);
+
+ $this->assertSame(0, $tester->getStatusCode());
+ $this->assertContains('[OK] There are no deprecations in the logs!', $tester->getDisplay());
+ }
+
+ public function testGetDeprecationNoFile(): void
+ {
+ static::bootKernel(['test_case' => 'ContainerDebug', 'root_config' => 'config.yml', 'debug' => true]);
+ $path = sprintf('%s/%sDeprecations.log', static::$kernel->getContainer()->getParameter('kernel.cache_dir'), static::$kernel->getContainer()->getParameter('kernel.container_class'));
+ @unlink($path);
+
+ $application = new Application(static::$kernel);
+ $application->setAutoExit(false);
+
+ @unlink(static::$container->getParameter('debug.container.dump'));
+
+ $tester = new ApplicationTester($application);
+ $tester->run(['command' => 'debug:container', '--deprecations' => true]);
+
+ $this->assertSame(0, $tester->getStatusCode());
+ $this->assertContains('[WARNING] The deprecation file does not exist', $tester->getDisplay());
+ }
+
+ public function testGetDeprecationXml(): void
+ {
+ static::bootKernel(['test_case' => 'ContainerDebug', 'root_config' => 'config.yml', 'debug' => true]);
+ $application = new Application(static::$kernel);
+ $application->setAutoExit(false);
+
+ @unlink(static::$container->getParameter('debug.container.dump'));
+
+ $tester = new ApplicationTester($application);
+ $tester->run(['command' => 'debug:container', '--deprecations' => true, '--format' => 'xml']);
+
+ $this->assertSame(1, $tester->getStatusCode());
+ $this->assertContains('Using the XML format to print the deprecations is not supported.', $tester->getDisplay());
+ }
+
public function provideIgnoreBackslashWhenFindingService()
{
return [