ParameterParser.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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. return $this->extractedOptions($definitions);
  61. }
  62. /**
  63. * @return InputOption[]
  64. */
  65. public function parseMethodOptions(string $class, string $method): array
  66. {
  67. if (! $this->methodDefinitionCollector) {
  68. return [];
  69. }
  70. $definitions = $this->methodDefinitionCollector->getParameters($class, $method);
  71. return $this->extractedOptions($definitions);
  72. }
  73. public function extractedOptions(array $definitions): array
  74. {
  75. $options = [];
  76. foreach ($definitions as $definition) {
  77. $type = $definition->getName();
  78. if (! in_array($type, ['int', 'float', 'string', 'bool'])) {
  79. continue;
  80. }
  81. $name = $definition->getMeta('name');
  82. $mode = $definition->allowsNull() ? InputOption::VALUE_OPTIONAL : InputOption::VALUE_REQUIRED;
  83. $default = $definition->getMeta('defaultValue');
  84. $options[] = new InputOption($name, null, $mode, '', $default, []);
  85. }
  86. return $options;
  87. }
  88. private function getInjections(array $definitions, string $callableName, array $arguments): array
  89. {
  90. $injections = [];
  91. foreach ($definitions as $pos => $definition) {
  92. $value = $arguments[$pos] ?? $arguments[$definition->getMeta('name')] ?? $arguments[Str::snake($definition->getMeta('name'), '-')] ?? null;
  93. if ($value === null) {
  94. if ($definition->getMeta('defaultValueAvailable')) {
  95. $injections[] = $definition->getMeta('defaultValue');
  96. } elseif ($this->container->has($definition->getName())) {
  97. $injections[] = $this->container->get($definition->getName());
  98. } elseif ($definition->allowsNull()) {
  99. $injections[] = null;
  100. } else {
  101. throw new InvalidArgumentException("Parameter '{$definition->getMeta('name')}' "
  102. . "of {$callableName} should not be null");
  103. }
  104. } else {
  105. $injections[] = $this->normalizer->denormalize($value, $definition->getName());
  106. }
  107. }
  108. return $injections;
  109. }
  110. }