ParameterParser.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  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\Command;
  12. use Closure;
  13. use Hyperf\Contract\NormalizerInterface;
  14. use Hyperf\Di\ClosureDefinitionCollectorInterface;
  15. use Hyperf\Di\MethodDefinitionCollectorInterface;
  16. use Hyperf\Stringable\Str;
  17. use InvalidArgumentException;
  18. use Psr\Container\ContainerInterface;
  19. use Symfony\Component\Console\Input\InputOption;
  20. class ParameterParser
  21. {
  22. private NormalizerInterface $normalizer;
  23. private ?ClosureDefinitionCollectorInterface $closureDefinitionCollector = null;
  24. private ?MethodDefinitionCollectorInterface $methodDefinitionCollector = null;
  25. public function __construct(private ContainerInterface $container)
  26. {
  27. $this->normalizer = $this->container->get(NormalizerInterface::class);
  28. if ($this->container->has(ClosureDefinitionCollectorInterface::class)) {
  29. $this->closureDefinitionCollector = $this->container->get(ClosureDefinitionCollectorInterface::class);
  30. }
  31. if ($this->container->has(MethodDefinitionCollectorInterface::class)) {
  32. $this->methodDefinitionCollector = $this->container->get(MethodDefinitionCollectorInterface::class);
  33. }
  34. }
  35. public function parseClosureParameters(Closure $closure, array $arguments): array
  36. {
  37. if (! $this->closureDefinitionCollector) {
  38. return [];
  39. }
  40. $definitions = $this->closureDefinitionCollector->getParameters($closure);
  41. return $this->getInjections($definitions, 'Closure', $arguments);
  42. }
  43. public function parseMethodParameters(string $class, string $method, array $arguments): array
  44. {
  45. if (! $this->methodDefinitionCollector) {
  46. return [];
  47. }
  48. $definitions = $this->methodDefinitionCollector->getParameters($class, $method);
  49. return $this->getInjections($definitions, "{$class}::{$method}", $arguments);
  50. }
  51. /**
  52. * @return InputOption[]
  53. */
  54. public function parseClosureOptions(Closure $closure): array
  55. {
  56. if (! $this->closureDefinitionCollector) {
  57. return [];
  58. }
  59. $definitions = $this->closureDefinitionCollector->getParameters($closure);
  60. $options = [];
  61. foreach ($definitions as $definition) {
  62. $type = $definition->getName();
  63. if (! in_array($type, ['int', 'float', 'string', 'bool'])) {
  64. continue;
  65. }
  66. $name = $definition->getMeta('name');
  67. $mode = $definition->allowsNull() ? InputOption::VALUE_OPTIONAL : InputOption::VALUE_REQUIRED;
  68. $default = $definition->getMeta('defaultValue');
  69. $options[] = new InputOption($name, null, $mode, '', $default, []);
  70. }
  71. return $options;
  72. }
  73. /**
  74. * @return InputOption[]
  75. */
  76. public function parseMethodOptions(string $class, string $method): array
  77. {
  78. if (! $this->methodDefinitionCollector) {
  79. return [];
  80. }
  81. $definitions = $this->methodDefinitionCollector->getParameters($class, $method);
  82. $options = [];
  83. foreach ($definitions as $definition) {
  84. $type = $definition->getName();
  85. if (! in_array($type, ['int', 'float', 'string', 'bool'])) {
  86. continue;
  87. }
  88. $name = $definition->getMeta('name');
  89. $mode = $definition->allowsNull() ? InputOption::VALUE_OPTIONAL : InputOption::VALUE_REQUIRED;
  90. $default = $definition->getMeta('defaultValue');
  91. $options[] = new InputOption($name, null, $mode, '', $default, []);
  92. }
  93. return $options;
  94. }
  95. private function getInjections(array $definitions, string $callableName, array $arguments): array
  96. {
  97. $injections = [];
  98. foreach ($definitions as $pos => $definition) {
  99. $value = $arguments[$pos] ?? $arguments[$definition->getMeta('name')] ?? $arguments[Str::snake($definition->getMeta('name'), '-')] ?? null;
  100. if ($value === null) {
  101. if ($definition->getMeta('defaultValueAvailable')) {
  102. $injections[] = $definition->getMeta('defaultValue');
  103. } elseif ($this->container->has($definition->getName())) {
  104. $injections[] = $this->container->get($definition->getName());
  105. } elseif ($definition->allowsNull()) {
  106. $injections[] = null;
  107. } else {
  108. throw new InvalidArgumentException("Parameter '{$definition->getMeta('name')}' "
  109. . "of {$callableName} should not be null");
  110. }
  111. } else {
  112. $injections[] = $this->normalizer->denormalize($value, $definition->getName());
  113. }
  114. }
  115. return $injections;
  116. }
  117. }