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 (method_exists($command, 'setDrupalFinder')) {
465 $command->setDrupalFinder(
466 $this->container->get('console.drupal_finder')
470 if (array_key_exists($command->getName(), $aliases)) {
471 $commandAliases = $aliases[$command->getName()];
472 if (!is_array($commandAliases)) {
473 $commandAliases = [$commandAliases];
475 $commandAliases = array_merge(
476 $command->getAliases(),
479 $command->setAliases($commandAliases);
482 $this->add($command);
489 private function registerGenerators()
491 $consoleGenerators = $this->container
492 ->findTaggedServiceIds('drupal.generator');
494 foreach ($consoleGenerators as $name => $tags) {
495 if (!$this->container->has($name)) {
500 $generator = $this->container->get($name);
501 } catch (\Exception $e) {
502 echo $name . ' - ' . $e->getMessage() . PHP_EOL;
511 if (method_exists($generator, 'setRenderer')) {
512 $generator->setRenderer(
513 $this->container->get('console.renderer')
517 if (method_exists($generator, 'setFileQueue')) {
518 $generator->setFileQueue(
519 $this->container->get('console.file_queue')
523 if (method_exists($generator, 'setCountCodeLines')) {
524 $generator->setCountCodeLines(
525 $this->container->get('console.count_code_lines')
529 if (method_exists($generator, 'setDrupalFinder')) {
530 $generator->setDrupalFinder(
531 $this->container->get('console.drupal_finder')
538 * registerCommandsFromAutoWireConfiguration
540 private function registerCommandsFromAutoWireConfiguration()
542 $configuration = $this->container->get('console.configuration_manager')
543 ->getConfiguration();
545 $autoWireForcedCommands = $configuration
546 ->get('application.autowire.commands.forced');
548 if (!is_array($autoWireForcedCommands)) {
552 foreach ($autoWireForcedCommands as $autoWireForcedCommand) {
554 if (!$autoWireForcedCommand['class']) {
558 $reflectionClass = new \ReflectionClass(
559 $autoWireForcedCommand['class']
563 if (array_key_exists('arguments', $autoWireForcedCommand)) {
564 foreach ($autoWireForcedCommand['arguments'] as $argument) {
565 $argument = substr($argument, 1);
566 $arguments[] = $this->container->get($argument);
570 $command = $reflectionClass->newInstanceArgs($arguments);
572 if (method_exists($command, 'setTranslator')) {
573 $command->setTranslator(
574 $this->container->get('console.translator_manager')
577 if (method_exists($command, 'setContainer')) {
578 $command->setContainer(
579 $this->container->get('service_container')
583 $this->add($command);
584 } catch (\Exception $e) {
585 echo $e->getMessage() . PHP_EOL;
590 $autoWireNameCommand = $configuration->get(
592 'application.autowire.commands.name.%s',
597 if ($autoWireNameCommand) {
600 if (array_key_exists('arguments', $autoWireNameCommand)) {
601 foreach ($autoWireNameCommand['arguments'] as $argument) {
602 $argument = substr($argument, 1);
603 $arguments[] = $this->container->get($argument);
607 $reflectionClass = new \ReflectionClass(
608 $autoWireNameCommand['class']
610 $command = $reflectionClass->newInstanceArgs($arguments);
612 if (method_exists($command, 'setTranslator')) {
613 $command->setTranslator(
614 $this->container->get('console.translator_manager')
617 if (method_exists($command, 'setContainer')) {
618 $command->setContainer(
619 $this->container->get('service_container')
623 $this->add($command);
624 } catch (\Exception $e) {
625 echo $e->getMessage() . PHP_EOL;
631 * registerChainCommands
633 public function registerChainCommands()
636 * @var ChainDiscovery $chainDiscovery
638 $chainDiscovery = $this->container->get('console.chain_discovery');
639 $chainCommands = $chainDiscovery->getChainCommands();
641 foreach ($chainCommands as $name => $chainCommand) {
643 $file = $chainCommand['file'];
644 $description = $chainCommand['description'];
645 $command = new ChainCustomCommand(
651 $this->add($command);
652 } catch (\Exception $e) {
653 echo $e->getMessage() . PHP_EOL;
659 * registerExtendCommands
661 private function registerExtendCommands()
663 $this->container->get('console.configuration_manager')
664 ->loadExtendConfiguration();
667 public function getData()
682 $languages = $this->container->get('console.configuration_manager')
684 ->get('application.languages');
687 foreach ($singleCommands as $singleCommand) {
688 $data['commands']['misc'][] = $this->commandData($singleCommand);
691 $namespaces = array_filter(
692 $this->getNamespaces(), function ($item) {
693 return (strpos($item, ':')<=0);
697 array_unshift($namespaces, 'misc');
699 foreach ($namespaces as $namespace) {
700 $commands = $this->all($namespace);
702 $commands, function ($cmd1, $cmd2) {
703 return strcmp($cmd1->getName(), $cmd2->getName());
707 foreach ($commands as $command) {
708 if (method_exists($command, 'getModule')) {
709 if ($command->getModule() == 'Console') {
710 $data['commands'][$namespace][] = $this->commandData(
715 $data['commands'][$namespace][] = $this->commandData(
722 $input = $this->getDefinition();
724 foreach ($input->getOptions() as $option) {
726 'name' => $option->getName(),
727 'description' => $this->trans('application.options.'.$option->getName())
731 foreach ($input->getArguments() as $argument) {
733 'name' => $argument->getName(),
734 'description' => $this->trans('application.arguments.'.$argument->getName())
738 $data['application'] = [
739 'namespaces' => $namespaces,
740 'options' => $options,
741 'arguments' => $arguments,
742 'languages' => $languages,
744 'title' => $this->trans('application.gitbook.messages.title'),
745 'note' => $this->trans('application.gitbook.messages.note'),
746 'note_description' => $this->trans('application.gitbook.messages.note-description'),
747 'command' => $this->trans('application.gitbook.messages.command'),
748 'options' => $this->trans('application.gitbook.messages.options'),
749 'option' => $this->trans('application.gitbook.messages.option'),
750 'details' => $this->trans('application.gitbook.messages.details'),
751 'arguments' => $this->trans('application.gitbook.messages.arguments'),
752 'argument' => $this->trans('application.gitbook.messages.argument'),
753 'examples' => $this->trans('application.gitbook.messages.examples')
761 private function commandData($commandName)
763 if (!$this->has($commandName)) {
767 $command = $this->find($commandName);
769 $input = $command->getDefinition();
771 foreach ($input->getOptions() as $option) {
772 $options[$option->getName()] = [
773 'name' => $option->getName(),
774 'description' => $this->trans($option->getDescription()),
779 foreach ($input->getArguments() as $argument) {
780 $arguments[$argument->getName()] = [
781 'name' => $argument->getName(),
782 'description' => $this->trans($argument->getDescription()),
786 $commandKey = str_replace(':', '.', $command->getName());
789 for ($i = 0; $i < 5; $i++) {
790 $description = sprintf(
791 'commands.%s.examples.%s.description',
795 $execution = sprintf(
796 'commands.%s.examples.%s.execution',
801 if ($description != $this->trans($description)) {
803 'description' => $this->trans($description),
804 'execution' => $this->trans($execution)
812 'name' => $command->getName(),
813 'description' => $command->getDescription(),
814 'options' => $options,
815 'arguments' => $arguments,
816 'examples' => $examples,
817 'aliases' => $command->getAliases(),
818 'key' => $commandKey,
819 'dashed' => str_replace(':', '-', $command->getName()),
821 'usage' => $this->trans('application.gitbook.messages.usage'),
822 'options' => $this->trans('application.gitbook.messages.options'),
823 'option' => $this->trans('application.gitbook.messages.option'),
824 'details' => $this->trans('application.gitbook.messages.details'),
825 'arguments' => $this->trans('application.gitbook.messages.arguments'),
826 'argument' => $this->trans('application.gitbook.messages.argument'),
827 'examples' => $this->trans('application.gitbook.messages.examples')
835 * @return DrupalInterface
837 public function getDrupal()
839 return $this->drupal;
843 * @param DrupalInterface $drupal
845 public function setDrupal($drupal)
847 $this->drupal = $drupal;
850 public function setContainer($container)
852 $this->container = $container;
855 public function getContainer()
857 return $this->container;
861 * Add Drupal system messages.
863 protected function addDrupalMessages($messageManager) {
864 if (function_exists('drupal_get_messages')) {
865 $drupalMessages = drupal_get_messages();
866 foreach ($drupalMessages as $type => $messages) {
867 foreach ($messages as $message) {
868 $method = $this->getMessageMethod($type);
869 $messageManager->{$method}((string)$message);
876 * Gets method name for MessageManager.
878 * @param string $type
879 * Type of the message.
884 protected function getMessageMethod($type) {
885 $methodName = 'info';
897 * Finds a command by name or alias.
899 * @param string $name A command name or a command alias
901 * @return mixed A Command instance
903 * Override parent find method to avoid name collisions with automatically
904 * generated command abbreviations.
905 * Command name validation was previously done at doRun method.
907 public function find($name)
909 return $this->get($name);