4

Looking at the code of the Sylius Bundle for Symfony I noticed the Resource Bundle has an interesting way of defining resource controllers as services. Here is the cart item controller service configuration in XML

<service id="sylius.controller.cart_item" class="%sylius.controller.cart_item.class%">
        <argument type="service">
            <service factory-service="sylius.controller.configuration_factory" factory-method="createConfiguration" class="Sylius\Bundle\ResourceBundle\Controller\Configuration">
                <argument>sylius</argument>
                <argument>cart_item</argument>
                <argument>SyliusCartBundle:CartItem</argument>
            </service>
        </argument>
        <call method="setContainer">
            <argument type="service" id="service_container" />
        </call>
    </service>

If I understand it correctly this code instantiates the controller class and passes as the constructor argument the result of a call to the factory-method "createConfiguration" in the factory-service class. Arguments are specified, so everything is fine.

My question is twofold: 1) Where is this documented? I could not find one example of this kind of arguments-as-a factory-callable in the docs. 2) What would be the YAML version of this?

Thanks...

smarques
  • 708
  • 7
  • 22

3 Answers3

4

Here is the way:

<service id="sylius.controller.cart_item" class="%sylius.controller.cart_item.class%">
    <argument type="service">
        <service factory-service="sylius.controller.configuration_factory" factory-method="createConfiguration" class="Sylius\Bundle\ResourceBundle\Controller\Configuration">
            <argument>sylius</argument>
            <argument>cart_item</argument>
            <argument>SyliusCartBundle:CartItem</argument>
        </service>
    </argument>
    <call method="setContainer">
        <argument type="service" id="service_container" />
    </call>
</service>

Can be written as the following in yml

sylius.controller.cart_item:
    class: %sylius.controller.cart_item.class%
    arguments:
        - "@=service('sylius.controller.configuration_factory').createConfiguration('sylius', 'cart_item', 'SyliusCartBundle:CartItem')"
    calls:
        - [setContainer, ["@service_container"]]
Alexei Tenitski
  • 9,030
  • 6
  • 41
  • 50
2

You can find the answer to both of your questions in the dependency injection docs.

As far as defining a service nested under another service in YAML, it doesn't seem the parser that ships with Symfony can handle that, but I did find someone's pet project that seems to aim for this functionality: https://gist.github.com/Mikulas/8004470

Peter
  • 808
  • 7
  • 15
  • Honestly the dependency injection docs is the first place I looked at. In the page you linked there is an example of using a factory to create a service. I was looking for an example of using a factory to create a service that is passed as an argument to a different service, which is just slightly different. That is what the xml above does. Its similar but not the same thing, in my opinion. – smarques Apr 06 '14 at 09:12
  • The only difference is syntax. I really don't like the way the Sylius bundle does it here, since the factory service is not reusable. Even if you are 100% sure that your factory service will only be used in one place, declaring it independently still makes more sense from a readability standpoint. – Peter Apr 07 '14 at 13:36
  • I agree with you on this. The fact I am asking does not mean that I like it or would suggest using it. :) Still I'd like to know if this syntax is documented anywhere and what the corresponding yml would be... :D – smarques Apr 07 '14 at 15:12
  • 1
    Ok, just intellectual curiosity then. I can understand that :) It doesn't seem the default YAML parser can understand nested service definitions, but I did find this [https://gist.github.com/Mikulas/8004470](https://gist.github.com/Mikulas/8004470) – Peter Apr 07 '14 at 15:45
2

I was trying to override the CartItemController and came across this, because I thought i needed to do it this way. But it's not the way to go. Anyways, to answer your question. Here is how the xml transforms into yaml

(because the solution suggested by Alexei Tenitski didn't work for me, I did it like so)

sylius.controller.cart_item:
    class:    Sylius\Bundle\ResourceBundle\Controller\ResourceController
    arguments:   ["@sylius.cart_item.config_factory"]
    calls:
       - [setContainer, ["@service_container"]]

sylius.cart_item.config_factory:
    class:  Sylius\Bundle\ResourceBundle\Controller\Configuration
    factory_class: Sylius\Bundle\ResourceBundle\Controller\ConfigurationFactory
    factory_method: createConfiguration
    arguments: ["sylius", "cart_item", "SyliusCartBundle:CartItem"]

But I'm guessing you were trying to override the CartItem controller, right? :) that's what I was trying to do anyways.

In the Sylius Docs is explained how you would go about doing that. Like this :

location : yourbundle/resources/config/config.yml

sylius_cart:
    classes:
        item:
            controller: YourBundle\Controller\CartItemController

Also, make sure that if you configure the route to your new controller action, you use the controller service instead of the normal approach.

location : yourbundle/resources/config/routing.yml

mybundle_ajaxcart_add:
    path:     /ajax/cart/add
    defaults: { _controller: sylius.controller.cart_item:addAjaxAction }

I wanted to post it here, because I was looking for this for about half a day and probably someone is going to be looking for the same solution. And I like to save that person the headache ;)

axelvnk
  • 442
  • 1
  • 6
  • 15
  • Thank you for this info... its very useful for working with Sylius and I am sure it will save many headaches :D. As for me I was interested in using factories in service definitions in yml. – smarques Mar 26 '15 at 17:45