Symfony 4 — как использовать служебные теги при автосвязывании всего пути

Я работаю над пакетом для Symfony 4, который структурирован следующим образом:

\Acme
  \FooBundle
    \Article
      \Entity
        - Article.php
        - Comment.php
      \Form
        - ArticleType.php
      \Repository
        - ArticleRepository.php
        - CommentRepository.php
      - ArticleManager.php
    \User
      \Entity
        - User.php
      \Repository
        - UserRepository.php
      - UserManager.php
    \SomethingElse
      \Entity
        - SomethingElse.php
      \Repository
        - SomethingElseRepository.php
      - SomethingElseManager.php

Есть еще много папок и сущностей, но это не имеет значения для вопроса.

Автосвязывание всех классов в этой папке можно создать с помощью такой конфигурации:

Acme\FooBundle\:
    resource: '../../*/{*Manager.php,Repository/*Repository.php}'
    exclude: '../../{Manager/BaseManager.php,Repository/BaseRepository.php}'
    autowire: true

Но когда вам нужно добавить служебные теги, такие как doctrine.repository_service, такая конфигурация больше не поможет. Без тега при использовании в контроллере, например:

$this->getDoctrine()->getRepository(Bar::class)

or

$this->getDoctrine()->getManager()->getRepository(Bar::class)

выдает ошибку:

Репозиторий сущностей "Acme\FooBundle\SomethingElse\Repository\SomethingElseRepository" реализует "Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepositoryInterface", но его службу найти не удалось. Убедитесь, что сервис существует и помечен тегом «doctrine.repository_service».

Дело в том, что, поскольку все они находятся в одной корневой папке, мне не разрешено использовать конфигурацию, подобную следующей, потому что она будет дублировать ключи Acme\FooBundle\:

Acme\FooBundle\:
    resource: '../../*/{*Manager.php}'
    exclude: '../../{Manager/BaseManager.php}'
    autowire: true

Acme\FooBundle\:
    resource: '../../*/{Repository/*Repository.php}'
    exclude: '../../{Repository/BaseRepository.php}'
    autowire: true
    tags: ['doctrine.repository_service']

Итак, мне было интересно, есть ли обходной путь, который я не смог найти, или мне нужно просто вручную добавить каждую службу?

Редактировать: Было бы неплохо иметь возможность использовать аннотацию в классе, чтобы при загрузке он «знал» свой тег, но я думаю, что это работает наоборот, загружая класс, потому что он был помечен определенным тегом.


person VMC    schedule 31.03.2018    source источник
comment
Не знаю, сработает ли это, но пробовали ли вы исключить каталоги репозитория (используя подстановочный знак) из своего первого ресурса? Это может предотвратить дублирование ключей. Чего я не вижу, так это того, как вы предотвращаете определение ваших объектов как сервисов, что может иметь забавные последствия.   -  person Cerad    schedule 31.03.2018
comment
Ресурс ограничен файлами, оканчивающимися на *Manager.php и *Repository.php, поэтому сущности не являются службами.   -  person VMC    schedule 10.04.2018
comment
Немного не по теме, но мне любопытно, откуда взялся этот тег доктрины.repository_service. Если ваш репозиторий расширяет ServiceEntityRepository, то для автоматического связывания тег не требуется. Убедитесь, что вы расширяете, а не реализуете.   -  person Cerad    schedule 11.04.2018
comment
Итак, если посмотреть на DoctrineBundle ServiceRepositoryCompilerPass, тег нужен только в том случае, если вы не используете автозагрузку.   -  person Cerad    schedule 11.04.2018


Ответы (5)


У меня было такое же сообщение об ошибке после обновления до symfony 4.4 с 3.4.

Проблема, похоже, заключалась в том, что у объекта была аннотация к @ORM\Entity(repositoryClass="App\Repository\MyRepository"), в то время как репозиторий расширяет ServiceEntityRepository и в конструкторе указывает на объект parent::__construct($registry, MyEntity::class);.

Удаление аннотации к объекту устранило проблему.

person T. van den Berg    schedule 30.06.2020
comment
Миллион благодарностей, сэр! Я пробовал автотегирование через services.yml, как упоминалось в другом ответе, но это принесло мне счастье. В конце концов, автоматическая пометка не нужна. - person Arnie; 06.12.2020

Я столкнулся с тем же сообщением об ошибке после рефакторинга (переименования) некоторых сущностей и связанных репозиториев с использованием PhpStorm 2019.2 Рефакторинг не обновил имя класса репозитория в блоке документации для сущности:

* @ORM\Entity(repositoryClass="App\Repository\OldRepository")

Поэтому я щелкнул правой кнопкой мыши > Copy Reference, чтобы получить полное имя NewRepository, и вставил его в ссылку на блок документа:

* @ORM\Entity(repositoryClass="\App\Repository\NewRepository")

PhpStorm поставил перед классом обратную косую черту, и я не заметил этого, пока не попробовал множество комбинаций предлагаемых решений для этой ошибки. Мне нужно было только удалить обратную косую черту, и ошибка исчезла:

* @ORM\Entity(repositoryClass="App\Repository\NewRepository")
person Arleigh Hix    schedule 21.12.2019

Вы можете автоматически настраивать теги в классе Kernel/Main Bundle:

https://symfony.com/doc/current/service_container/tags.html#autoconfiguring-tags

<?php

namespace Acme\FooBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;

class FooBundle extends Bundle
{
    public function build(ContainerBuilder $container)
    {
        parent::build($container);

        $container->registerForAutoconfiguration(EntityRepository::class)
            ->addTag('doctrine.repository_service');
    }
}
person MakG    schedule 31.03.2018
comment
Спасибо за ответ, @MakG! Пробовал и в связке и в ядре, как указано в документации. К сожалению, это не работает. - person VMC; 11.04.2018

Вы можете пометить все свои репозитории, например:

App\Repository\:
        resource: '../src/Repository'
        autowire: true
        tags: ['doctrine.repository_service']
person MAZux    schedule 16.05.2020

Спасибо @t-van-den-berg и @arleigh-hix!

У меня возникла эта проблема после перехода с Symfony 3.4 на 4.4, когда я хотел использовать старые репозитории с новыми сервисами.

Мое решение было небольшим изменением:

use App\Repository\NewRepository;
//...
/**
 * @ORM\Entity(repositoryClass=NewRepository::class)
 */

И объявление службы (для использования интерфейса):

  App\Repository\NewRepository:
    arguments:
      - "@doctrine"
  App\Repository\NewRepositoryInterface: '@App\Repository\NewRepository'
person paaacman    schedule 11.06.2021