8000 added logging of unused tags by fabpot · Pull Request #15963 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

added logging of unused tags #15963

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

Merged
merged 3 commits into from
Sep 28, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view 8000 the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
* Find all service tags which are defined, but not used and yield a warning log message.
*
* @author Florian Pfitzer <pfitzer@wurzel3.de>
*/
class UnusedTagsPass implements CompilerPassInterface
{
private $whitelist = array(
'console.command',
'config_cache.resource_checker',
'data_collector',
'form.type',
'form.type_extension',
'form.type_guesser',
'kernel.cache_clearer',
'kernel.cache_warmer',
'kernel.event_listener',
'kernel.event_subscriber',
'kernel.fragment_renderer',
'monolog.logger',
'routing.expression_language_provider',
'routing.loader',
'security.expression_language_provider',
'security.remember_me_aware',
'security.voter',
'serializer.encoder',
'serializer.normalizer',
'templating.helper',
'translation.dumper',
'translation.extractor',
'translation.loader',
'twig.extension',
'twig.loader',
'validator.constraint_validator',
'validator.initializer',
);

public function process(ContainerBuilder $container)
{
$compiler = $container->getCompiler();
$formatter = $compiler->getLoggingFormatter();
$tags = array_unique(array_merge($container->findTags(), $this->whitelist));

foreach ($container->findUnusedTags() as $tag) {
// skip whitelisted tags
if (in_array($tag, $this->whitelist)) {
continue;
}

// check for typos
$candidates = arra 10000 y();
foreach ($tags as $definedTag) {
if ($definedTag === $tag) {
continue;
}

if (false !== strpos($definedTag, $tag) || levenshtein($tag, $definedTag) <= strlen($tag) / 3) {
$candidates[] = $definedTag;
}
}

$services = array_keys($container->findTaggedServiceIds($tag));
$message = sprintf('Tag "%s" was defined on service(s) "%s", but was never used.', $tag, implode('", "', $services));
if (!empty($candidates)) {
$message .= sprintf(' Did you mean "%s"?', implode('", "', $candidates));
}

$compiler->addLogMessage($formatter->format($this, $message));
}
}
}
2 changes: 2 additions & 0 deletions src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslationExtractorPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslationDumperPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\SerializerPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\UnusedTagsPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ConfigCachePass;
use Symfony\Component\Debug\ErrorHandler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
Expand Down Expand Up @@ -91,6 +92,7 @@ public function build(ContainerBuilder $container)
$container->addCompilerPass(new SerializerPass());

if ($container->getParameter('kernel.debug')) {
$container->addCompilerPass(new UnusedTagsPass(), PassConfig::TYPE_AFTER_REMOVING);
$container->addCompilerPass(new ContainerBuilderDebugDumpPass(), PassConfig::TYPE_AFTER_REMOVING);
$container->addCompilerPass(new CompilerDebugDumpPass(), PassConfig::TYPE_AFTER_REMOVING);
$container->addCompilerPass(new ConfigCachePass());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler;

use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\UnusedTagsPass;

class UnusedTagsPassTest extends \PHPUnit_Framework_TestCase
{
public function testProcess()
{
$pass = new UnusedTagsPass();

$formatter = $this->getMock('Symfony\Component\DependencyInjection\Compiler\LoggingFormatter');
$formatter
->expects($this->at(0))
->method('format')
->with($pass, 'Tag "kenrel.event_subscriber" was defined on service(s) "foo", "bar", but was never used. Did you mean "kernel.event_subscriber"?')
;

$compiler = $this->getMock('Symfony\Component\DependencyInjection\Compiler\Compiler');
$compiler->expects($this->once())->method('getLoggingFormatter')->will($this->returnValue($formatter));

$container = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder',
array('findTaggedServiceIds', 'getCompiler', 'findUnusedTags', 'findTags')
);
$container->expects($this->once())->method('getCompiler')->will($this->returnValue($compiler));
$container->expects($this->once())
->method('findTags')
->will($this->returnValue(array('kenrel.event_subscriber')));
$container->expects($this->once())
->method('findUnusedTags')
->will($this->returnValue(array('kenrel.event_subscriber', 'form.type')));
$container->expects($this->once())
->method('findTaggedServiceIds')
->with('kenrel.event_subscriber')
->will($this->returnValue(array(
'foo' => array(),
'bar' => array(),
)));

$pass->process($container);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class LoggingFormatter
{
public function formatRemoveService(CompilerPassInterface $pass, $id, $reason)
{
return $this->format($pass, sprintf('Removed service "%s"; reason: %s', $id, $reason));
return $this->format($pass, sprintf('Removed service "%s"; reason: %s.', $id, $reason));
}

public function formatInlineService(CompilerPassInterface $pass, $id, $target)
Expand Down
16 changes: 16 additions & 0 deletions src/Symfony/Component/DependencyInjection/ContainerBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
*/
private $expressionLanguageProviders = array();

/**
* @var string[] with tag names used by findTaggedServiceIds
*/
private $usedTags = array();

/**
* Sets the track resources flag.
*
Expand Down Expand Up @@ -1064,6 +1069,7 @@ public function resolveServices($value)
*/
public function findTaggedServiceIds($name)
{
$this->usedTags[] = $name;
$tags = array();
foreach ($this->getDefinitions() as $id => $definition) {
if ($definition->hasTag($name)) {
Expand All @@ -1089,6 +1095,16 @@ public function findTags()
return array_unique($tags);
}

/**
* Returns all tags not queried by findTaggedServiceIds.
*
* @return string[] An array of tags
*/
public function findUnusedTags()
{
return array_values(array_diff($this->findTags(), $this->usedTags));
}

public function addExpressionLanguageProvider(ExpressionFunctionProviderInterface $provider)
{
$this->expressionLanguageProviders[] = $provider;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,18 @@ public function testfindTaggedServiceIds()
$this->assertEquals(array(), $builder->findTaggedServiceIds('foobar'), '->findTaggedServiceIds() returns an empty array if there is annotated services');
}

public function testFindUnusedTags()
{
$builder = new ContainerBuilder();
$builder
->register('foo', 'Bar\FooClass')
->addTag('kernel.event_listener', array('foo' => 'foo'))
->addTag('kenrel.event_listener', array('bar' => 'bar'))
;
$builder->findTaggedServiceIds('kernel.event_listener');
$this->assertEquals(array('kenrel.event_listener'), $builder->findUnusedTags(), '->findUnusedTags() returns an array with unused tags');
}

/**
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::findDefinition
*/
Expand Down
0