feature #35995 [FrameworkBundle] add --deprecations on debug:container command (Simperfit, noemi-salaun)
This PR was merged into the 5.1-dev branch. Discussion ---------- [FrameworkBundle] add --deprecations on debug:container command | Q | A | ------------- | --- | Branch? | master (5.1) | Bug fix? | no | New feature? | yes <!-- please update src/**/CHANGELOG.md files --> | Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Tickets | #30089 <!-- prefix each issue number with "Fix #", if any --> | License | MIT | Doc PR | todo _I apologize in advance, I am not fluent in English_ Continuity of @Simperfit work from his PR https://github.com/symfony/symfony/pull/32584 I added support for XML, JSON and markdown formats as well as unit tests for all formats. ## XML format ```xml <?xml version="1.0" encoding="UTF-8"?> <deprecations remainingCount="5"> <deprecation count="3"> <message>Some deprecation message.</message> <file>/path/to/some/file.php</file> <line>39</line> </deprecation> <deprecation count="2"> <message>An other deprecation message.</message> <file>/path/to/an/other/file.php</file> <line>25</line> </deprecation> </deprecations> ``` ## JSON format ```json { "remainingCount": 5, "deprecations": [ { "message": "Some deprecation message.", "file": "\/path\/to\/some\/file.php", "line": 39, "count": 3 }, { "message": "An other deprecation message.", "file": "\/path\/to\/an\/other\/file.php", "line": 25, "count": 2 } ] } ``` ## Markdown format ## Remaining deprecations (5) - 3x: "Some deprecation message." in /path/to/some/file.php:39 - 2x: "An other deprecation message." in /path/to/an/other/file.php:25 I added a new commit on top of @Simperfit 's one, but I don't know how you would like to have the git history writed. Commits -------ee6391eb29
[FrameworkBundle] add all formats support for debug:container --deprecations command161f659146
[FrameworkBundle] add --deprecations on debug:container command
This commit is contained in:
commit
d028a503e6
@ -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` option to see compile-time deprecations.
|
||||
|
||||
5.0.0
|
||||
-----
|
||||
|
@ -62,6 +62,7 @@ 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, 'Displays deprecations generated when compiling and warming up the container'),
|
||||
])
|
||||
->setDescription('Displays current services for an application')
|
||||
->setHelp(<<<'EOF'
|
||||
@ -69,6 +70,10 @@ The <info>%command.name%</info> command displays all configured <comment>public<
|
||||
|
||||
<info>php %command.full_name%</info>
|
||||
|
||||
To see deprecations generated during container compilation and cache warmup, use the <info>--deprecations</info> option:
|
||||
|
||||
<info>php %command.full_name% --deprecations</info>
|
||||
|
||||
To get specific information about a service, specify its name:
|
||||
|
||||
<info>php %command.full_name% validator</info>
|
||||
@ -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 = [];
|
||||
}
|
||||
@ -180,7 +187,7 @@ EOF
|
||||
$errorIo->comment('To search for a specific tag, re-run this command with a search term. (e.g. <comment>debug:container --tag=form.type</comment>)');
|
||||
} elseif ($input->getOption('parameters')) {
|
||||
$errorIo->comment('To search for a specific parameter, re-run this command with a search term. (e.g. <comment>debug:container --parameter=kernel.debug</comment>)');
|
||||
} else {
|
||||
} elseif (!$input->getOption('deprecations')) {
|
||||
$errorIo->comment('To search for a specific service, re-run this command with a search term. (e.g. <comment>debug:container log</comment>)');
|
||||
}
|
||||
}
|
||||
|
@ -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 = []): void;
|
||||
|
||||
abstract protected function describeContainerDefinition(Definition $definition, array $options = []);
|
||||
|
||||
abstract protected function describeContainerAlias(Alias $alias, array $options = [], ContainerBuilder $builder = null);
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Bundle\FrameworkBundle\Console\Descriptor;
|
||||
|
||||
use Symfony\Component\Console\Exception\LogicException;
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
@ -154,6 +155,30 @@ 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
|
||||
{
|
||||
$containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $builder->getParameter('kernel.cache_dir'), $builder->getParameter('kernel.container_class'));
|
||||
if (!file_exists($containerDeprecationFilePath)) {
|
||||
throw new RuntimeException('The deprecation file does not exist, please try warming the cache first.');
|
||||
}
|
||||
|
||||
$logs = unserialize(file_get_contents($containerDeprecationFilePath));
|
||||
|
||||
$formattedLogs = [];
|
||||
$remainingCount = 0;
|
||||
foreach ($logs as $log) {
|
||||
$formattedLogs[] = [
|
||||
'message' => $log['message'],
|
||||
'file' => $log['file'],
|
||||
'line' => $log['line'],
|
||||
'count' => $log['count'],
|
||||
];
|
||||
$remainingCount += $log['count'];
|
||||
}
|
||||
|
||||
$this->writeData(['remainingCount' => $remainingCount, 'deprecations' => $formattedLogs], $options);
|
||||
}
|
||||
|
||||
private function writeData(array $data, array $options)
|
||||
{
|
||||
$flags = isset($options['json_encoding']) ? $options['json_encoding'] : 0;
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Bundle\FrameworkBundle\Console\Descriptor;
|
||||
|
||||
use Symfony\Component\Console\Exception\LogicException;
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
@ -104,6 +105,33 @@ class MarkdownDescriptor extends Descriptor
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
throw new RuntimeException('The deprecation file does not exist, please try warming the cache first.');
|
||||
}
|
||||
|
||||
$logs = unserialize(file_get_contents($containerDeprecationFilePath));
|
||||
if (0 === \count($logs)) {
|
||||
$this->write("## There are no deprecations in the logs!\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$formattedLogs = [];
|
||||
$remainingCount = 0;
|
||||
foreach ($logs as $log) {
|
||||
$formattedLogs[] = sprintf("- %sx: \"%s\" in %s:%s\n", $log['count'], $log['message'], $log['file'], $log['line']);
|
||||
$remainingCount += $log['count'];
|
||||
}
|
||||
|
||||
$this->write(sprintf("## Remaining deprecations (%s)\n\n", $remainingCount));
|
||||
foreach ($formattedLogs as $formattedLog) {
|
||||
$this->write($formattedLog);
|
||||
}
|
||||
}
|
||||
|
||||
protected function describeContainerServices(ContainerBuilder $builder, array $options = [])
|
||||
{
|
||||
$showHidden = isset($options['show_hidden']) && $options['show_hidden'];
|
||||
|
@ -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()) {
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Bundle\FrameworkBundle\Console\Descriptor;
|
||||
|
||||
use Symfony\Component\Console\Exception\LogicException;
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
@ -106,6 +107,34 @@ 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
|
||||
{
|
||||
$containerDeprecationFilePath = sprintf('%s/%sDeprecations.log', $builder->getParameter('kernel.cache_dir'), $builder->getParameter('kernel.container_class'));
|
||||
if (!file_exists($containerDeprecationFilePath)) {
|
||||
throw new RuntimeException('The deprecation file does not exist, please try warming the cache first.');
|
||||
}
|
||||
|
||||
$logs = unserialize(file_get_contents($containerDeprecationFilePath));
|
||||
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->appendChild($deprecationsXML = $dom->createElement('deprecations'));
|
||||
|
||||
$formattedLogs = [];
|
||||
$remainingCount = 0;
|
||||
foreach ($logs as $log) {
|
||||
$deprecationsXML->appendChild($deprecationXML = $dom->createElement('deprecation'));
|
||||
$deprecationXML->setAttribute('count', $log['count']);
|
||||
$deprecationXML->appendChild($dom->createElement('message', $log['message']));
|
||||
$deprecationXML->appendChild($dom->createElement('file', $log['file']));
|
||||
$deprecationXML->appendChild($dom->createElement('line', $log['line']));
|
||||
$remainingCount += $log['count'];
|
||||
}
|
||||
|
||||
$deprecationsXML->setAttribute('remainingCount', $remainingCount);
|
||||
|
||||
$this->writeDocument($dom);
|
||||
}
|
||||
|
||||
private function writeDocument(\DOMDocument $dom)
|
||||
{
|
||||
$dom->formatOutput = true;
|
||||
|
@ -211,6 +211,19 @@ abstract class AbstractDescriptorTest extends TestCase
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getDeprecationsTestData
|
||||
*/
|
||||
public function testGetDeprecations(ContainerBuilder $builder, $expectedDescription)
|
||||
{
|
||||
$this->assertDescription($expectedDescription, $builder, ['deprecations' => true]);
|
||||
}
|
||||
|
||||
public function getDeprecationsTestData()
|
||||
{
|
||||
return $this->getDescriptionTestData(ObjectsProvider::getContainerDeprecations());
|
||||
}
|
||||
|
||||
abstract protected function getDescriptor();
|
||||
|
||||
abstract protected function getFormat();
|
||||
|
@ -88,6 +88,22 @@ class ObjectsProvider
|
||||
];
|
||||
}
|
||||
|
||||
public static function getContainerDeprecations()
|
||||
{
|
||||
$builderWithDeprecations = new ContainerBuilder();
|
||||
$builderWithDeprecations->setParameter('kernel.cache_dir', __DIR__.'/../../Fixtures/Descriptor/cache');
|
||||
$builderWithDeprecations->setParameter('kernel.container_class', 'KernelContainerWith');
|
||||
|
||||
$builderWithoutDeprecations = new ContainerBuilder();
|
||||
$builderWithoutDeprecations->setParameter('kernel.cache_dir', __DIR__.'/../../Fixtures/Descriptor/cache');
|
||||
$builderWithoutDeprecations->setParameter('kernel.container_class', 'KernelContainerWithout');
|
||||
|
||||
return [
|
||||
'deprecations' => $builderWithDeprecations,
|
||||
'deprecations_empty' => $builderWithoutDeprecations,
|
||||
];
|
||||
}
|
||||
|
||||
public static function getContainerBuilders()
|
||||
{
|
||||
$builder1 = new ContainerBuilder();
|
||||
|
@ -0,0 +1 @@
|
||||
a:2:{i:0;a:6:{s:4:"type";i:16384;s:7:"message";s:25:"Some deprecation message.";s:4:"file";s:22:"/path/to/some/file.php";s:4:"line";i:39;s:5:"trace";a:0:{}s:5:"count";i:3;}i:1;a:6:{s:4:"type";i:16384;s:7:"message";s:29:"An other deprecation message.";s:4:"file";s:26:"/path/to/an/other/file.php";s:4:"line";i:25;s:5:"trace";a:0:{}s:5:"count";i:2;}}
|
@ -0,0 +1 @@
|
||||
a:0:{}
|
@ -0,0 +1,17 @@
|
||||
{
|
||||
"remainingCount": 5,
|
||||
"deprecations": [
|
||||
{
|
||||
"message": "Some deprecation message.",
|
||||
"file": "\/path\/to\/some\/file.php",
|
||||
"line": 39,
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"message": "An other deprecation message.",
|
||||
"file": "\/path\/to\/an\/other\/file.php",
|
||||
"line": 25,
|
||||
"count": 2
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
## Remaining deprecations (5)
|
||||
|
||||
- 3x: "Some deprecation message." in /path/to/some/file.php:39
|
||||
- 2x: "An other deprecation message." in /path/to/an/other/file.php:25
|
@ -0,0 +1,9 @@
|
||||
|
||||
[33mRemaining deprecations (5)[39m
|
||||
[33m==========================[39m
|
||||
|
||||
* 3x: Some deprecation message.
|
||||
in /path/to/some/file.php:39
|
||||
* 2x: An other deprecation message.
|
||||
in /path/to/an/other/file.php:25
|
||||
|
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<deprecations remainingCount="5">
|
||||
<deprecation count="3">
|
||||
<message>Some deprecation message.</message>
|
||||
<file>/path/to/some/file.php</file>
|
||||
<line>39</line>
|
||||
</deprecation>
|
||||
<deprecation count="2">
|
||||
<message>An other deprecation message.</message>
|
||||
<file>/path/to/an/other/file.php</file>
|
||||
<line>25</line>
|
||||
</deprecation>
|
||||
</deprecations>
|
@ -0,0 +1,4 @@
|
||||
{
|
||||
"remainingCount": 0,
|
||||
"deprecations": []
|
||||
}
|
@ -0,0 +1 @@
|
||||
## There are no deprecations in the logs!
|
@ -0,0 +1,5 @@
|
||||
|
||||
[30;42m [39;49m
|
||||
[30;42m [OK] There are no deprecations in the logs! [39;49m
|
||||
[30;42m [39;49m
|
||||
|
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<deprecations remainingCount="0"/>
|
@ -136,6 +136,73 @@ 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->assertStringContainsString('Symfony\Bundle\FrameworkBundle\Controller\Controller', $tester->getDisplay());
|
||||
$this->assertStringContainsString('/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->assertStringContainsString('[OK] There are no deprecations in the logs!', $tester->getDisplay());
|
||||
}
|
||||
|
||||
public function testGetDeprecationNoFile()
|
||||
{
|
||||
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->assertStringContainsString('[WARNING] The deprecation file does not exist', $tester->getDisplay());
|
||||
}
|
||||
|
||||
public function provideIgnoreBackslashWhenFindingService()
|
||||
{
|
||||
return [
|
||||
|
Reference in New Issue
Block a user