3 namespace Drupal\Console\Core;
5 use Drupal\Console\Core\EventSubscriber\RemoveMessagesListener;
6 use Drupal\Console\Core\EventSubscriber\ShowGenerateCountCodeLinesListener;
7 use Drupal\Console\Core\Utils\TranslatorManagerInterface;
8 use Symfony\Component\DependencyInjection\ContainerInterface;
9 use Symfony\Component\EventDispatcher\EventDispatcher;
10 use Symfony\Component\Console\Output\OutputInterface;
11 use Symfony\Component\Console\Input\InputInterface;
12 use Symfony\Component\Console\Input\InputOption;
13 use Symfony\Component\Console\Application as BaseApplication;
14 use Symfony\Component\Console\Input\ArrayInput;
15 use Drupal\Console\Core\EventSubscriber\DefaultValueEventListener;
16 use Drupal\Console\Core\EventSubscriber\ShowGenerateChainListener;
17 use Drupal\Console\Core\EventSubscriber\ShowTipsListener;
18 use Drupal\Console\Core\EventSubscriber\ShowWelcomeMessageListener;
19 use Drupal\Console\Core\EventSubscriber\ValidateExecutionListener;
20 use Drupal\Console\Core\EventSubscriber\ShowGeneratedFilesListener;
21 use Drupal\Console\Core\EventSubscriber\ShowGenerateInlineListener;
22 use Drupal\Console\Core\EventSubscriber\CallCommandListener;
23 use Drupal\Console\Core\Utils\ConfigurationManager;
24 use Drupal\Console\Core\Style\DrupalStyle;
25 use Drupal\Console\Core\Utils\ChainDiscovery;
26 use Drupal\Console\Core\Command\Chain\ChainCustomCommand;
27 use Drupal\Console\Core\Bootstrap\DrupalInterface;
32 * @package Drupal\Console
34 class Application extends BaseApplication
37 * @var ContainerInterface
44 protected $commandName;
47 * @var DrupalInterface
54 protected $eventRegistered;
57 * ConsoleApplication constructor.
59 * @param ContainerInterface $container
61 * @param string $version
63 public function __construct(
64 ContainerInterface $container,
68 $this->container = $container;
69 $this->eventRegistered = false;
70 parent::__construct($name, $version);
75 * @return TranslatorManagerInterface
77 public function getTranslator()
79 if ($this->container) {
80 return $this->container->get('console.translator_manager');
91 public function trans($key)
93 if ($this->getTranslator()) {
94 return $this->getTranslator()->trans($key);
103 public function doRun(InputInterface $input, OutputInterface $output)
105 $io = new DrupalStyle($input, $output);
106 $messageManager = $this->container->get('console.message_manager');
107 $this->commandName = $this->getCommandName($input)?:'list';
109 $clear = $this->container->get('console.configuration_manager')
111 ->get('application.clear')?:false;
112 if ($clear === true || $clear === 'true') {
113 $output->write(sprintf("\033\143"));
116 $this->loadCommands();
119 * @var ConfigurationManager $configurationManager
121 $configurationManager = $this->container
122 ->get('console.configuration_manager');
124 if (!$this->has($this->commandName)) {
125 $isValidCommand = false;
126 $config = $configurationManager->getConfiguration();
127 $mappings = $config->get('application.commands.mappings');
129 if (array_key_exists($this->commandName, $mappings)) {
130 $commandNameMap = $mappings[$this->commandName];
131 $messageManager->warning(
133 $this->trans('application.errors.renamed-command'),
139 $this->find($commandNameMap)->setAliases([$this->commandName])
141 $isValidCommand = true;
144 $drushCommand = $configurationManager->readDrushEquivalents($this->commandName);
147 $this->find($drushCommand)->setAliases([$this->commandName])
149 $isValidCommand = true;
150 $messageManager->warning(
152 $this->trans('application.errors.drush-command'),
159 $namespaces = $this->getNamespaces();
160 if (in_array($this->commandName, $namespaces)) {
161 $input = new ArrayInput(
164 'namespace' => $this->commandName
167 $this->commandName = 'list';
168 $isValidCommand = true;
171 if (!$isValidCommand) {
174 $this->trans('application.errors.invalid-command'),
183 $code = parent::doRun(
188 // Propagate Drupal messages.
189 $this->addDrupalMessages($messageManager);
191 if ($this->showMessages($input)) {
192 $messages = $messageManager->getMessages();
194 foreach ($messages as $message) {
195 $showBy = $message['showBy'];
196 if ($showBy!=='all' && $showBy!==$this->commandName) {
199 $type = $message['type'];
200 $io->$type($message['message']);
208 public function loadCommands()
210 $this->registerGenerators();
211 $this->registerCommands();
212 $this->registerEvents();
213 $this->registerExtendCommands();
216 * @var ConfigurationManager $configurationManager
218 $configurationManager = $this->container
219 ->get('console.configuration_manager');
221 $config = $configurationManager->getConfiguration()
222 ->get('application.extras.config')?:'true';
223 if ($config === 'true') {
224 $this->registerCommandsFromAutoWireConfiguration();
227 $chains = $configurationManager->getConfiguration()
228 ->get('application.extras.chains')?:'true';
229 if ($chains === 'true') {
230 $this->registerChainCommands();
235 * @param InputInterface $input
239 private function showMessages(InputInterface $input)
241 $format = $input->hasOption('format')?$input->getOption('format'):'txt';
243 if ($format !== 'txt') {
253 private function registerEvents()
255 if (!$this->eventRegistered) {
256 $dispatcher = new EventDispatcher();
257 $dispatcher->addSubscriber(
258 new ValidateExecutionListener(
259 $this->container->get('console.translator_manager'),
260 $this->container->get('console.configuration_manager')
263 $dispatcher->addSubscriber(
264 new ShowWelcomeMessageListener(
265 $this->container->get('console.translator_manager')
268 $dispatcher->addSubscriber(
269 new DefaultValueEventListener(
270 $this->container->get('console.configuration_manager')
273 $dispatcher->addSubscriber(
274 new ShowTipsListener(
275 $this->container->get('console.translator_manager')
278 $dispatcher->addSubscriber(
279 new CallCommandListener(
280 $this->container->get('console.chain_queue')
283 $dispatcher->addSubscriber(
284 new ShowGeneratedFilesListener(
285 $this->container->get('console.file_queue'),
286 $this->container->get('console.show_file')
289 $dispatcher->addSubscriber(
290 new ShowGenerateInlineListener(
291 $this->container->get('console.translator_manager')
294 $dispatcher->addSubscriber(
295 new ShowGenerateChainListener(
296 $this->container->get('console.translator_manager')
300 $dispatcher->addSubscriber(
301 new ShowGenerateCountCodeLinesListener(
302 $this->container->get('console.translator_manager'),
303 $this->container->get('console.count_code_lines')
307 $dispatcher->addSubscriber(
308 new RemoveMessagesListener(
309 $this->container->get('console.message_manager')
313 $this->setDispatcher($dispatcher);
314 $this->eventRegistered = true;
321 private function addOptions()
323 // Get the configuration from config.yml.
324 $env = $this->container
325 ->get('console.configuration_manager')
327 ->get('application.environment');
329 $this->getDefinition()->addOption(
333 InputOption::VALUE_OPTIONAL,
334 $this->trans('application.options.env'),
335 !empty($env) ? $env : 'prod'
338 $this->getDefinition()->addOption(
342 InputOption::VALUE_OPTIONAL,
343 $this->trans('application.options.root')
346 $this->getDefinition()->addOption(
350 InputOption::VALUE_NONE,
351 $this->trans('application.options.debug')
354 $this->getDefinition()->addOption(
358 InputOption::VALUE_NONE,
359 $this->trans('application.options.learning')
362 $this->getDefinition()->addOption(
366 InputOption::VALUE_NONE,
367 $this->trans('application.options.generate-chain')
370 $this->getDefinition()->addOption(
374 InputOption::VALUE_NONE,
375 $this->trans('application.options.generate-inline')
378 $this->getDefinition()->addOption(
382 InputOption::VALUE_NONE,
383 $this->trans('application.options.generate-doc')
386 $this->getDefinition()->addOption(
390 InputOption::VALUE_OPTIONAL,
391 $this->trans('application.options.target')
394 $this->getDefinition()->addOption(
398 InputOption::VALUE_REQUIRED,
399 $this->trans('application.options.uri')
402 $this->getDefinition()->addOption(
406 InputOption::VALUE_NONE,
407 $this->trans('application.options.yes')
415 private function registerCommands()
417 $consoleCommands = $this->container
418 ->findTaggedServiceIds('drupal.command');
420 $aliases = $this->container->get('console.configuration_manager')
422 ->get('application.commands.aliases')?:[];
424 $invalidCommands = [];
425 if ($this->container->has('console.key_value_storage')) {
426 $invalidCommands = $this->container
427 ->get('console.key_value_storage')
428 ->get('invalid_commands', []);
431 foreach ($consoleCommands as $name => $tags) {
432 if (in_array($name, $invalidCommands)) {
436 if (!$this->container->has($name)) {
441 $command = $this->container->get($name);
442 } catch (\Exception $e) {
443 echo $name . ' - ' . $e->getMessage() . PHP_EOL;
452 if (method_exists($command, 'setTranslator')) {
453 $command->setTranslator(
454 $this->container->get('console.translator_manager')
458 if (method_exists($command, 'setContainer')) {
459 $command->setContainer(
460 $this->container->get('service_container')
464 if (array_key_exists($command->getName(), $aliases)) {
465 $commandAliases = $aliases[$command->getName()];
466 if (!is_array($commandAliases)) {
467 $commandAliases = [$commandAliases];
469 $commandAliases = array_merge(
470 $command->getAliases(),
473 $command->setAliases($commandAliases);
476 $this->add($command);
483 private function registerGenerators()
485 $consoleGenerators = $this->container
486 ->findTaggedServiceIds('drupal.generator');
488 foreach ($consoleGenerators as $name => $tags) {
489 if (!$this->container->has($name)) {
494 $generator = $this->container->get($name);
495 } catch (\Exception $e) {
496 echo $name . ' - ' . $e->getMessage() . PHP_EOL;
504 if (method_exists($generator, 'setRenderer')) {
505 $generator->setRenderer(
506 $this->container->get('console.renderer')
510 if (method_exists($generator, 'setFileQueue')) {
511 $generator->setFileQueue(
512 $this->container->get('console.file_queue')
516 if (method_exists($generator, 'setCountCodeLines')) {
517 $generator->setCountCodeLines(
518 $this->container->get('console.count_code_lines')
522 if (method_exists($generator, 'setDrupalFinder')) {
523 $generator->setDrupalFinder(
524 $this->container->get('console.drupal_finder')
531 * registerCommandsFromAutoWireConfiguration
533 private function registerCommandsFromAutoWireConfiguration()
535 $configuration = $this->container->get('console.configuration_manager')
536 ->getConfiguration();
538 $autoWireForcedCommands = $configuration
539 ->get('application.autowire.commands.forced');
541 if (!is_array($autoWireForcedCommands)) {
545 foreach ($autoWireForcedCommands as $autoWireForcedCommand) {
547 if (!$autoWireForcedCommand['class']) {
551 $reflectionClass = new \ReflectionClass(
552 $autoWireForcedCommand['class']
556 if (array_key_exists('arguments', $autoWireForcedCommand)) {
557 foreach ($autoWireForcedCommand['arguments'] as $argument) {
558 $argument = substr($argument, 1);
559 $arguments[] = $this->container->get($argument);
563 $command = $reflectionClass->newInstanceArgs($arguments);
565 if (method_exists($command, 'setTranslator')) {
566 $command->setTranslator(
567 $this->container->get('console.translator_manager')
570 if (method_exists($command, 'setContainer')) {
571 $command->setContainer(
572 $this->container->get('service_container')
576 $this->add($command);
577 } catch (\Exception $e) {
578 echo $e->getMessage() . PHP_EOL;
583 $autoWireNameCommand = $configuration->get(
585 'application.autowire.commands.name.%s',
590 if ($autoWireNameCommand) {
593 if (array_key_exists('arguments', $autoWireNameCommand)) {
594 foreach ($autoWireNameCommand['arguments'] as $argument) {
595 $argument = substr($argument, 1);
596 $arguments[] = $this->container->get($argument);
600 $reflectionClass = new \ReflectionClass(
601 $autoWireNameCommand['class']
603 $command = $reflectionClass->newInstanceArgs($arguments);
605 if (method_exists($command, 'setTranslator')) {
606 $command->setTranslator(
607 $this->container->get('console.translator_manager')
610 if (method_exists($command, 'setContainer')) {
611 $command->setContainer(
612 $this->container->get('service_container')
616 $this->add($command);
617 } catch (\Exception $e) {
618 echo $e->getMessage() . PHP_EOL;
624 * registerChainCommands
626 public function registerChainCommands()
629 * @var ChainDiscovery $chainDiscovery
631 $chainDiscovery = $this->container->get('console.chain_discovery');
632 $chainCommands = $chainDiscovery->getChainCommands();
634 foreach ($chainCommands as $name => $chainCommand) {
636 $file = $chainCommand['file'];
637 $description = $chainCommand['description'];
638 $command = new ChainCustomCommand(
644 $this->add($command);
645 } catch (\Exception $e) {
646 echo $e->getMessage() . PHP_EOL;
652 * registerExtendCommands
654 private function registerExtendCommands()
656 $this->container->get('console.configuration_manager')
657 ->loadExtendConfiguration();
660 public function getData()
675 $languages = $this->container->get('console.configuration_manager')
677 ->get('application.languages');
680 foreach ($singleCommands as $singleCommand) {
681 $data['commands']['misc'][] = $this->commandData($singleCommand);
684 $namespaces = array_filter(
685 $this->getNamespaces(), function ($item) {
686 return (strpos($item, ':')<=0);
690 array_unshift($namespaces, 'misc');
692 foreach ($namespaces as $namespace) {
693 $commands = $this->all($namespace);
695 $commands, function ($cmd1, $cmd2) {
696 return strcmp($cmd1->getName(), $cmd2->getName());
700 foreach ($commands as $command) {
701 if (method_exists($command, 'getModule')) {
702 if ($command->getModule() == 'Console') {
703 $data['commands'][$namespace][] = $this->commandData(
708 $data['commands'][$namespace][] = $this->commandData(
715 $input = $this->getDefinition();
717 foreach ($input->getOptions() as $option) {
719 'name' => $option->getName(),
720 'description' => $this->trans('application.options.'.$option->getName())
724 foreach ($input->getArguments() as $argument) {
726 'name' => $argument->getName(),
727 'description' => $this->trans('application.arguments.'.$argument->getName())
731 $data['application'] = [
732 'namespaces' => $namespaces,
733 'options' => $options,
734 'arguments' => $arguments,
735 'languages' => $languages,
737 'title' => $this->trans('application.gitbook.messages.title'),
738 'note' => $this->trans('application.gitbook.messages.note'),
739 'note_description' => $this->trans('application.gitbook.messages.note-description'),
740 'command' => $this->trans('application.gitbook.messages.command'),
741 'options' => $this->trans('application.gitbook.messages.options'),
742 'option' => $this->trans('application.gitbook.messages.option'),
743 'details' => $this->trans('application.gitbook.messages.details'),
744 'arguments' => $this->trans('application.gitbook.messages.arguments'),
745 'argument' => $this->trans('application.gitbook.messages.argument'),
746 'examples' => $this->trans('application.gitbook.messages.examples')
754 private function commandData($commandName)
756 if (!$this->has($commandName)) {
760 $command = $this->find($commandName);
762 $input = $command->getDefinition();
764 foreach ($input->getOptions() as $option) {
765 $options[$option->getName()] = [
766 'name' => $option->getName(),
767 'description' => $this->trans($option->getDescription()),
772 foreach ($input->getArguments() as $argument) {
773 $arguments[$argument->getName()] = [
774 'name' => $argument->getName(),
775 'description' => $this->trans($argument->getDescription()),
779 $commandKey = str_replace(':', '.', $command->getName());
782 for ($i = 0; $i < 5; $i++) {
783 $description = sprintf(
784 'commands.%s.examples.%s.description',
788 $execution = sprintf(
789 'commands.%s.examples.%s.execution',
794 if ($description != $this->trans($description)) {
796 'description' => $this->trans($description),
797 'execution' => $this->trans($execution)
805 'name' => $command->getName(),
806 'description' => $command->getDescription(),
807 'options' => $options,
808 'arguments' => $arguments,
809 'examples' => $examples,
810 'aliases' => $command->getAliases(),
811 'key' => $commandKey,
812 'dashed' => str_replace(':', '-', $command->getName()),
814 'usage' => $this->trans('application.gitbook.messages.usage'),
815 'options' => $this->trans('application.gitbook.messages.options'),
816 'option' => $this->trans('application.gitbook.messages.option'),
817 'details' => $this->trans('application.gitbook.messages.details'),
818 'arguments' => $this->trans('application.gitbook.messages.arguments'),
819 'argument' => $this->trans('application.gitbook.messages.argument'),
820 'examples' => $this->trans('application.gitbook.messages.examples')
828 * @return DrupalInterface
830 public function getDrupal()
832 return $this->drupal;
836 * @param DrupalInterface $drupal
838 public function setDrupal($drupal)
840 $this->drupal = $drupal;
843 public function setContainer($container)
845 $this->container = $container;
848 public function getContainer()
850 return $this->container;
854 * Add Drupal system messages.
856 protected function addDrupalMessages($messageManager) {
857 if (function_exists('drupal_get_messages')) {
858 $drupalMessages = drupal_get_messages();
859 foreach ($drupalMessages as $type => $messages) {
860 foreach ($messages as $message) {
861 $method = $this->getMessageMethod($type);
862 $messageManager->{$method}((string)$message);
869 * Gets method name for MessageManager.
871 * @param string $type
872 * Type of the message.
877 protected function getMessageMethod($type) {
878 $methodName = 'info';
890 * Finds a command by name or alias.
892 * @param string $name A command name or a command alias
894 * @return mixed A Command instance
896 * Override parent find method to avoid name collisions with automatically
897 * generated command abbreviations.
898 * Command name validation was previously done at doRun method.
900 public function find($name)
902 return $this->get($name);