Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit dffc922

Browse files
committed
Drastically improved debug:autowiring + new autowiring info system
This introduces a new interface + tag that can be used by bundles to inform the core about the *purpose* of the autowirable classes/interfaces. This is makes debug:autowiring human-focused: showing you a list of the autowireable services based on the *purpose* of them.
1 parent 7f8e215 commit dffc922

File tree

17 files changed

+556
-7
lines changed

17 files changed

+556
-7
lines changed

src/Symfony/Bundle/FrameworkBundle/Command/DebugAutowiringCommand.php

Lines changed: 86 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
use Symfony\Component\Console\Input\InputInterface;
1616
use Symfony\Component\Console\Output\OutputInterface;
1717
use Symfony\Component\Console\Style\SymfonyStyle;
18+
use Symfony\Component\DependencyInjection\Debug\AutowiringInfoManager;
19+
use Symfony\Component\DependencyInjection\Debug\AutowiringTypeInfo;
1820

1921
/**
2022
* A console command for autowiring information.
@@ -27,6 +29,15 @@ class DebugAutowiringCommand extends ContainerDebugCommand
2729
{
2830
protected static $defaultName = 'debug:autowiring';
2931

32+
private $autowiringInfoManager;
33+
34+
public function __construct(AutowiringInfoManager $autowiringInfoManager = null)
35+
{
36+
$this->autowiringInfoManager = $autowiringInfoManager;
37+
38+
parent::__construct();
39+
}
40+
3041
/**
3142
* {@inheritdoc}
3243
*/
@@ -78,24 +89,92 @@ protected function execute(InputInterface $input, OutputInterface $output)
7889

7990
asort($serviceIds);
8091

81-
$io->title('Autowirable Services');
8292
$io->text('The following classes & interfaces can be used as type-hints when autowiring:');
8393
if ($search) {
8494
$io->text(sprintf('(only showing classes/interfaces matching <comment>%s</comment>)', $search));
8595
}
8696
$io->newLine();
87-
$tableRows = array();
97+
98+
$keyServices = array();
99+
$otherServices = array();
88100
$hasAlias = array();
89101
foreach ($serviceIds as $serviceId) {
102+
if (null !== $this->autowiringInfoManager && $autowiringInfo = $this->autowiringInfoManager->getInfo($serviceId)) {
103+
$keyServices[] = array(
104+
'info' => $autowiringInfo,
105+
'alias' => $builder->has($serviceId) ? $builder->getAlias($serviceId) : null,
106+
);
107+
108+
continue;
109+
}
110+
90111
if ($builder->hasAlias($serviceId)) {
91-
$tableRows[] = array(sprintf('<fg=cyan>%s</fg=cyan>', $serviceId));
92-
$tableRows[] = array(sprintf(' alias to %s', $builder->getAlias($serviceId)));
93112
$hasAlias[(string) $builder->getAlias($serviceId)] = true;
94-
} else {
95-
$tableRows[$serviceId] = array(sprintf('<fg=cyan>%s</fg=cyan>', $serviceId));
96113
}
114+
115+
$otherServices[$serviceId] = array(
116+
'type' => $serviceId,
117+
'alias' => $builder->hasAlias($serviceId) ? $builder->getAlias($serviceId) : null,
118+
);
97119
}
120+
$otherServices = array_diff_key($otherServices, $hasAlias);
121+
122+
usort($keyServices, function ($a, $b) {
123+
if ($a['info']->getPriority() === $b['info']->getPriority()) {
124+
return 0;
125+
}
126+
127+
return $a['info']->getPriority() > $b['info']->getPriority() ? -1 : 1;
128+
});
129+
130+
$this->printKeyServices($keyServices, $io);
98131

99-
$io->table(array(), array_diff_key($tableRows, $hasAlias));
132+
$this->printOtherServices($otherServices, $io);
133+
}
134+
135+
private function printOtherServices(array $otherServices, SymfonyStyle $io)
136+
{
137+
if (empty($otherServices)) {
138+
return;
139+
}
140+
141+
// not necessary to print if this is the only list
142+
if (null !== $this->autowiringInfoManager) {
143+
$io->title('Other Services');
144+
}
145+
146+
foreach ($otherServices as $serviceData) {
147+
$io->writeln(sprintf('<fg=cyan>%s</fg=cyan>', $serviceData['type']));
148+
if ($alias = $serviceData['alias']) {
149+
$io->writeln(sprintf(' alias to %s', $alias));
150+
}
151+
}
152+
}
153+
154+
private function printKeyServices(array $keyServices, SymfonyStyle $io)
155+
{
156+
if (empty($keyServices)) {
157+
return;
158+
}
159+
160+
$io->title('Key Services');
161+
foreach ($keyServices as $serviceData) {
162+
/** @var AutowiringTypeInfo $info */
163+
$info = $serviceData['info'];
164+
165+
$nameLine = sprintf('<comment>%s</comment>', $info->getName());
166+
if ($info->getDescription()) {
167+
$nameLine .= sprintf(' (%s)', $info->getDescription());
168+
}
169+
$io->writeln($nameLine);
170+
171+
$io->writeln(sprintf(' Type: <fg=cyan>%s</fg=cyan>', $info->getType()));
172+
173+
if ($serviceData['alias']) {
174+
$io->writeln(sprintf(' Alias to the %s service', $serviceData['alias']));
175+
}
176+
177+
$io->writeln('');
178+
}
100179
}
101180
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler;
13+
14+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
15+
use Symfony\Component\DependencyInjection\ContainerBuilder;
16+
use Symfony\Component\DependencyInjection\Reference;
17+
18+
/**
19+
* Looks for & processes debug.autowiring_info_provider tags.
20+
*
21+
* @author Ryan Weaver <[email protected]>
22+
*/
23+
class AutowireDebugInfoPass implements CompilerPassInterface
24+
{
25+
const AUTOWIRING_INFO_PROVIDER_TAG = 'debug.autowiring_info_provider';
26+
27+
public function process(ContainerBuilder $container)
28+
{
29+
if (false === $container->hasDefinition('debug.autowiring_info_manager')) {
30+
return;
31+
}
32+
33+
$definition = $container->getDefinition('debug.autowiring_info_manager');
34+
35+
$references = array();
36+
foreach ($container->findTaggedServiceIds(self::AUTOWIRING_INFO_PROVIDER_TAG, true) as $serviceId => $attributes) {
37+
$references[] = new Reference($serviceId);
38+
}
39+
40+
$definition->replaceArgument(0, $references);
41+
}
42+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\DependencyInjection;
13+
14+
use Doctrine\Common\Annotations\Reader;
15+
use Psr\Cache\CacheItemPoolInterface;
16+
use Psr\SimpleCache\CacheInterface;
17+
use Symfony\Component\Asset\Packages;
18+
use Symfony\Component\DependencyInjection\Debug\AutowiringInfoProviderInterface;
19+
use Symfony\Component\DependencyInjection\Debug\AutowiringTypeInfo;
20+
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
21+
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
22+
use Symfony\Component\Filesystem\Filesystem;
23+
use Symfony\Component\Form\FormFactoryInterface;
24+
use Symfony\Component\HttpFoundation\RequestStack;
25+
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
26+
use Symfony\Component\HttpFoundation\Session\SessionInterface;
27+
use Symfony\Component\HttpKernel\KernelInterface;
28+
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
29+
use Symfony\Component\Routing\RouterInterface;
30+
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
31+
use Symfony\Component\Serializer\SerializerInterface;
32+
use Symfony\Component\Stopwatch\Stopwatch;
33+
use Symfony\Component\Translation\TranslatorInterface;
34+
use Symfony\Component\Validator\Validator\ValidatorInterface;
35+
use Symfony\Component\Workflow\Registry;
36+
37+
/**
38+
* @author Ryan Weaver <[email protected]>
39+
*/
40+
final class FrameworkAutowiringInfoProvider implements AutowiringInfoProviderInterface
41+
{
42+
public function getTypeInfos(): array
43+
{
44+
return array(
45+
AutowiringTypeInfo::create(CacheItemPoolInterface::class, 'Cache', 10)
46+
->setDescription('general-purpose service for caching things'),
47+
48+
AutowiringTypeInfo::create(CacheInterface::class, 'Simple Cache', 10)
49+
->setDescription('simpler cache, but less features'),
50+
51+
AutowiringTypeInfo::create(RouterInterface::class, 'Router', 10)
52+
->setDescription('used to generate URLs'),
53+
54+
AutowiringTypeInfo::create(EventDispatcherInterface::class, 'Event Dispatcher')
55+
->setDescription('used to dispatch custom events'),
56+
57+
AutowiringTypeInfo::create(Reader::class, 'Annotation Reader', -10),
58+
59+
AutowiringTypeInfo::create(ParameterBagInterface::class, 'Parameter Bag')
60+
->setDescription('access service parameters'),
61+
62+
AutowiringTypeInfo::create(Filesystem::class, 'Filesystem')
63+
->setDescription('helper for filesystem actions'),
64+
65+
AutowiringTypeInfo::create(RequestStack::class, 'Request Stack')
66+
->setDescription('access the Request object'),
67+
68+
AutowiringTypeInfo::create(SessionInterface::class, 'Session'),
69+
70+
AutowiringTypeInfo::create(FlashBagInterface::class, 'Flash Bag')
71+
->setDescription('use to set temporary success/failure messages'),
72+
73+
AutowiringTypeInfo::create(KernelInterface::class, 'Kernel'),
74+
75+
AutowiringTypeInfo::create(Stopwatch::class, 'Stopwatch')
76+
->setDescription('use to add custom timings to profiler'),
77+
78+
AutowiringTypeInfo::create(Packages::class, 'Asset Packages')
79+
->setDescription('use to generate URLs to assets'),
80+
81+
AutowiringTypeInfo::create(FormFactoryInterface::class, 'Form Factory')
82+
->setDescription('use to create form objects'),
83+
84+
AutowiringTypeInfo::create(ValidatorInterface::class, 'Validator')
85+
->setDescription('use to validate data against some constraints'),
86+
87+
AutowiringTypeInfo::create(TranslatorInterface::class, 'Translator'),
88+
89+
AutowiringTypeInfo::create(PropertyAccessorInterface::class, 'Property Accessor')
90+
->setDescription('use to read dynamic keys from some data'),
91+
92+
AutowiringTypeInfo::create(CsrfTokenManagerInterface::class, 'CSRF Token Manager')
93+
->setDescription('generate and check CSRF tokens'),
94+
95+
AutowiringTypeInfo::create(SerializerInterface::class, 'Serializer')
96+
->setDescription('use to serialize data to JSON, XML, etc'),
97+
98+
AutowiringTypeInfo::create(Registry::class, 'Workflow')
99+
->setDescription('use to fetch workflows'),
100+
101+
AutowiringTypeInfo::create(Registry::class, 'Workflow')
102+
->setDescription('use to fetch workflows'),
103+
);
104+
}
105+
}

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Symfony\Bridge\Monolog\Processor\DebugProcessor;
1717
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
1818
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
19+
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AutowireDebugInfoPass;
1920
use Symfony\Bundle\FrameworkBundle\Routing\AnnotatedRouteControllerLoader;
2021
use Symfony\Bundle\FullStack;
2122
use Symfony\Component\Cache\Adapter\AbstractAdapter;
@@ -33,6 +34,7 @@
3334
use Symfony\Component\DependencyInjection\ChildDefinition;
3435
use Symfony\Component\DependencyInjection\ContainerBuilder;
3536
use Symfony\Component\DependencyInjection\ContainerInterface;
37+
use Symfony\Component\DependencyInjection\Debug\AutowiringInfoProviderInterface;
3638
use Symfony\Component\DependencyInjection\Definition;
3739
use Symfony\Component\DependencyInjection\EnvVarProcessorInterface;
3840
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
@@ -330,6 +332,8 @@ public function load(array $configs, ContainerBuilder $container)
330332
->addTag('validator.constraint_validator');
331333
$container->registerForAutoconfiguration(ObjectInitializerInterface::class)
332334
->addTag('validator.initializer');
335+
$container->registerForAutoconfiguration(AutowiringInfoProviderInterface::class)
336+
->addTag(AutowireDebugInfoPass::AUTOWIRING_INFO_PROVIDER_TAG);
333337

334338
if (!$container->getParameter('kernel.debug')) {
335339
// remove tagged iterator argument for resource checkers

src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddAnnotationsCachedReaderPass;
1515
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddDebugLogProcessorPass;
16+
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AutowireDebugInfoPass;
1617
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\CacheCollectorPass;
1718
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\CachePoolPass;
1819
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\CachePoolClearerPass;
@@ -120,6 +121,7 @@ public function build(ContainerBuilder $container)
120121
$container->addCompilerPass(new UnusedTagsPass(), PassConfig::TYPE_AFTER_REMOVING);
121122
$container->addCompilerPass(new ContainerBuilderDebugDumpPass(), PassConfig::TYPE_BEFORE_REMOVING, -255);
122123
$container->addCompilerPass(new CacheCollectorPass(), PassConfig::TYPE_BEFORE_REMOVING);
124+
$container->addCompilerPass(new AutowireDebugInfoPass());
123125
}
124126
}
125127

src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
</service>
5757

5858
<service id="console.command.debug_autowiring" class="Symfony\Bundle\FrameworkBundle\Command\DebugAutowiringCommand">
59+
<argument type="service" id="debug.autowiring_info_manager" on-invalid="ignore" />
5960
<tag name="console.command" command="debug:autowiring" />
6061
</service>
6162

src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,13 @@
2323
<argument type="service" id="debug.argument_resolver.inner" />
2424
<argument type="service" id="debug.stopwatch" />
2525
</service>
26+
27+
<service id="debug.autowiring_info_manager" class="Symfony\Component\DependencyInjection\Debug\AutowiringInfoManager">
28+
<argument /> <!-- argument info providers -->
29+
</service>
30+
31+
<service id="debug.autowiring.framework_autowiring_info_provider" class="Symfony\Bundle\FrameworkBundle\DependencyInjection\FrameworkAutowiringInfoProvider">
32+
<tag name="debug.autowiring_info_provider" />
33+
</service>
2634
</services>
2735
</container>

src/Symfony/Bundle/FrameworkBundle/Tests/Functional/DebugAutowiringCommandTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public function testBasicFunctionality()
3131

3232
$this->assertContains('Symfony\Component\HttpKernel\HttpKernelInterface', $tester->getDisplay());
3333
$this->assertContains('alias to http_kernel', $tester->getDisplay());
34+
$this->assertContains('Simple Cache', $tester->getDisplay(), 'Key services are displayed');
3435
}
3536

3637
public function testSearchArgument()
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\SecurityBundle\DependencyInjection;
13+
14+
use Symfony\Component\DependencyInjection\Debug\AutowiringInfoProviderInterface;
15+
use Symfony\Component\DependencyInjection\Debug\AutowiringTypeInfo;
16+
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
17+
use Symfony\Component\Security\Core\Security;
18+
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
19+
20+
/**
21+
* @author Ryan Weaver <[email protected]>
22+
*/
23+
final class SecurityAutowiringInfoProvider implements AutowiringInfoProviderInterface
24+
{
25+
public function getTypeInfos(): array
26+
{
27+
return array(
28+
AutowiringTypeInfo::create(GuardAuthenticatorHandler::class, 'Guard Auth Handler')
29+
->setDescription('use to manually authenticate with Guard'),
30+
31+
AutowiringTypeInfo::create(Security::class, 'Security')
32+
->setDescription('use to check access & get the current User'),
33+
34+
AutowiringTypeInfo::create(UserPasswordEncoderInterface::class, 'Password Encoder')
35+
->setDescription('use to encode passwords & check them'),
36+
);
37+
}
38+
}

src/Symfony/Bundle/SecurityBundle/Resources/config/security_debug.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,9 @@
1919
</service>
2020

2121
<service id="security.firewall" alias="debug.security.firewall" />
22+
23+
<service id="debug.autowiring.security_autowiring_info_provider" class="Symfony\Bundle\SecurityBundle\DependencyInjection\SecurityAutowiringInfoProvider">
24+
<tag name="debug.autowiring_info_provider" />
25+
</service>
2226
</services>
2327
</container>

0 commit comments

Comments
 (0)