简体   繁体   中英

How to fix "Cannot autowire service: Argument references class but no such service exists" in Sylius?

In Sylius 1.11, after creating a new Campaign entity using the maker bundle, I get this error when trying to fetch a campaign using its repository:

Cannot autowire service "App\Repository\CampaignRepository": argument "$class" of method "Doctrine\ORM\EntityRepository::__construct()" references class "Doctrine\ORM\Mapping\ClassMetadata" but no such service exists.

This seems to be the code that trigger the error:

<?php

namespace App\Controller;

use App\Repository\CampaignRepository;

class CampaignController extends AbstractController {
    protected CampaignRepository $repository;

    public function __construct(CampaignRepository $repository) {
        $this->repository = $repository;
    }

    public function details(string $id)
    {
        $campaign = $this->repository->find($id);

        dd($campaign);
    }
}

The App\Repository\CampaignRepository exists and is defined as follow, which is what the Sylius documentation recommends :

<?php

namespace App\Repository;

use App\Entity\Campaign;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository;

/**
 * @extends ServiceEntityRepository<Campaign>
 *
 * @method Campaign|null find($id, $lockMode = null, $lockVersion = null)
 * @method Campaign|null findOneBy(array $criteria, array $orderBy = null)
 * @method Campaign[]    findAll()
 * @method Campaign[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
 */
class CampaignRepository extends EntityRepository
{
}

How to fix this error?

TL;DR

It turns out Sylius is quite picky on both the type hinting and the variable name. This is due to how Symfony's dependency injection works and how Sylius chose to use it.

Change the constructor to:

public function __construct(
   \Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository $campaignRepository
) {
    $this->repository = $campaignRepository;
}

How are you supposed to guess that?

You need to use the bin/console debug:container command. But if you try, you'll run into the same error message as when running you controller action.

What you need to do is:

  1. comment any method that use the symfony's dependency injection feature to access an instance of your repository (in our case the App\Controller\CampaignController::__construct() method)
  2. run the bin/console debug:container CampaignRepository
    This will return you a list of services:
bin/console debug:container CampaignRepository

Select one of the following services to display its information:
[0] App\Repository\CampaignRepository
[1] Doctrine\Persistence\ObjectRepository $campaignRepository
[2] Doctrine\Common\Collections\Selectable $campaignRepository
[3] Sylius\Component\Resource\Repository\RepositoryInterface $campaignRepository
[4] Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository $campaignRepository
[5] Doctrine\ORM\EntityRepository $campaignRepository
  1. chose a combination of class name & parameter to use as your constructor parameter (I went with Sylius\Component\Resource\Repository\RepositoryInterface $campaignRepository but any of the suggestions with a parameter name should work)
  2. uncomment the method you commented on step 1 & update its signature
  3. voilà

If you're curious how this works, have a look here: https://symfony.com/doc/current/service_container/autowiring.html#dealing-with-multiple-implementations-of-the-same-type

As a type-hint you can use any of the interfaces that the repository class implements, the base ones that can be used for any resource repository are Sylius\Component\Resource\Repository\RepositoryInterface and Doctrine\Persistence\ObjectRepository . For built-in Sylius resources, there are repository interfaces in the lower-level components and sometimes in the core component, like Sylius\Component\Order\Repository\OrderRepositoryInterface and Sylius\Component\Core\Repository\OrderRepositoryInterface . Plugins usually also define interfaces. For custom repositories in your projects, you should also define interfaces if you add custom methods. The argument name also matters. To check which type-hints are available, together with the argument name use the command bin/console debug:autowiring campaing .

you can add to the file services.yaml

your sercvice here -> the path of your file: autowire: true or add the arguments manually your sercvice here -> the path of your file: arguments:[....]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM