How to create my own Custom Resource with custom controller without getting “can not autowire”-exception?

I’d like to create my own custom resource in a Sylius application as described here. After many pitfalls and errors as described blow I looked also at some Sylius plugins and found this one, where everything works fine.

However, following Docs and such examples won’t work in my cases.

I have defined the resource this way:

resources.yml:

    app.custody:
        driver: doctrine/orm
        classes:
            model: AppBundle\Entity\CustodyWallet
            form: AppBundle\Form\Type\CustodyType
            controller: AppBundle\Controller\Shop\CustodyController

routing.yml:

account_token_custody:
    path: /account/custody
    methods: [GET, POST]
    defaults:
        _controller: app.controller.custody:custodyAction
        _sylius:
            template: "@AppBundle/custody.html.twig"
            redirect: sylius_shop_account_dashboard

The CustodyController looks like this:

use AppBundle\Entity\CustodyWallet;
use AppBundle\Form\Type\CustodyType;
use Sylius\Bundle\ResourceBundle\Controller\ResourceController;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class CustodyController extends ResourceController
{
	public function custodyAction(Request $request): Response
	{
        // .... code .....
	}
}

However, it results in the following error:

Cannot autowire service “AppBundle\Controller\Shop\CustodyController”:
argument “$metadata” of method
“Sylius\Bundle\ResourceBundle\Controller\ResourceController::__construct()”
references interface
“Sylius\Component\Resource\Metadata\MetadataInterface” but no such
service exists. Did you create a class that implements this interface?

Searching for this error sent me to this GitHub issue, where people recommend to set autowire to false for this particular Controller. So I did:

services.yml:

AppBundle\Controller\Shop\CustodyController:
    autowire: false
    public: true

But this way the constructor is called without any arguments:

Too few arguments to function
Sylius\Bundle\ResourceBundle\Controller\ResourceController::__construct(),
0 passed in
/var/www/var/cache/dev/Container1MQRWcB/getCustodyControllerService.php
on line 16 and exactly 17 expected

I’m curious why a similar configuration works in the CmsPlugin which I have mentioned above but not in my case.

How can I achieve that?

Hey @itinance,

If you will check the configuration of CmsPlugin (or Sylius itself) you will see, that autowiring is turned off for ResourceControllers. What you need to do, is to turn off autodiscovery for this controller. But in order to achieve it, you will probably need to turn off it for the whole folder(probably you can achieve it for the particular file).

The problem is related to the naming of services. Your configuration:

    app.custody:
        driver: doctrine/orm
        classes:
            model: AppBundle\Entity\CustodyWallet
            form: AppBundle\Form\Type\CustodyType
            controller: AppBundle\Controller\Shop\CustodyController

will generate app.controller.custody controller, while autowiring will generate AppBundle\Controller\Shop\CustodyController, which is another service pointing to the same class. The first one is configured by Sylius, however second is not autowired (because you turned off this feature), so we are missing 17 services.

We should eventually improve autowiring support for our Sylius Resource, as the error is not obvious.

2 Likes
2 Likes

many thanks you guys. @vvasiloi’s answer on SO helped a lot. And thanks for further explanation @lchrusciel

You can leave the default configuration and just add the following and it works:

_instanceof:
    Sylius\Bundle\ResourceBundle\Controller\ResourceController:
        autowire: false
1 Like