86d08a10f990dcc4a446afddbab9e828f8312c56
[yaffs-website] / vendor / drupal / console-core / src / Application.php
1 <?php
2
3 namespace Drupal\Console\Core;
4
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;
28
29 /**
30  * Class Application
31  *
32  * @package Drupal\Console
33  */
34 class Application extends BaseApplication
35 {
36     /**
37      * @var ContainerInterface
38      */
39     protected $container;
40
41     /**
42      * @var string
43      */
44     protected $commandName;
45
46     /**
47      * @var DrupalInterface
48      */
49     protected $drupal;
50
51     /**
52      * @var bool
53      */
54     protected $eventRegistered;
55
56     /**
57      * ConsoleApplication constructor.
58      *
59      * @param ContainerInterface $container
60      * @param string             $name
61      * @param string             $version
62      */
63     public function __construct(
64         ContainerInterface $container,
65         $name,
66         $version
67     ) {
68         $this->container = $container;
69         $this->eventRegistered = false;
70         parent::__construct($name, $version);
71         $this->addOptions();
72     }
73
74     /**
75      * @return TranslatorManagerInterface
76      */
77     public function getTranslator()
78     {
79         if ($this->container) {
80             return $this->container->get('console.translator_manager');
81         }
82
83         return null;
84     }
85
86     /**
87      * @param $key string
88      *
89      * @return string
90      */
91     public function trans($key)
92     {
93         if ($this->getTranslator()) {
94             return $this->getTranslator()->trans($key);
95         }
96
97         return null;
98     }
99
100     /**
101      * {@inheritdoc}
102      */
103     public function doRun(InputInterface $input, OutputInterface $output)
104     {
105         $io = new DrupalStyle($input, $output);
106         $messageManager = $this->container->get('console.message_manager');
107         $this->commandName = $this->getCommandName($input)?:'list';
108
109         $clear = $this->container->get('console.configuration_manager')
110             ->getConfiguration()
111             ->get('application.clear')?:false;
112         if ($clear === true || $clear === 'true') {
113             $output->write(sprintf("\033\143"));
114         }
115
116         $this->loadCommands();
117
118         /**
119          * @var ConfigurationManager $configurationManager
120          */
121         $configurationManager = $this->container
122             ->get('console.configuration_manager');
123
124         if (!$this->has($this->commandName)) {
125             $isValidCommand = false;
126             $config = $configurationManager->getConfiguration();
127             $mappings = $config->get('application.commands.mappings');
128
129             if (array_key_exists($this->commandName, $mappings)) {
130                 $commandNameMap = $mappings[$this->commandName];
131                 $messageManager->warning(
132                     sprintf(
133                         $this->trans('application.errors.renamed-command'),
134                         $this->commandName,
135                         $commandNameMap
136                     )
137                 );
138                 $this->add(
139                     $this->find($commandNameMap)->setAliases([$this->commandName])
140                 );
141                 $isValidCommand = true;
142             }
143
144             $drushCommand = $configurationManager->readDrushEquivalents($this->commandName);
145             if ($drushCommand) {
146                 $this->add(
147                     $this->find($drushCommand)->setAliases([$this->commandName])
148                 );
149                 $isValidCommand = true;
150                 $messageManager->warning(
151                     sprintf(
152                         $this->trans('application.errors.drush-command'),
153                         $this->commandName,
154                         $drushCommand
155                     )
156                 );
157             }
158
159             $namespaces = $this->getNamespaces();
160             if (in_array($this->commandName, $namespaces)) {
161                 $input = new ArrayInput(
162                     [
163                         'command' => 'list',
164                         'namespace' => $this->commandName
165                     ]
166                 );
167                 $this->commandName = 'list';
168                 $isValidCommand = true;
169             }
170
171             if (!$isValidCommand) {
172                 $io->error(
173                     sprintf(
174                         $this->trans('application.errors.invalid-command'),
175                         $this->commandName
176                     )
177                 );
178
179                 return 1;
180             }
181         }
182
183         $code = parent::doRun(
184             $input,
185             $output
186         );
187
188         // Propagate Drupal messages.
189         $this->addDrupalMessages($messageManager);
190
191         if ($this->showMessages($input)) {
192             $messages = $messageManager->getMessages();
193
194             foreach ($messages as $message) {
195                 $showBy = $message['showBy'];
196                 if ($showBy!=='all' && $showBy!==$this->commandName) {
197                     continue;
198                 }
199                 $type = $message['type'];
200                 $io->$type($message['message']);
201             }
202         }
203
204
205         return $code;
206     }
207
208     public function loadCommands()
209     {
210         $this->registerGenerators();
211         $this->registerCommands();
212         $this->registerEvents();
213         $this->registerExtendCommands();
214
215         /**
216          * @var ConfigurationManager $configurationManager
217          */
218         $configurationManager = $this->container
219             ->get('console.configuration_manager');
220
221         $config = $configurationManager->getConfiguration()
222             ->get('application.extras.config')?:'true';
223         if ($config === 'true') {
224             $this->registerCommandsFromAutoWireConfiguration();
225         }
226
227         $chains = $configurationManager->getConfiguration()
228             ->get('application.extras.chains')?:'true';
229         if ($chains === 'true') {
230             $this->registerChainCommands();
231         }
232     }
233
234     /**
235      * @param InputInterface $input
236      *
237      * @return bool
238      */
239     private function showMessages(InputInterface $input)
240     {
241         $format = $input->hasOption('format')?$input->getOption('format'):'txt';
242
243         if ($format !== 'txt') {
244             return false;
245         }
246
247         return true;
248     }
249
250     /**
251      * registerEvents
252      */
253     private function registerEvents()
254     {
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')
261                 )
262             );
263             $dispatcher->addSubscriber(
264                 new ShowWelcomeMessageListener(
265                     $this->container->get('console.translator_manager')
266                 )
267             );
268             $dispatcher->addSubscriber(
269                 new DefaultValueEventListener(
270                     $this->container->get('console.configuration_manager')
271                 )
272             );
273             $dispatcher->addSubscriber(
274                 new ShowTipsListener(
275                     $this->container->get('console.translator_manager')
276                 )
277             );
278             $dispatcher->addSubscriber(
279                 new CallCommandListener(
280                     $this->container->get('console.chain_queue')
281                 )
282             );
283             $dispatcher->addSubscriber(
284                 new ShowGeneratedFilesListener(
285                     $this->container->get('console.file_queue'),
286                     $this->container->get('console.show_file')
287                 )
288             );
289             $dispatcher->addSubscriber(
290                 new ShowGenerateInlineListener(
291                     $this->container->get('console.translator_manager')
292                 )
293             );
294             $dispatcher->addSubscriber(
295                 new ShowGenerateChainListener(
296                     $this->container->get('console.translator_manager')
297                 )
298             );
299
300             $dispatcher->addSubscriber(
301                 new ShowGenerateCountCodeLinesListener(
302                     $this->container->get('console.translator_manager'),
303                     $this->container->get('console.count_code_lines')
304                 )
305             );
306
307             $dispatcher->addSubscriber(
308                 new RemoveMessagesListener(
309                     $this->container->get('console.message_manager')
310                 )
311             );
312
313             $this->setDispatcher($dispatcher);
314             $this->eventRegistered = true;
315         }
316     }
317
318     /**
319      * addOptions
320      */
321     private function addOptions()
322     {
323         // Get the configuration from config.yml.
324         $env = $this->container
325             ->get('console.configuration_manager')
326             ->getConfiguration()
327             ->get('application.environment');
328
329         $this->getDefinition()->addOption(
330             new InputOption(
331                 '--env',
332                 '-e',
333                 InputOption::VALUE_OPTIONAL,
334                 $this->trans('application.options.env'),
335                 !empty($env) ? $env : 'prod'
336             )
337         );
338         $this->getDefinition()->addOption(
339             new InputOption(
340                 '--root',
341                 null,
342                 InputOption::VALUE_OPTIONAL,
343                 $this->trans('application.options.root')
344             )
345         );
346         $this->getDefinition()->addOption(
347             new InputOption(
348                 '--debug',
349                 null,
350                 InputOption::VALUE_NONE,
351                 $this->trans('application.options.debug')
352             )
353         );
354         $this->getDefinition()->addOption(
355             new InputOption(
356                 '--learning',
357                 null,
358                 InputOption::VALUE_NONE,
359                 $this->trans('application.options.learning')
360             )
361         );
362         $this->getDefinition()->addOption(
363             new InputOption(
364                 '--generate-chain',
365                 '-c',
366                 InputOption::VALUE_NONE,
367                 $this->trans('application.options.generate-chain')
368             )
369         );
370         $this->getDefinition()->addOption(
371             new InputOption(
372                 '--generate-inline',
373                 '-i',
374                 InputOption::VALUE_NONE,
375                 $this->trans('application.options.generate-inline')
376             )
377         );
378         $this->getDefinition()->addOption(
379             new InputOption(
380                 '--generate-doc',
381                 '-d',
382                 InputOption::VALUE_NONE,
383                 $this->trans('application.options.generate-doc')
384             )
385         );
386         $this->getDefinition()->addOption(
387             new InputOption(
388                 '--target',
389                 '-t',
390                 InputOption::VALUE_OPTIONAL,
391                 $this->trans('application.options.target')
392             )
393         );
394         $this->getDefinition()->addOption(
395             new InputOption(
396                 '--uri',
397                 '-l',
398                 InputOption::VALUE_REQUIRED,
399                 $this->trans('application.options.uri')
400             )
401         );
402         $this->getDefinition()->addOption(
403             new InputOption(
404                 '--yes',
405                 '-y',
406                 InputOption::VALUE_NONE,
407                 $this->trans('application.options.yes')
408             )
409         );
410     }
411
412     /**
413      * registerCommands
414      */
415     private function registerCommands()
416     {
417         $consoleCommands = $this->container
418             ->findTaggedServiceIds('drupal.command');
419
420         $aliases = $this->container->get('console.configuration_manager')
421             ->getConfiguration()
422             ->get('application.commands.aliases')?:[];
423
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', []);
429         }
430
431         foreach ($consoleCommands as $name => $tags) {
432             if (in_array($name, $invalidCommands)) {
433                 continue;
434             }
435
436             if (!$this->container->has($name)) {
437                 continue;
438             }
439
440             try {
441                 $command = $this->container->get($name);
442             } catch (\Exception $e) {
443                 echo $name . ' - ' . $e->getMessage() . PHP_EOL;
444
445                 continue;
446             }
447
448             if (!$command) {
449                 continue;
450             }
451
452             if (method_exists($command, 'setTranslator')) {
453                 $command->setTranslator(
454                     $this->container->get('console.translator_manager')
455                 );
456             }
457
458             if (method_exists($command, 'setContainer')) {
459                 $command->setContainer(
460                     $this->container->get('service_container')
461                 );
462             }
463
464             if (array_key_exists($command->getName(), $aliases)) {
465                 $commandAliases = $aliases[$command->getName()];
466                 if (!is_array($commandAliases)) {
467                     $commandAliases = [$commandAliases];
468                 }
469                 $commandAliases = array_merge(
470                     $command->getAliases(),
471                     $commandAliases
472                 );
473                 $command->setAliases($commandAliases);
474             }
475
476             $this->add($command);
477         }
478     }
479
480     /**
481      * registerGenerators
482      */
483     private function registerGenerators()
484     {
485         $consoleGenerators = $this->container
486             ->findTaggedServiceIds('drupal.generator');
487
488         foreach ($consoleGenerators as $name => $tags) {
489             if (!$this->container->has($name)) {
490                 continue;
491             }
492
493             try {
494                 $generator = $this->container->get($name);
495             } catch (\Exception $e) {
496                 echo $name . ' - ' . $e->getMessage() . PHP_EOL;
497
498                 continue;
499             }
500
501             if (!$generator) {
502                 continue;
503             }
504             if (method_exists($generator, 'setRenderer')) {
505                 $generator->setRenderer(
506                     $this->container->get('console.renderer')
507                 );
508             }
509
510             if (method_exists($generator, 'setFileQueue')) {
511                 $generator->setFileQueue(
512                     $this->container->get('console.file_queue')
513                 );
514             }
515
516             if (method_exists($generator, 'setCountCodeLines')) {
517                 $generator->setCountCodeLines(
518                     $this->container->get('console.count_code_lines')
519                 );
520             }
521
522             if (method_exists($generator, 'setDrupalFinder')) {
523                 $generator->setDrupalFinder(
524                     $this->container->get('console.drupal_finder')
525                 );
526             }
527         }
528     }
529
530     /**
531      * registerCommandsFromAutoWireConfiguration
532      */
533     private function registerCommandsFromAutoWireConfiguration()
534     {
535         $configuration = $this->container->get('console.configuration_manager')
536             ->getConfiguration();
537
538         $autoWireForcedCommands = $configuration
539             ->get('application.autowire.commands.forced');
540
541         if (!is_array($autoWireForcedCommands)) {
542             return;
543         }
544
545         foreach ($autoWireForcedCommands as $autoWireForcedCommand) {
546             try {
547                 if (!$autoWireForcedCommand['class']) {
548                     continue;
549                 }
550
551                 $reflectionClass = new \ReflectionClass(
552                     $autoWireForcedCommand['class']
553                 );
554
555                 $arguments = [];
556                 if (array_key_exists('arguments', $autoWireForcedCommand)) {
557                     foreach ($autoWireForcedCommand['arguments'] as $argument) {
558                         $argument = substr($argument, 1);
559                         $arguments[] = $this->container->get($argument);
560                     }
561                 }
562
563                 $command = $reflectionClass->newInstanceArgs($arguments);
564
565                 if (method_exists($command, 'setTranslator')) {
566                     $command->setTranslator(
567                         $this->container->get('console.translator_manager')
568                     );
569                 }
570                 if (method_exists($command, 'setContainer')) {
571                     $command->setContainer(
572                         $this->container->get('service_container')
573                     );
574                 }
575
576                 $this->add($command);
577             } catch (\Exception $e) {
578                 echo $e->getMessage() . PHP_EOL;
579                 continue;
580             }
581         }
582
583         $autoWireNameCommand = $configuration->get(
584             sprintf(
585                 'application.autowire.commands.name.%s',
586                 $this->commandName
587             )
588         );
589
590         if ($autoWireNameCommand) {
591             try {
592                 $arguments = [];
593                 if (array_key_exists('arguments', $autoWireNameCommand)) {
594                     foreach ($autoWireNameCommand['arguments'] as $argument) {
595                         $argument = substr($argument, 1);
596                         $arguments[] = $this->container->get($argument);
597                     }
598                 }
599
600                 $reflectionClass = new \ReflectionClass(
601                     $autoWireNameCommand['class']
602                 );
603                 $command = $reflectionClass->newInstanceArgs($arguments);
604
605                 if (method_exists($command, 'setTranslator')) {
606                     $command->setTranslator(
607                         $this->container->get('console.translator_manager')
608                     );
609                 }
610                 if (method_exists($command, 'setContainer')) {
611                     $command->setContainer(
612                         $this->container->get('service_container')
613                     );
614                 }
615
616                 $this->add($command);
617             } catch (\Exception $e) {
618                 echo $e->getMessage() . PHP_EOL;
619             }
620         }
621     }
622
623     /**
624      * registerChainCommands
625      */
626     public function registerChainCommands()
627     {
628         /**
629          * @var ChainDiscovery $chainDiscovery
630          */
631         $chainDiscovery = $this->container->get('console.chain_discovery');
632         $chainCommands = $chainDiscovery->getChainCommands();
633
634         foreach ($chainCommands as $name => $chainCommand) {
635             try {
636                 $file = $chainCommand['file'];
637                 $description = $chainCommand['description'];
638                 $command = new ChainCustomCommand(
639                     $name,
640                     $description,
641                     $file,
642                     $chainDiscovery
643                 );
644                 $this->add($command);
645             } catch (\Exception $e) {
646                 echo $e->getMessage() . PHP_EOL;
647             }
648         }
649     }
650
651     /**
652      * registerExtendCommands
653      */
654     private function registerExtendCommands()
655     {
656         $this->container->get('console.configuration_manager')
657             ->loadExtendConfiguration();
658     }
659
660     public function getData()
661     {
662         $singleCommands = [
663             'about',
664             'chain',
665             'check',
666             'composerize',
667             'exec',
668             'help',
669             'init',
670             'list',
671             'shell',
672             'server'
673         ];
674
675         $languages = $this->container->get('console.configuration_manager')
676             ->getConfiguration()
677             ->get('application.languages');
678
679         $data = [];
680         foreach ($singleCommands as $singleCommand) {
681             $data['commands']['misc'][] = $this->commandData($singleCommand);
682         }
683
684         $namespaces = array_filter(
685             $this->getNamespaces(), function ($item) {
686                 return (strpos($item, ':')<=0);
687             }
688         );
689         sort($namespaces);
690         array_unshift($namespaces, 'misc');
691
692         foreach ($namespaces as $namespace) {
693             $commands = $this->all($namespace);
694             usort(
695                 $commands, function ($cmd1, $cmd2) {
696                     return strcmp($cmd1->getName(), $cmd2->getName());
697                 }
698             );
699
700             foreach ($commands as $command) {
701                 if (method_exists($command, 'getModule')) {
702                     if ($command->getModule() == 'Console') {
703                         $data['commands'][$namespace][] = $this->commandData(
704                             $command->getName()
705                         );
706                     }
707                 } else {
708                     $data['commands'][$namespace][] = $this->commandData(
709                         $command->getName()
710                     );
711                 }
712             }
713         }
714
715         $input = $this->getDefinition();
716         $options = [];
717         foreach ($input->getOptions() as $option) {
718             $options[] = [
719                 'name' => $option->getName(),
720                 'description' => $this->trans('application.options.'.$option->getName())
721             ];
722         }
723         $arguments = [];
724         foreach ($input->getArguments() as $argument) {
725             $arguments[] = [
726                 'name' => $argument->getName(),
727                 'description' => $this->trans('application.arguments.'.$argument->getName())
728             ];
729         }
730
731         $data['application'] = [
732             'namespaces' => $namespaces,
733             'options' => $options,
734             'arguments' => $arguments,
735             'languages' => $languages,
736             'messages' => [
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')
747             ],
748             'examples' => []
749         ];
750
751         return $data;
752     }
753
754     private function commandData($commandName)
755     {
756         if (!$this->has($commandName)) {
757             return [];
758         }
759
760         $command = $this->find($commandName);
761
762         $input = $command->getDefinition();
763         $options = [];
764         foreach ($input->getOptions() as $option) {
765             $options[$option->getName()] = [
766                 'name' => $option->getName(),
767                 'description' => $this->trans($option->getDescription()),
768             ];
769         }
770
771         $arguments = [];
772         foreach ($input->getArguments() as $argument) {
773             $arguments[$argument->getName()] = [
774                 'name' => $argument->getName(),
775                 'description' => $this->trans($argument->getDescription()),
776             ];
777         }
778
779         $commandKey = str_replace(':', '.', $command->getName());
780
781         $examples = [];
782         for ($i = 0; $i < 5; $i++) {
783             $description = sprintf(
784                 'commands.%s.examples.%s.description',
785                 $commandKey,
786                 $i
787             );
788             $execution = sprintf(
789                 'commands.%s.examples.%s.execution',
790                 $commandKey,
791                 $i
792             );
793
794             if ($description != $this->trans($description)) {
795                 $examples[] = [
796                     'description' => $this->trans($description),
797                     'execution' => $this->trans($execution)
798                 ];
799             } else {
800                 break;
801             }
802         }
803
804         $data = [
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()),
813             'messages' => [
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')
821             ],
822         ];
823
824         return $data;
825     }
826
827     /**
828      * @return DrupalInterface
829      */
830     public function getDrupal()
831     {
832         return $this->drupal;
833     }
834
835     /**
836      * @param DrupalInterface $drupal
837      */
838     public function setDrupal($drupal)
839     {
840         $this->drupal = $drupal;
841     }
842
843     public function setContainer($container)
844     {
845         $this->container = $container;
846     }
847
848     public function getContainer()
849     {
850         return $this->container;
851     }
852
853     /**
854      * Add Drupal system messages.
855      */
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);
863                 }
864             }
865         }
866     }
867
868     /**
869      * Gets method name for MessageManager.
870      *
871      * @param string $type
872      *   Type of the message.
873      *
874      * @return string
875      *   Name of the method
876      */
877     protected function getMessageMethod($type) {
878         $methodName = 'info';
879         switch ($type) {
880             case 'error':
881             case 'warning':
882                 $methodName = $type;
883                 break;
884         }
885
886         return $methodName;
887     }
888
889     /**
890      * Finds a command by name or alias.
891      *
892      * @param string $name A command name or a command alias
893      *
894      * @return mixed A Command instance
895      *
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.
899      */
900     public function find($name)
901     {
902         return $this->get($name);
903     }
904 }