Не удается autowire service: аргумент ссылается на класс, но такой службы не существует

Я обновляю проект с Symfony 3 to Symfony 4 (https://github.com/symfony/symfony/blob/master/UPGRADE-4.0.md) и у меня есть много репозиториев / сервисов, подобных этому:

namespace AppEntity;

use AppEntityActivation;
use DoctrineORMEntityRepository;
use PredisClient;

class ActivationRepository extends EntityRepository
{
    // ...
}

и когда я пытаюсь запустить проект в браузере такой:

http://localhost:8000/login

Я получаю эту ошибку:

(1/1) RuntimeException
Cannot autowire service "AppEntityActivationRepository": 
argument "$class" of method 
"DoctrineORMEntityRepository::__construct()" 
references class "DoctrineORMMappingClassMetadata" 
but no such service exists.

означает ли это, что вы должны создать службу для "DoctrineORMMappingClassMetadata" в вашей сервисы.файл yaml?

благодаря autowiring мои новые услуги.файл yaml довольно мал по сравнению со старым, в котором было 2000+ строк. Новая услуга.yaml просто имеет несколько из них (до сих пор):

App:
    resource: '../src/*'

# Controllers
AppController:
    resource: '../src/Controller'
    autowire: true
    public: true
    tags: ['controller.service_arguments']

# Models
AppModel:
    resource: '../src/Model/'
    autowire: true
    public: true

// etc

вопрос: Вам действительно нужно добавить определения служб в службы.yaml для сторонних классов поставщиков? И если да, могу ли я получить пример того, как это сделать, пожалуйста? Любые советы от тех, кто уже обновился от Symfony 3 to в Symfony 4 было бы здорово.

PHP 7.2.0-2 + ubuntu16.04.1+deb.sury.org+2 (cli) (построено: 7 декабря 2017 20:14: 31) ( NTS ) Linux Mint 18, Apache2 Ubuntu.

EDIT / FYI:

это " доктринаORMEntityRepository::_ _ construct ()", которую ActivationRepository расширяет:

/**
     * Initializes a new <tt>EntityRepository</tt>.
     *
     * @param EntityManager         $em    The EntityManager to use.
     * @param MappingClassMetadata $class The class descriptor.
     */
    public function __construct(EntityManagerInterface $em, MappingClassMetadata $class)
    {
        $this->_entityName = $class->name;
        $this->_em         = $em;
        $this->_class      = $class;
    }

который находится здесь:

/vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php

2 ответов


начиная с версии 1.8 DoctrineBundle, вы можете расширить свой класс, используя Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository вместо Doctrine\ORM\EntityRepository. Результат будет таким же, но это поддерживает autowire.

пример:

use App\Entity\Activation;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Common\Persistence\ManagerRegistry;

class ActivationRepository extends ServiceEntityRepository
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, Activation::class);
    }

    // ...
}

вам действительно нужно добавить определения служб в службы.yaml для сторонних классов поставщиков?

нет, не делай этого. Мое личное предложение: не расширяйте EntityRepository. Когда-либо. Вы не хотите, чтобы интерфейс вашего репозитория имел такой метод, как createQuery или flush. По крайней мере, вы этого не хотите, если рассматриваете репозиторий как коллекцию объектов. Если вы расширяете EntityRepository у вас будет дырявой абстракцией.

вместо этого вы можете впрыснуть EntityManager внутри вашего репозитория, и это все:

use App\Entity\Activation;
use App\Repository\ActivationRepository;
use Doctrine\ORM\EntityManagerInterface;

final class DoctrineActivationRepository implements ActivationRepository
{
    private $entityManager;
    private $repository;

    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
        $this->repository = $this->entityManager->getRepository(Activation::class);
    }

    public function store(Activation $activation): void
    {
        $this->entityManager->persist($activation);
        $this->entityManager->flush();
    }

    public function get($id): ?Activation
    {
        return $this->repository->find($id);
    }

    // other methods, that you defined in your repository's interface.
}

никаких других шагов не требуется.