Using service aliases for dependency injection

2020-04-08 01:22发布

In my application I have an SMS service. This service is a simple POPO that takes an instance to a driver to do the actual SMS functionality.

Imagine I have two drivers, mock_driver and gateway_driver which are defined as something like this in the services section:

mock_driver:
    class: MyApp\Service\Sms\MockDriver

gateway_driver:
    class: MyApp\Service\Sms\GatewayDriver
    calls:
        - [setConfig, ["%gateway_user%", "%gateway_password%", "%gateway_endpoint%"]]

And the SMS service is defined like this:

service_sms:
    class: MyApp\Service\SmsService
    calls:
        - [setDriver, ["%service_sms_driver%"]] 

The problem I'm facing is that I want to pass an "instance" of one of the two drivers into the setDriver method of my service. Which driver this is should be defined in my parameters.yml, something such as:

service_sms_driver: ["@mock_driver"]

However, I'm stuck on the syntax to make this work correctly. I think the gist of it is correct except for the syntax on the service_sms_driver value in my parameters.yml and the setDriver method call on the actual service.

Any help appreciated.

Edit: Just as a clarification, both drivers implement the same interface. However, every driver might need different ways of configuration which might not be captured in an interface. If I was simply passing class names it would work fine but I'm trying to inject instances instead. Hope this makes sense.

1条回答
我命由我不由天
2楼-- · 2020-04-08 01:45

Since your services construct differently, the idea of aliasing seems to be a correct idea.
To do so, just create your two driver services and your manager. (Note the usage of @driver)

services.yml

gateway_driver:
    class: Acme\FooBundle\GatewayDriver
mock_driver:
    class: Acme\FooBundle\MockDriver

manager:
    class: Acme\FooBundle\SmsManager
    arguments: [ @driver ]

Then, you can edit this alias into your AcmeFooExtension file

Acme/FooBundle/DependencyInjection/AcmeFooExtension.php

public function load(array $configs, ContainerBuilder $container)
{
    $driver = $container->getParameter('service_sms_driver');
    $container->setAlias('driver', $driver);
}

This will take the service_sms_driver parameter and create an alias of this service.


Example of debugging:

config_dev.yml

parameters:
    service_sms_driver: mock_driver

Running

$ php app/console --env=dev container:debug driver

Results in

[container] Information for service driver
This service is an alias for the service mock_driver


config_prod.yml

parameters:
    service_sms_driver: gateway_driver

Running

$ php app/console --env=prod container:debug driver

Results in

[container] Information for service driver
This service is an alias for the service gateway_driver


config_test.yml

parameters:
    service_sms_driver: unknown_driver

Running

$ php app/console --env=test container:debug driver

Results in

[Symfony\Component\DependencyInjection\Exception\InvalidArgumentException]
The service definition "unknown_driver" does not exist.

查看更多
登录 后发表回答