|
2 | 2 |
|
3 | 3 | namespace Drush\Commands; |
4 | 4 |
|
| 5 | +use Drupal\Component\DependencyInjection\ContainerInterface as DrupalContainer; |
| 6 | +use Drush\Drush; |
| 7 | +use League\Container\Container as DrushContainer; |
5 | 8 | use Psr\Container\ContainerInterface; |
6 | 9 | use Symfony\Component\DependencyInjection\Attribute\Autowire; |
7 | 10 | use Symfony\Component\DependencyInjection\Exception\AutowiringFailedException; |
|
16 | 19 | */ |
17 | 20 | trait AutowireTrait |
18 | 21 | { |
19 | | - /** |
| 22 | + /** |
| 23 | + * Limit to service and param or plain value. |
| 24 | + * |
| 25 | + * @see \Symfony\Component\DependencyInjection\Attribute\Autowire::__construct |
| 26 | + */ |
| 27 | + private const ACCEPTED_AUTOWIRE_ARGUMENTS = [ |
| 28 | + 0 => 'value', |
| 29 | + 1 => 'service', |
| 30 | + 4 => 'param', |
| 31 | + ]; |
| 32 | + |
| 33 | + /** |
20 | 34 | * Instantiates a new instance of the implementing class using autowiring. |
21 | 35 | * |
22 | 36 | * @param ContainerInterface $container |
23 | 37 | * The service container this instance should use. |
24 | 38 | * |
25 | 39 | * @return static |
26 | 40 | */ |
27 | | - public static function create(ContainerInterface $container) |
| 41 | + public static function create(ContainerInterface $container, ?ContainerInterface $drushContainer = null) |
28 | 42 | { |
29 | 43 | $args = []; |
30 | 44 |
|
31 | 45 | if (method_exists(static::class, '__construct')) { |
| 46 | + $drushContainer = $container instanceof DrushContainer ? $container : ($drushContainer instanceof DrushContainer ? $drushContainer : Drush::getContainer()); |
| 47 | + $drupalContainer = $container instanceof DrupalContainer ? $container : null; |
| 48 | + |
32 | 49 | $constructor = new \ReflectionMethod(static::class, '__construct'); |
33 | 50 | foreach ($constructor->getParameters() as $parameter) { |
34 | | - $service = ltrim((string) $parameter->getType(), '?'); |
35 | | - foreach ($parameter->getAttributes(Autowire::class) as $attribute) { |
36 | | - $service = (string) $attribute->newInstance()->value; |
| 51 | + if (!$attributes = $parameter->getAttributes(Autowire::class)) { |
| 52 | + // No #[Autowire()] attribute. |
| 53 | + $service = ltrim((string) $parameter->getType(), '?'); |
| 54 | + if (!$drushContainer->has($service)) { |
| 55 | + throw new AutowiringFailedException($service, sprintf('Cannot autowire service "%s": argument "$%s" of method "%s::_construct()", you should configure its value explicitly.', $service, $parameter->getName(), static::class)); |
| 56 | + } |
| 57 | + $args[] = $drushContainer->get($service); |
| 58 | + continue; |
37 | 59 | } |
38 | 60 |
|
39 | | - if (!$container->has($service)) { |
40 | | - throw new AutowiringFailedException($service, sprintf('Cannot autowire service "%s": argument "$%s" of method "%s::_construct()", you should configure its value explicitly.', $service, $parameter->getName(), static::class)); |
41 | | - } |
| 61 | + // This parameter has an #[Autowire()] attribute. |
| 62 | + [$attribute] = $attributes; |
| 63 | + $value = null; |
| 64 | + foreach ($attribute->getArguments() as $key => $argument) { |
| 65 | + // Resolve argument name when arguments are passed as list. |
| 66 | + if (is_int($key)) { |
| 67 | + if ($argument === null || !isset(self::ACCEPTED_AUTOWIRE_ARGUMENTS[$key])) { |
| 68 | + continue; |
| 69 | + } |
| 70 | + $key = self::ACCEPTED_AUTOWIRE_ARGUMENTS[$key]; |
| 71 | + } |
| 72 | + |
| 73 | + if (!in_array($key, self::ACCEPTED_AUTOWIRE_ARGUMENTS, true)) { |
| 74 | + continue; |
| 75 | + } |
42 | 76 |
|
43 | | - $args[] = $container->get($service); |
| 77 | + $value = $attribute->newInstance()->value; |
| 78 | + $valueAsString = (string) $value; |
| 79 | + $value = match ($key) { |
| 80 | + 'service' => $drushContainer->has($valueAsString) ? $drushContainer->get($valueAsString) : throw new AutowiringFailedException($valueAsString, sprintf('Cannot autowire service "%s": argument "$%s" of method "%s::_construct()", you should configure its value explicitly.', $valueAsString, $parameter->getName(), static::class)), |
| 81 | + // Container param comes as %foo.bar.param%. |
| 82 | + 'param' => $drupalContainer ? $drupalContainer->getParameter(trim($valueAsString, '%')) : $valueAsString, |
| 83 | + default => $value, |
| 84 | + }; |
| 85 | + // Done as Autowire::__construct() only needs one argument. |
| 86 | + break; |
| 87 | + } |
| 88 | + if ($value !== null) { |
| 89 | + $args[] = $value; |
| 90 | + } |
44 | 91 | } |
45 | 92 | } |
46 | 93 |
|
|
0 commit comments