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
Drastically improved debug:autowiring + new autowiring info system #26142
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,8 @@ | |
use Symfony\Component\Console\Input\InputInterface; | ||
use Symfony\Component\Console\Output\OutputInterface; | ||
use Symfony\Component\Console\Style\SymfonyStyle; | ||
use Symfony\Component\DependencyInjection\Debug\AutowiringInfoManager; | ||
use Symfony\Component\DependencyInjection\Debug\AutowiringTypeInfo; | ||
|
||
/** | ||
* A console command for autowiring information. | ||
|
@@ -27,6 +29,15 @@ class DebugAutowiringCommand extends ContainerDebugCommand | |
{ | ||
protected static $defaultName = 'debug:autowiring'; | ||
|
||
private $autowiringInfoManager; | ||
|
||
public function __construct(AutowiringInfoManager $autowiringInfoManager = null) | ||
{ | ||
$this->autowiringInfoManager = $autowiringInfoManager; | ||
|
||
parent::__construct(); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
|
@@ -78,24 +89,92 @@ protected function execute(InputInterface $input, OutputInterface $output) | |
|
||
asort($serviceIds); | ||
|
||
$io->title('Autowirable Services'); | ||
$io->text('The following classes & interfaces can be used as type-hints when autowiring:'); | ||
if ($search) { | ||
$io->text(sprintf('(only showing classes/interfaces matching <comment>%s</comment>)', $search)); | ||
} | ||
$io->newLine(); | ||
$tableRows = array(); | ||
|
||
$keyServices = array(); | ||
$otherServices = array(); | ||
$hasAlias = array(); | ||
foreach ($serviceIds as $serviceId) { | ||
if (null !== $this->autowiringInfoManager && $autowiringInfo = $this->autowiringInfoManager->getInfo($serviceId)) { | ||
$keyServices[] = array( | ||
'info' => $autowiringInfo, | ||
'alias' => $builder->has($serviceId) ? $builder->getAlias($serviceId) : null, | ||
); | ||
|
||
continue; | ||
} | ||
|
||
if ($builder->hasAlias($serviceId)) { | ||
$tableRows[] = array(sprintf('<fg=cyan>%s</fg=cyan>', $serviceId)); | ||
$tableRows[] = array(sprintf(' alias to %s', $builder->getAlias($serviceId))); | ||
$hasAlias[(string) $builder->getAlias($serviceId)] = true; | ||
} else { | ||
$tableRows[$serviceId] = array(sprintf('<fg=cyan>%s</fg=cyan>', $serviceId)); | ||
} | ||
|
||
$otherServices[$serviceId] = array( | ||
'type' => $serviceId, | ||
'alias' => $builder->hasAlias($serviceId) ? $builder->getAlias($serviceId) : null, | ||
); | ||
} | ||
$otherServices = array_diff_key($otherServices, $hasAlias); | ||
|
||
usort($keyServices, function ($a, $b) { | ||
if ($a['info']->getPriority() === $b['info']->getPriority()) { | ||
return 0; | ||
} | ||
|
||
return $a['info']->getPriority() > $b['info']->getPriority() ? -1 : 1; | ||
}); | ||
|
||
$this->printKeyServices($keyServices, $io); | ||
|
||
$io->table(array(), array_diff_key($tableRows, $hasAlias)); | ||
$this->printOtherServices($otherServices, $io); | ||
} | ||
|
||
private function printOtherServices(array $otherServices, SymfonyStyle $io) | ||
{ | ||
if (empty($otherServices)) { | ||
return; | ||
} | ||
|
||
// not necessary to print if this is the only list | ||
if (null !== $this->autowiringInfoManager) { | ||
$io->title('Other Services'); | ||
} | ||
|
||
foreach ($otherServices as $serviceData) { | ||
$io->writeln(sprintf('<fg=cyan>%s</fg=cyan>', $serviceData['type'])); | ||
if ($alias = $serviceData['alias']) { | ||
$io->writeln(sprintf(' alias to %s', $alias)); | ||
} | ||
} | ||
} | ||
|
||
private function printKeyServices(array $keyServices, SymfonyStyle $io) | ||
{ | ||
if (empty($keyServices)) { | ||
return; | ||
} | ||
|
||
$io->title('Key Services'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i'd say |
||
foreach ($keyServices as $serviceData) { | ||
/** @var AutowiringTypeInfo $info */ | ||
$info = $serviceData['info']; | ||
|
||
$nameLine = sprintf('<comment>%s</comment>', $info->getName()); | ||
if ($info->getDescription()) { | ||
$nameLine .= sprintf(' (%s)', $info->getDescription()); | ||
} | ||
$io->writeln($nameLine); | ||
|
||
$io->writeln(sprintf(' Type: <fg=cyan>%s</fg=cyan>', $info->getType())); | ||
|
||
if ($serviceData['alias']) { | ||
$io->writeln(sprintf(' Alias to the %s service', $serviceData['alias'])); | ||
} | ||
|
||
$io->writeln(''); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<?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\DependencyInjection\Compiler; | ||
|
||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; | ||
use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
use Symfony\Component\DependencyInjection\Reference; | ||
|
||
/** | ||
* Looks for & processes debug.autowiring_info_provider tags. | ||
* | ||
* @author Ryan Weaver <ryan@knpuniversity.com> | ||
*/ | ||
class AutowireDebugInfoPass implements CompilerPassInterface | ||
{ | ||
const AUTOWIRING_INFO_PROVIDER_TAG = 'debug.autowiring_info_provider'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
public function process(ContainerBuilder $container) | ||
{ | ||
if (false === $container->hasDefinition('debug.autowiring_info_manager')) { | ||
return; | ||
} | ||
|
||
$definition = $container->getDefinition('debug.autowiring_info_manager'); | ||
|
||
$references = array(); | ||
foreach ($container->findTaggedServiceIds(self::AUTOWIRING_INFO_PROVIDER_TAG, true) as $serviceId => $attributes) { | ||
$references[] = new Reference($serviceId); | ||
} | ||
|
||
$definition->replaceArgument(0, $references); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
<?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\DependencyInjection; | ||
|
||
use Doctrine\Common\Annotations\Reader; | ||
use Psr\Cache\CacheItemPoolInterface; | ||
use Psr\SimpleCache\CacheInterface; | ||
use Symfony\Component\Asset\Packages; | ||
use Symfony\Component\DependencyInjection\Debug\AutowiringInfoProviderInterface; | ||
use Symfony\Component\DependencyInjection\Debug\AutowiringTypeInfo; | ||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; | ||
use Symfony\Component\EventDispatcher\EventDispatcherInterface; | ||
use Symfony\Component\Filesystem\Filesystem; | ||
use Symfony\Component\Form\FormFactoryInterface; | ||
use Symfony\Component\HttpFoundation\RequestStack; | ||
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface; | ||
use Symfony\Component\HttpFoundation\Session\SessionInterface; | ||
use Symfony\Component\HttpKernel\KernelInterface; | ||
use Symfony\Component\PropertyAccess\PropertyAccessorInterface; | ||
use Symfony\Component\Routing\RouterInterface; | ||
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; | ||
use Symfony\Component\Serializer\SerializerInterface; | ||
use Symfony\Component\Stopwatch\Stopwatch; | ||
use Symfony\Component\Translation\TranslatorInterface; | ||
use Symfony\Component\Validator\Validator\ValidatorInterface; | ||
use Symfony\Component\Workflow\Registry; | ||
|
||
/** | ||
* @author Ryan Weaver <ryan@knpuniversity.com> | ||
*/ | ||
final class FrameworkAutowiringInfoProvider implements AutowiringInfoProviderInterface | ||
{ | ||
public function getTypeInfos(): array | ||
{ | ||
return array( | ||
AutowiringTypeInfo::create(CacheItemPoolInterface::class, 'Cache', 10) | ||
->setDescription('general-purpose service for caching things'), | ||
|
||
AutowiringTypeInfo::create(CacheInterface::class, 'Simple Cache', 10) | ||
->setDescription('simpler cache, but less features'), | ||
|
||
AutowiringTypeInfo::create(RouterInterface::class, 'Router', 10) | ||
->setDescription('used to generate URLs'), | ||
|
||
AutowiringTypeInfo::create(EventDispatcherInterface::class, 'Event Dispatcher') | ||
->setDescription('used to dispatch custom events'), | ||
|
||
AutowiringTypeInfo::create(Reader::class, 'Annotation Reader', -10), | ||
|
||
AutowiringTypeInfo::create(ParameterBagInterface::class, 'Parameter Bag') | ||
->setDescription('access service parameters'), | ||
|
||
AutowiringTypeInfo::create(Filesystem::class, 'Filesystem') | ||
->setDescription('helper for filesystem actions'), | ||
|
||
AutowiringTypeInfo::create(RequestStack::class, 'Request Stack') | ||
->setDescription('access the Request object'), | ||
|
||
AutowiringTypeInfo::create(SessionInterface::class, 'Session'), | ||
|
||
AutowiringTypeInfo::create(FlashBagInterface::class, 'Flash Bag') | ||
->setDescription('use to set temporary success/failure messages'), | ||
|
||
AutowiringTypeInfo::create(KernelInterface::class, 'Kernel'), | ||
|
||
AutowiringTypeInfo::create(Stopwatch::class, 'Stopwatch') | ||
->setDescription('use to add custom timings to profiler'), | ||
|
||
AutowiringTypeInfo::create(Packages::class, 'Asset Packages') | ||
->setDescription('use to generate URLs to assets'), | ||
|
||
AutowiringTypeInfo::create(FormFactoryInterface::class, 'Form Factory') | ||
->setDescription('use to create form objects'), | ||
|
||
AutowiringTypeInfo::create(ValidatorInterface::class, 'Validator') | ||
->setDescription('use to validate data against some constraints'), | ||
|
||
AutowiringTypeInfo::create(TranslatorInterface::class, 'Translator'), | ||
|
||
AutowiringTypeInfo::create(PropertyAccessorInterface::class, 'Property Accessor') | ||
->setDescription('use to read dynamic keys from some data'), | ||
|
||
AutowiringTypeInfo::create(CsrfTokenManagerInterface::class, 'CSRF Token Manager') | ||
->setDescription('generate and check CSRF tokens'), | ||
|
||
AutowiringTypeInfo::create(SerializerInterface::class, 'Serializer') | ||
->setDescription('use to serialize data to JSON, XML, etc'), | ||
|
||
AutowiringTypeInfo::create(Registry::class, 'Workflow') | ||
->setDescription('use to fetch workflows'), | ||
|
||
AutowiringTypeInfo::create(Registry::class, 'Workflow') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. duplicated :) |
||
->setDescription('use to fetch workflows'), | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,5 +23,13 @@ | |
<argument type="service" id="debug.argument_resolver.inner" /> | ||
<argument type="service" id="debug.stopwatch" /> | ||
</service> | ||
|
||
<service id="debug.autowiring_info_manager" class="Symfony\Component\DependencyInjection\Debug\AutowiringInfoManager"> | ||
<argument /> <!-- argument info providers --> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
</service> | ||
|
||
<service id="debug.autowiring.framework_autowiring_info_provider" class="Symfony\Bundle\FrameworkBundle\DependencyInjection\FrameworkAutowiringInfoProvider"> | ||
<tag name="debug.autowiring_info_provider" /> | ||
</service> | ||
</services> | ||
</container> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
<?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\SecurityBundle\DependencyInjection; | ||
|
||
use Symfony\Component\DependencyInjection\Debug\AutowiringInfoProviderInterface; | ||
use Symfony\Component\DependencyInjection\Debug\AutowiringTypeInfo; | ||
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; | ||
use Symfony\Component\Security\Core\Security; | ||
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler; | ||
|
||
/** | ||
* @author Ryan Weaver <ryan@knpuniversity.com> | ||
*/ | ||
final class SecurityAutowiringInfoProvider implements AutowiringInfoProviderInterface | ||
{ | ||
public function getTypeInfos(): array | ||
{ | ||
return array( | ||
AutowiringTypeInfo::create(GuardAuthenticatorHandler::class, 'Guard Auth Handler') | ||
->setDescription('use to manually authenticate with Guard'), | ||
|
||
AutowiringTypeInfo::create(Security::class, 'Security') | ||
->setDescription('use to check access & get the current User'), | ||
|
||
AutowiringTypeInfo::create(UserPasswordEncoderInterface::class, 'Password Encoder') | ||
->setDescription('use to encode passwords & check them'), | ||
); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like this isn't used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are both used - one I think just for phpdoc :). We have a PR bot (fabbot) that validates cs, including unused use statements
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh how come include namespaces for just docblocks? Interesting!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It lets you use the short class names in phpdoc - like @param Foo - editors will use the use statement to know the full class name that you’re referencing :)