Symfony2 conditional service declaration
Asked Answered
A

1

6

I'm currently trying to find a solid solution to change the dependencies of a Symfony2 service dynamically. In detail: I have a Services which uses a HTTP-Driver to communicate with an external API.

class myAwesomeService
{
    private $httpDriver;

    public function __construct(
        HTTDriverInterface $httpDriver
    ) {
        $this->httpDriver = $httpDriver;
    }

    public function transmitData($data)
    {
        $this->httpDriver->dispatch($data);
    } 
}

While running the Behat tests on the CI, I'd like to use a httpMockDriver instead of the real driver because the external API might be down, slow or even broken and I don't want to break the build.

At the moment I'm doing something like this:

<?php
namespace MyAwesome\TestBundle\DependencyInjection;

class MyAwesomeTestExtension extends Extension
{
    /**
     * {@inheritDoc}
     */
    public function load(array $configs, ContainerBuilder $container)
    {
        $configuration = new Configuration();
        $config = $this->processConfiguration($configuration, $configs);

        $loader = new Loader\YamlFileLoader($container, new       
                     FileLocator(__DIR__.'/../Resources/config'));
        $environment = //get environment
        if ($environment == 'test') {
            $loader->load('services_mock.yml');         
        } else {
            $loader->load('services.yml');          
        }
    }
}

This works for now, but will break for sure. So, is there a more elegant/solid way to change the HTTPDriver dynamically?

Asbestosis answered 9/8, 2014 at 7:0 Comment(2)
Why do you think it will break?Tennison
Keeping track of two different yml files ... someone will for sure forget to modify one of the files while changing a dependencyAsbestosis
A
13

I finally found a solution that looks solid to me. As of Symfony 2.4 you can use the expression syntax: Using the Expression Language

So I configured my service this way.

service.yml
parameters:
  httpDriver.class:       HTTP\Driver\Driver
  httpMockDriver.class:   HTTP\Driver\MockDriver
  myAwesomeService.class: My\Awesome\Service
service:
  myAwesomeService:
    class:        "%myAwesomeService.class%"
    arguments:    
      - "@=service('service_container').get('kernel.environment') == 'test'? service('httpMockDriver) : service('httpDriver)"

This works for me.

Asbestosis answered 11/8, 2014 at 17:34 Comment(3)
just a bit of upgrade to that - you can use parameter('key') to get parameter inside expression, no need to do it using container; and 2nd - to get container, you can just use container variable; details are here: symfony.com/doc/current/book/…Syllabism
The link is deprecated. Here's the right one: symfony.com/doc/current/service_container/…Daisie
I was hoping to use an expression for class instead of arguments but it doesn't work, any way to get that behavior?Supervise

© 2022 - 2024 — McMap. All rights reserved.