vendor/symfony/framework-bundle/Command/DebugAutowiringCommand.php line 40

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Bundle\FrameworkBundle\Command;
  11. use Symfony\Bundle\FrameworkBundle\Console\Descriptor\Descriptor;
  12. use Symfony\Component\Console\Completion\CompletionInput;
  13. use Symfony\Component\Console\Completion\CompletionSuggestions;
  14. use Symfony\Component\Console\Formatter\OutputFormatterStyle;
  15. use Symfony\Component\Console\Input\InputArgument;
  16. use Symfony\Component\Console\Input\InputInterface;
  17. use Symfony\Component\Console\Input\InputOption;
  18. use Symfony\Component\Console\Output\OutputInterface;
  19. use Symfony\Component\Console\Style\SymfonyStyle;
  20. use Symfony\Component\HttpKernel\Debug\FileLinkFormatter;
  21. /**
  22.  * A console command for autowiring information.
  23.  *
  24.  * @author Ryan Weaver <ryan@knpuniversity.com>
  25.  *
  26.  * @internal
  27.  */
  28. class DebugAutowiringCommand extends ContainerDebugCommand
  29. {
  30.     protected static $defaultName 'debug:autowiring';
  31.     protected static $defaultDescription 'List classes/interfaces you can use for autowiring';
  32.     private $supportsHref;
  33.     private $fileLinkFormatter;
  34.     public function __construct(string $name nullFileLinkFormatter $fileLinkFormatter null)
  35.     {
  36.         $this->supportsHref method_exists(OutputFormatterStyle::class, 'setHref');
  37.         $this->fileLinkFormatter $fileLinkFormatter;
  38.         parent::__construct($name);
  39.     }
  40.     /**
  41.      * {@inheritdoc}
  42.      */
  43.     protected function configure()
  44.     {
  45.         $this
  46.             ->setDefinition([
  47.                 new InputArgument('search'InputArgument::OPTIONAL'A search filter'),
  48.                 new InputOption('all'nullInputOption::VALUE_NONE'Show also services that are not aliased'),
  49.             ])
  50.             ->setDescription(self::$defaultDescription)
  51.             ->setHelp(<<<'EOF'
  52. The <info>%command.name%</info> command displays the classes and interfaces that
  53. you can use as type-hints for autowiring:
  54.   <info>php %command.full_name%</info>
  55. You can also pass a search term to filter the list:
  56.   <info>php %command.full_name% log</info>
  57. EOF
  58.             )
  59.         ;
  60.     }
  61.     /**
  62.      * {@inheritdoc}
  63.      */
  64.     protected function execute(InputInterface $inputOutputInterface $output): int
  65.     {
  66.         $io = new SymfonyStyle($input$output);
  67.         $errorIo $io->getErrorStyle();
  68.         $builder $this->getContainerBuilder($this->getApplication()->getKernel());
  69.         $serviceIds $builder->getServiceIds();
  70.         $serviceIds array_filter($serviceIds, [$this'filterToServiceTypes']);
  71.         if ($search $input->getArgument('search')) {
  72.             $searchNormalized preg_replace('/[^a-zA-Z0-9\x7f-\xff $]++/'''$search);
  73.             $serviceIds array_filter($serviceIds, function ($serviceId) use ($searchNormalized) {
  74.                 return false !== stripos(str_replace('\\'''$serviceId), $searchNormalized) && !str_starts_with($serviceId'.');
  75.             });
  76.             if (empty($serviceIds)) {
  77.                 $errorIo->error(sprintf('No autowirable classes or interfaces found matching "%s"'$search));
  78.                 return 1;
  79.             }
  80.         }
  81.         uasort($serviceIds'strnatcmp');
  82.         $io->title('Autowirable Types');
  83.         $io->text('The following classes & interfaces can be used as type-hints when autowiring:');
  84.         if ($search) {
  85.             $io->text(sprintf('(only showing classes/interfaces matching <comment>%s</comment>)'$search));
  86.         }
  87.         $hasAlias = [];
  88.         $all $input->getOption('all');
  89.         $previousId '-';
  90.         $serviceIdsNb 0;
  91.         foreach ($serviceIds as $serviceId) {
  92.             $text = [];
  93.             $resolvedServiceId $serviceId;
  94.             if (!str_starts_with($serviceId$previousId)) {
  95.                 $text[] = '';
  96.                 if ('' !== $description Descriptor::getClassDescription($serviceId$resolvedServiceId)) {
  97.                     if (isset($hasAlias[$serviceId])) {
  98.                         continue;
  99.                     }
  100.                     $text[] = $description;
  101.                 }
  102.                 $previousId $serviceId.' $';
  103.             }
  104.             $serviceLine sprintf('<fg=yellow>%s</>'$serviceId);
  105.             if ($this->supportsHref && '' !== $fileLink $this->getFileLink($serviceId)) {
  106.                 $serviceLine sprintf('<fg=yellow;href=%s>%s</>'$fileLink$serviceId);
  107.             }
  108.             if ($builder->hasAlias($serviceId)) {
  109.                 $hasAlias[$serviceId] = true;
  110.                 $serviceAlias $builder->getAlias($serviceId);
  111.                 $serviceLine .= ' <fg=cyan>('.$serviceAlias.')</>';
  112.                 if ($serviceAlias->isDeprecated()) {
  113.                     $serviceLine .= ' - <fg=magenta>deprecated</>';
  114.                 }
  115.             } elseif (!$all) {
  116.                 ++$serviceIdsNb;
  117.                 continue;
  118.             }
  119.             $text[] = $serviceLine;
  120.             $io->text($text);
  121.         }
  122.         $io->newLine();
  123.         if ($serviceIdsNb) {
  124.             $io->text(sprintf('%s more concrete service%s would be displayed when adding the "--all" option.'$serviceIdsNb$serviceIdsNb 's' ''));
  125.         }
  126.         if ($all) {
  127.             $io->text('Pro-tip: use interfaces in your type-hints instead of classes to benefit from the dependency inversion principle.');
  128.         }
  129.         $io->newLine();
  130.         return 0;
  131.     }
  132.     private function getFileLink(string $class): string
  133.     {
  134.         if (null === $this->fileLinkFormatter
  135.             || (null === $r $this->getContainerBuilder($this->getApplication()->getKernel())->getReflectionClass($classfalse))) {
  136.             return '';
  137.         }
  138.         return (string) $this->fileLinkFormatter->format($r->getFileName(), $r->getStartLine());
  139.     }
  140.     public function complete(CompletionInput $inputCompletionSuggestions $suggestions): void
  141.     {
  142.         if ($input->mustSuggestArgumentValuesFor('search')) {
  143.             $builder $this->getContainerBuilder($this->getApplication()->getKernel());
  144.             $suggestions->suggestValues(array_filter($builder->getServiceIds(), [$this'filterToServiceTypes']));
  145.         }
  146.     }
  147. }