DebugCommand.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  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\Component\Messenger\Command;
  11. use Symfony\Component\Console\Command\Command;
  12. use Symfony\Component\Console\Completion\CompletionInput;
  13. use Symfony\Component\Console\Completion\CompletionSuggestions;
  14. use Symfony\Component\Console\Exception\RuntimeException;
  15. use Symfony\Component\Console\Input\InputArgument;
  16. use Symfony\Component\Console\Input\InputInterface;
  17. use Symfony\Component\Console\Output\OutputInterface;
  18. use Symfony\Component\Console\Style\SymfonyStyle;
  19. /**
  20. * A console command to debug Messenger information.
  21. *
  22. * @author Roland Franssen <franssen.roland@gmail.com>
  23. */
  24. class DebugCommand extends Command
  25. {
  26. protected static $defaultName = 'debug:messenger';
  27. protected static $defaultDescription = 'List messages you can dispatch using the message buses';
  28. private $mapping;
  29. public function __construct(array $mapping)
  30. {
  31. $this->mapping = $mapping;
  32. parent::__construct();
  33. }
  34. /**
  35. * {@inheritdoc}
  36. */
  37. protected function configure()
  38. {
  39. $this
  40. ->addArgument('bus', InputArgument::OPTIONAL, sprintf('The bus id (one of "%s")', implode('", "', array_keys($this->mapping))))
  41. ->setDescription(self::$defaultDescription)
  42. ->setHelp(<<<'EOF'
  43. The <info>%command.name%</info> command displays all messages that can be
  44. dispatched using the message buses:
  45. <info>php %command.full_name%</info>
  46. Or for a specific bus only:
  47. <info>php %command.full_name% command_bus</info>
  48. EOF
  49. )
  50. ;
  51. }
  52. /**
  53. * {@inheritdoc}
  54. */
  55. protected function execute(InputInterface $input, OutputInterface $output)
  56. {
  57. $io = new SymfonyStyle($input, $output);
  58. $io->title('Messenger');
  59. $mapping = $this->mapping;
  60. if ($bus = $input->getArgument('bus')) {
  61. if (!isset($mapping[$bus])) {
  62. throw new RuntimeException(sprintf('Bus "%s" does not exist. Known buses are "%s".', $bus, implode('", "', array_keys($this->mapping))));
  63. }
  64. $mapping = [$bus => $mapping[$bus]];
  65. }
  66. foreach ($mapping as $bus => $handlersByMessage) {
  67. $io->section($bus);
  68. $tableRows = [];
  69. foreach ($handlersByMessage as $message => $handlers) {
  70. if ($description = self::getClassDescription($message)) {
  71. $tableRows[] = [sprintf('<comment>%s</>', $description)];
  72. }
  73. $tableRows[] = [sprintf('<fg=cyan>%s</fg=cyan>', $message)];
  74. foreach ($handlers as $handler) {
  75. $tableRows[] = [
  76. sprintf(' handled by <info>%s</>', $handler[0]).$this->formatConditions($handler[1]),
  77. ];
  78. if ($handlerDescription = self::getClassDescription($handler[0])) {
  79. $tableRows[] = [sprintf(' <comment>%s</>', $handlerDescription)];
  80. }
  81. }
  82. $tableRows[] = [''];
  83. }
  84. if ($tableRows) {
  85. $io->text('The following messages can be dispatched:');
  86. $io->newLine();
  87. $io->table([], $tableRows);
  88. } else {
  89. $io->warning(sprintf('No handled message found in bus "%s".', $bus));
  90. }
  91. }
  92. return 0;
  93. }
  94. private function formatConditions(array $options): string
  95. {
  96. if (!$options) {
  97. return '';
  98. }
  99. $optionsMapping = [];
  100. foreach ($options as $key => $value) {
  101. $optionsMapping[] = $key.'='.$value;
  102. }
  103. return ' (when '.implode(', ', $optionsMapping).')';
  104. }
  105. private static function getClassDescription(string $class): string
  106. {
  107. try {
  108. $r = new \ReflectionClass($class);
  109. if ($docComment = $r->getDocComment()) {
  110. $docComment = preg_split('#\n\s*\*\s*[\n@]#', substr($docComment, 3, -2), 2)[0];
  111. return trim(preg_replace('#\s*\n\s*\*\s*#', ' ', $docComment));
  112. }
  113. } catch (\ReflectionException $e) {
  114. }
  115. return '';
  116. }
  117. public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
  118. {
  119. if ($input->mustSuggestArgumentValuesFor('bus')) {
  120. $suggestions->suggestValues(array_keys($this->mapping));
  121. }
  122. }
  123. }