Циклическая зависимость сервисного контейнера Symfony4

В процессе миграции проекта symfony3.4 на Symfony4 с помощью symfony-flex

После адаптации структуры каталогов и выполнения нескольких корректировок я теперь сталкиваюсь с тем, что выглядит как ошибка циклической зависимости, которая обнаруживается на этапе начальной загрузки контейнера службы приложений. Нажатие на приложение (с консоли или с внешнего интерфейса) вызывает исключение, связанное с Xdebug, говоря, что «достигнут предел вложенных вызовов функций ('256')».

Если посмотреть на обратную трассировку, можно увидеть повторяющуюся закономерность и сделать вывод, что виноват не Xdebug, а две службы, косвенно зависящие друг от друга.

Вовлеченные услуги:

  • Диспетчер журналов - это общедоступная служба, которая помогает сохранять действия пользователя в базе данных:

    log_manager:
        class: Service\Log\LogManager
        public: true
        arguments:
            - "@doctrine.orm.entity_manager"
            - "@?security.token_storage"
    
  • LoggableSubscriber использует службу LogManager для создания новой записи при изменении состояния некоторых объектов приложения:

    Doctrine\Behavior\ORM\Loggable\LoggableSubscriber:
        public: false
        arguments:
            - "@log_manager"
            - "@event_dispatcher"
        tags:
            - { name: doctrine.event_subscriber }
    

Backtrace (читайте снизу вверх):

==== ↑↑ PATTERN REPEATS ON AND ON ↑↑ ====
==== ONCE AGAIN DOCTRINE LOOKS FOR SUBSCRIBERS ====
at boDevDebugProjectContainer->load('…/var/cache/bo/dev/ContainerTv5AUyL/getLoggableSubscriberService.php')
    in getDoctrine_Dbal_ApiacmeConnectionService.php (line 34)
at require('…/var/cache/bo/dev/ContainerTv5AUyL/getDoctrine_Dbal_ApiacmeConnectionService.php')
    in boDevDebugProjectContainer.php (line 446)
at boDevDebugProjectContainer->load('…/var/cache/bo/dev/ContainerTv5AUyL/getDoctrine_Dbal_ApiacmeConnectionService.php')
    in getDoctrine_Orm_ApiacmeEntityManagerService.php (line 74)
at require('…/var/cache/bo/dev/ContainerTv5AUyL/getDoctrine_Orm_ApiacmeEntityManagerService.php')
    in boDevDebugProjectContainer.php (line 446)
==== "LOGMANAGER" NATURALLY REQUIRES DOCTRINE ENTITY MANAGER SERVICE ====
at boDevDebugProjectContainer->load('…/var/cache/bo/dev/ContainerTv5AUyL/getDoctrine_Orm_ApiacmeEntityManagerService.php')
    in getLogManagerService.php (line 10)
at require('…/var/cache/bo/dev/ContainerTv5AUyL/getLogManagerService.php')
    in boDevDebugProjectContainer.php (line 446)
at boDevDebugProjectContainer->load('…/var/cache/bo/dev/ContainerTv5AUyL/getLogManagerService.php')
    in getLoggableSubscriberService.php (line 11)

==== BUT OUR "LOGGABLESUBSCRIBER" IN TURN NEEDS THE "LOGMANAGER" SERVICE ====
at require('…/var/cache/bo/dev/ContainerTv5AUyL/getLoggableSubscriberService.php')
    in boDevDebugProjectContainer.php (line 446)

==== DOCTRINE LOADS SUBSCRIBERS (ATTACHED VIA "TAG" PROPERTY) ====
at boDevDebugProjectContainer->load('…/var/cache/bo/dev/ContainerTv5AUyL/getLoggableSubscriberService.php')
    in getDoctrine_Dbal_ApiacmeConnectionService.php (line 34)
==== ↑↑ PATTERN STARTS HERE ↑↑ ====

at require('…/var/cache/bo/dev/ContainerTv5AUyL/getDoctrine_Dbal_ApiacmeConnectionService.php')
    in boDevDebugProjectContainer.php (line 446)
at boDevDebugProjectContainer->load('…/var/cache/bo/dev/ContainerTv5AUyL/getDoctrine_Dbal_ApiacmeConnectionService.php')
    in getDoctrine_Orm_ApiacmeEntityManagerService.php (line 74)
at require('…/var/cache/bo/dev/ContainerTv5AUyL/getDoctrine_Orm_ApiacmeEntityManagerService.php')
    in boDevDebugProjectContainer.php (line 446)

==== FIRST, OUR "LOGMANAGER" SERVICE DEPENDS ON DOCTRINE MAIN ENTITYMANAGER ====
at boDevDebugProjectContainer->load('…/var/cache/bo/dev/ContainerTv5AUyL/getDoctrine_Orm_ApiacmeEntityManagerService.php')
    in getLogManagerService.php (line 10)
at require('…/var/cache/bo/dev/ContainerTv5AUyL/getLogManagerService.php')
    in boDevDebugProjectContainer.php (line 446)
↑↑ ↑↑ ↑↑
…

Это просто заблуждение? Или есть способ сообщить контейнеру службы об этой ситуации, установив какое-либо свойство / флаг где-нибудь в конфигурации, чтобы он не сошел с ума? Я видел несколько вопросов, связанных с этой темой, но ответы относятся к контекст их вопроса.

Я собирался разорвать зависимость службы LogManager от диспетчера сущностей доктрины, из-за чего класс LogManager больше не мог сохранять свой базовый объект сущности в базе данных сам по себе и, как следствие, делегировал эту работу в вызывающий контекст, возвращая вместо этого экземпляр для сохранения. Я не уверен, что это идеальное решение.

Предлагаемый подход будет очень признателен.
Спасибо.


person Stphane    schedule 29.03.2018    source источник


Ответы (1)


Замена аргумента внедрения зависимости на вызов метода устранила проблему. Мое определение службы log_manager теперь выглядит так:

log_manager:
    class: Service\Log\LogManager
    public: true
    arguments:
        - "@?security.token_storage"
    calls:
        - ['setEntityManager', ["@doctrine.orm.entity_manager"]]

Прокомментируйте / ответьте, если есть лучший способ решить проблему.

person Stphane    schedule 04.04.2018