1

Lets suppose I have an interface ThingInterface and two implementations Thing and MockThing. Now assuming I am using dependency injection and I have programmed against ThingInterface then in symfony I can tell it which implementation to use, as follows:

services:
    ...
    ThingInterface: '@Thing'
    ...

Is it possible to pick and implementation to use based on a parameter? E.g:

parameters:
    useMock: 'true'

services:
    ...
    # ThingInterface maps to ThingMock or Thing based on useMock parameter
    ThingInterface: '@ThingMock'
    ...

I'm using symfony 3.4.

The context here is that I'll have a number of services, and I want to easily switch between an actual implementation and mocked version. I can do this individually for each service, but I was hoping I can do this through a parameter 'toggle'.

I found this which gives this example:

services:
    AppBundle\Mailer:
        arguments: ["@=container.hasParameter('some_param') ? parameter('some_param') : 'default_value'"]

But I have been unable to make it work for mapping interfaces to implementations:

parameters:
    useMock: 'true'

services:
    ...
    # ThingInterface maps to ThingMock or Thing based on useMock parameter
    ThingInterface: '@ThingMock'
    ThingInterface: ["@=container.getParameter('useMock') ? service('ThingMock') : service('Thing')"]
    ...
5
  • 1
    You forgot to indicate the used Symfony's version. Commented May 1, 2019 at 17:18
  • @gp_sflover thanks, I've added the symfony version I'm using. Although only answers for symfony 3.4 would be useful for me, I'd welcome an answer for any version. Commented May 2, 2019 at 7:58
  • You may look at factory. symfony.com/doc/3.4/service_container/factories.html Commented May 2, 2019 at 8:15
  • Is this strictly for testing? If so, I question the value of mocking services. In any event, you might be able to do this with an environment aware compiler pass. But I sort of think you may be on the wrong path. Commented May 2, 2019 at 11:44
  • @Cerad - not just testing, also developing. The services we are mocking are ones which interact with an API managed by an external party. Mocking it has proved very valuable: it allows us to write automated integration tests, when developing we know what data we're dealing with (we don't have to hunt down particular entities with particular values), and we can quickly create our "scenarios" to replicate bugs. It also meant we were blocked in our development when the team managing the API were fixing bugs or developing new endpoints :). Commented Jul 10, 2019 at 19:31

1 Answer 1

2

For some unknown reason, the shorthand of just setting a string to alias/remap to doesn't seem to evaluate at all with symfony.

You can try this:

Namespace\ClassA: ~
Namespace\ClassB: ~
Namespace\MyInterface:
    class: '%my_interface.class%'

However, you'll probably end up with two instances of the class (two services). Alias unfortunately doesn't seem to work, neither will import.

The only other options seem ugly and basically lose autowiring, IE, binding everywhere.

Unfortunately these are the only ways to do it as symfony doesn't support what you're asking for.

If you want to do that you have to implement that as a framework extension or use a different framework. There's a bunch of github issues and denied pull requests confirming this.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.