Skip to content

[DependencyInjection] #[AutowireServiceClosure] does not work together with #[Target] #50634

@ruudk

Description

@ruudk

Symfony version(s) affected

6.3.0

Description

The new #[AutowireServiceClosure] attribute introduced in #49628 by @nicolas-grekas does not seem to work together with #[Target].

In CheckExceptionOnInvalidReferenceBehaviorPass.php line 86:

  The service "MyExtension" has a dependency on a non-existent service "MyCache". 

How to reproduce

class MyExtension
{
    public function __construct(
        #[AutowireServiceClosure(MyService::class)]
        private Closure $myService,
        #[Target('myTargetName')]
        #[AutowireServiceClosure(MyCache::class)]
        private Closure $cache,
    ) {}
}

Possible Solution

I tried debugging it but couldn't get it to work. I feel we should add a new condition here:

if ($attribute instanceof AutowireCallable) {
$value = (new Definition($type = \is_string($attribute->lazy) ? $attribute->lazy : ($type ?: 'Closure')))
->setFactory(['Closure', 'fromCallable'])
->setArguments([\is_array($value) ? $value + [1 => '__invoke'] : $value])
->setLazy($attribute->lazy || 'Closure' !== $type && 'callable' !== (string) $parameter->getType());
} elseif ($lazy = $attribute->lazy) {
$definition = (new Definition($type))
->setFactory('current')
->setArguments([[$value ??= $getValue()]])
->setLazy(true);
if (!\is_array($lazy)) {
if (str_contains($type, '|')) {
throw new AutowiringFailedException($this->currentId, sprintf('Cannot use #[Autowire] with option "lazy: true" on union types for service "%s"; set the option to the interface(s) that should be proxied instead.', $this->currentId));
}
$lazy = str_contains($type, '&') ? explode('&', $type) : [];
}
if ($lazy) {
if (!class_exists($type) && !interface_exists($type, false)) {
$definition->setClass('object');
}
foreach ($lazy as $v) {
$definition->addTag('proxy', ['interface' => $v]);
}
}
if ($definition->getClass() !== (string) $value || $definition->getTag('proxy')) {
$value .= '.'.$this->container->hash([$definition->getClass(), $definition->getTag('proxy')]);
}
$this->container->setDefinition($value = '.lazy.'.$value, $definition);
$value = new Reference($value);
}
$arguments[$index] = $value;

I tried adding:

} elseif ($attribute instanceof AutowireServiceClosure && $target !== []) {
    $arguments[$index] = $getValue();
}        

but that resulted in

In DefinitionErrorExceptionPass.php line 51:

  [Symfony\Component\DependencyInjection\Exception\RuntimeException]
  Cannot autowire service "MyExtension": "#[Target('myTargetName')" on argument "$cache" of method "__construct()"

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions