ApplicationFactory.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * This file is part of Hyperf.
  5. *
  6. * @link https://www.hyperf.io
  7. * @document https://hyperf.wiki
  8. * @contact group@hyperf.io
  9. * @license https://github.com/hyperf/hyperf/blob/master/LICENSE
  10. */
  11. namespace Hyperf\Framework;
  12. use Hyperf\Command\Annotation\Command;
  13. use Hyperf\Command\Parser;
  14. use Hyperf\Contract\ConfigInterface;
  15. use Hyperf\Di\Annotation\AnnotationCollector;
  16. use Hyperf\Framework\Event\BootApplication;
  17. use InvalidArgumentException;
  18. use Psr\Container\ContainerInterface;
  19. use Psr\EventDispatcher\EventDispatcherInterface;
  20. use Symfony\Component\Console\Application;
  21. use Symfony\Component\Console\Command\Command as SymfonyCommand;
  22. use Symfony\Component\Console\Exception\InvalidArgumentException as SymfonyInvalidArgumentException;
  23. use Symfony\Component\Console\Exception\LogicException;
  24. use Symfony\Component\Console\Input\InputArgument;
  25. use Symfony\Component\Console\Input\InputOption;
  26. class ApplicationFactory
  27. {
  28. public function __invoke(ContainerInterface $container)
  29. {
  30. if ($container->has(EventDispatcherInterface::class)) {
  31. $eventDispatcher = $container->get(EventDispatcherInterface::class);
  32. $eventDispatcher->dispatch(new BootApplication());
  33. }
  34. $config = $container->get(ConfigInterface::class);
  35. $commands = $config->get('commands', []);
  36. // Append commands that defined by annotation.
  37. $annotationCommands = [];
  38. if (class_exists(AnnotationCollector::class) && class_exists(Command::class)) {
  39. $annotationCommands = AnnotationCollector::getClassesByAnnotation(Command::class);
  40. $annotationCommands = array_keys($annotationCommands);
  41. }
  42. $commands = array_unique(array_merge($commands, $annotationCommands));
  43. $application = new Application();
  44. if ($config->get('symfony.event.enable', false) && isset($eventDispatcher) && class_exists(SymfonyEventDispatcher::class)) {
  45. $application->setDispatcher(new SymfonyEventDispatcher($eventDispatcher));
  46. }
  47. foreach ($commands as $command) {
  48. $application->add(
  49. $this->pendingCommand($container->get($command))
  50. );
  51. }
  52. return $application;
  53. }
  54. /**
  55. * @throws InvalidArgumentException
  56. * @throws SymfonyInvalidArgumentException
  57. * @throws LogicException
  58. */
  59. protected function pendingCommand(SymfonyCommand $command): SymfonyCommand
  60. {
  61. /** @var null|Command $annotation */
  62. $annotation = AnnotationCollector::getClassAnnotation($command::class, Command::class) ?? null;
  63. if (! $annotation) {
  64. return $command;
  65. }
  66. if ($annotation->signature) {
  67. [$name, $arguments, $options] = Parser::parse($annotation->signature);
  68. if ($name) {
  69. $annotation->name = $name;
  70. }
  71. if ($arguments) {
  72. $annotation->arguments = array_merge($annotation->arguments, $arguments);
  73. }
  74. if ($options) {
  75. $annotation->options = array_merge($annotation->options, $options);
  76. }
  77. }
  78. if ($annotation->name) {
  79. $command->setName($annotation->name);
  80. }
  81. if ($annotation->arguments) {
  82. $annotation->arguments = array_map(static function ($argument): InputArgument {
  83. if ($argument instanceof InputArgument) {
  84. return $argument;
  85. }
  86. if (is_array($argument)) {
  87. return new InputArgument(...$argument);
  88. }
  89. throw new LogicException(sprintf('Invalid argument type: %s.', gettype($argument)));
  90. }, $annotation->arguments);
  91. $command->getDefinition()->addArguments($annotation->arguments);
  92. }
  93. if ($annotation->options) {
  94. $annotation->options = array_map(static function ($option): InputOption {
  95. if ($option instanceof InputOption) {
  96. return $option;
  97. }
  98. if (is_array($option)) {
  99. return new InputOption(...$option);
  100. }
  101. throw new LogicException(sprintf('Invalid option type: %s.', gettype($option)));
  102. }, $annotation->options);
  103. $command->getDefinition()->addOptions($annotation->options);
  104. }
  105. if ($annotation->description) {
  106. $command->setDescription($annotation->description);
  107. }
  108. if ($annotation->aliases) {
  109. $command->setAliases($annotation->aliases);
  110. }
  111. return $command;
  112. }
  113. }