Skip to content

[DependencyInjection] Attribute #[Target()] does not work #54578

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
lkolndeep opened this issue Apr 12, 2024 · 6 comments
Closed

[DependencyInjection] Attribute #[Target()] does not work #54578

lkolndeep opened this issue Apr 12, 2024 · 6 comments

Comments

@lkolndeep
Copy link

Symfony version(s) affected

6.4.6

Description

Hello,

When I tested the #[Target] attribute feature that you can see in the docs here: Target attribute docs, it does not work.

Thanks in advance,

How to reproduce

I created a project which contains:

  • two services which implements an interface
  • one global service which takes the interface as a parameter to test the Target attribute feature
  • a controller with a route which takes a string as a parameter

Here the link of the project: bug_app You will find some comments explaining the bug in the NotificationSender service.

Possible Solution

No response

Additional Context

No response

@smnandre
Copy link
Member

I think your service may not be defined as an alias but as a service.. Maybe try using "alias" instead of "class" in your services.yaml ?

https://symfony.com/doc/current/service_container/alias_private.html#aliasing

@lkolndeep
Copy link
Author

Hello @smnandre ,

I changed a little the service.yaml file as you advised and I also uncomment this line App\Interface\MessageInterface $notification: '@app.message.message_second' to test the second service without the Target feature.

app.message.message_first: '@App\Service\MessageFirst'
app.message.message_second: '@App\Service\MessageSecond'

# Default used service
App\Interface\MessageInterface: '@app.message.message_first'

# Called service if we use the $notification variable (put here to compare with the Target attribute feature)
App\Interface\MessageInterface $notification: '@app.message.message_second'

App\Service\NotificationSender:
    autowire: true

In the NotificationSender class, I changed the variable for the parameter type MessageInterface to $notification to test if the second service is taking into account.

Without the Target attribute feature in the NotificationSender, everything works well. The two services are taking into account depending on commenting/uncommenting this line App\Interface\MessageInterface $notification: '@app.message.message_second' in the service.yaml.

So, our change in the services.yaml is OK. Now, I test the Target attribute feature:

First case:

Now, I suppose I comment this line in the yaml file: # App\Interface\MessageInterface $notification: '@app.message.message_second'

When I add the Target attribute in the NoficationSender class with the first service, it still doesn't work:

class NotificationSender
{
    public function __construct(
        #[Target('app.message.message_first')]
        private MessageInterface $notification
    ){
    }

    public function send(string $word): string
    {
        $sentence = $this->notification->show($word);

        return $sentence;
    }
}

I have this error:

Cannot resolve argument $notificationSender of "App\Controller\WelcomeController::showMessage()": Cannot autowire service "App\Service\NotificationSender": argument "$notification" of method "__construct()" has "#[Target('app.message.message_first')]" but no such target exists. You should maybe alias this interface to one of these existing services: "App\Service\MessageFirst", "App\Service\MessageSecond".

When I try the second service with: #[Target('app.message.message_second')], it does not work too:

Cannot resolve argument $notificationSender of "App\Controller\WelcomeController::showMessage()": Cannot autowire service "App\Service\NotificationSender": argument "$notification" of method "__construct()" has "#[Target('app.message.message_second')]" but no such target exists. You should maybe alias this interface to one of these existing services: "App\Service\MessageFirst", "App\Service\MessageSecond".

Second case:

I uncomment this line in the yaml file: App\Interface\MessageInterface $notification: '@app.message.message_second' and I test the first service with: #[Target('app.message.message_first')]. I does not work:

Cannot resolve argument $notificationSender of "App\Controller\WelcomeController::showMessage()": Cannot autowire service "App\Service\NotificationSender": argument "$notification" of method "__construct()" has "#[Target('app.message.message_first')]" but no such target exists. Did you mean to target "notification" instead?

I tested the second service with #[Target('app.message.message_second')] and it does not work too:

Cannot resolve argument $notificationSender of "App\Controller\WelcomeController::showMessage()": Cannot autowire service "App\Service\NotificationSender": argument "$notification" of method "__construct()" has "#[Target('app.message.message_second')]" but no such target exists. Did you mean to target "notification" instead?

Regards,

@lkolndeep lkolndeep closed this as not planned Won't fix, can't repro, duplicate, stale Apr 13, 2024
@lkolndeep lkolndeep reopened this Apr 13, 2024
@smnandre
Copy link
Member

Try with #[Autowire(service: 'app.message.message_second')] instead of Target(...)

@lkolndeep
Copy link
Author

I tested #[Autowire(service: 'app.message.message_second')] and even #[Autowire(service: 'app.message.message_first')]. Both work well.

@HypeMC
Copy link
Contributor

HypeMC commented Apr 14, 2024

The #[Target] attribute doesn't work with service IDs or aliases, it expects the name of the parameter of the named alias. See https://symfony.com/blog/new-in-symfony-4-2-autowiring-by-type-and-name.

In your case, that would look something like this:

services:
    App\Interface\MessageInterface $firstMessage: '@App\Service\MessageFirst'
    App\Interface\MessageInterface $secondMessage: '@App\Service\MessageSecond'
public function __construct(
    #[Target('secondMessage')]
    private MessageInterface $message
) {
}

@lkolndeep
Copy link
Author

@HypeMC Thank you very much. Now, it works!

@xabbuh xabbuh closed this as not planned Won't fix, can't repro, duplicate, stale Apr 14, 2024
javiereguiluz added a commit to symfony/symfony-docs that referenced this issue Jun 24, 2024
…(HypeMC)

This PR was merged into the 5.4 branch.

Discussion
----------

[DependencyInjection] Clarify the `#[Target]` attribute

The `#[Target]` attribute seems to be a constant source of confusion for developers, as evident by:

- symfony/symfony#50541
- symfony/symfony#51565
- symfony/symfony#54578

Also, the example given is either unclear or just wrong. Hopefully, this helps clarify things.

Commits
-------

2fb1ada [DependencyInjection] Clarify the `#[Target]` attribute
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants