簡體   English   中英

Doctrine onFlush事件監聽器服務的Symfony循環引用異常

[英]Symfony Circular Reference Exception for Doctrine onFlush Event Listener Service

我已經為Doctrine onFlush事件監聽器創建了一個服務。 在這個監聽器中,我想引用我在另一個服務中的常用函數來檢查實體的快捷方式路徑。 其他服務使用實體管理器來執行此操作,因此該其他服務的服務定義將doctrine實體管理器注入構造函數參數。 但是,如果我在我的主onFlush事件監聽器中包含其他服務,我會得到一個關於循環引用的令人討厭的錯誤。

我可以使這個entity_helper服務在set函數setEntityManager($entityManager)接受實體管理器。 但這意味着無論何時我在其他任何地方使用此entity_helper服務,我都必須始終傳入EntityManager。 也許那沒關系,但這是唯一的解決方案嗎? 開始時我的邏輯/理解是否有問題? (我是Symfony的新手,所以我經常出錯)。

圖表A:令人討厭的錯誤

Fatal error: Uncaught exception 'Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException' with message 'Circular reference detected for service "doctrine.dbal.cms_connection", path: "doctrine.dbal.cms_connection".' in /var/www/core/cms/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php:456 Stack trace: #0 /var/www/core/cms/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php(604): Symfony\Component\DependencyInjection\Dumper\PhpDumper->addServiceInlinedDefinitionsSetup('doctrine.dbal.c...', Object(Symfony\Component\DependencyInjection\Definition)) #1 /var/www/core/cms/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php(630): Symfony\Component\DependencyInjection\Dumper\PhpDumper->addService('doctrine.dbal.c...', Object(Symfony\Component\DependencyInjection\Definition)) #2 /var/www/core/cms/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php(117): Symfony\Componen in /var/www/core/cms/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php on line 456

Services.yml

# This is the helper class for all entities
gutensite_cms.entity_helper:
    class: Gutensite\CmsBundle\Service\EntityHelper
    # This causes the Circular Reference Error when this service is included in Event Listener
    arguments: [ "@doctrine.orm.cms_entity_manager" ]
    # Passing via a setter injection also causes the same error.
    #calls:
    #    - [setEntityManager, ['@doctrine.orm.cms_entity_manager']]


# An event listener for any entity that is Versionable
gutensite_cms.listener.is_versionable:
    class: Gutensite\CmsBundle\EventListener\IsVersionableListener
    #only pass in the services we need
    arguments: [ "@gutensite_cms.entity_helper" ]
    tags:
        - { name: doctrine.event_listener, event: onFlush }

Gutensite \\ CmsBundle \\服務\\ EntityHelper

namespace Gutensite\CmsBundle\Service;

use Doctrine\ORM\EntityManager;

class EntityHelper {

    /**
     * @var $em EntityManager
     */
    private $em;

    public function __construct(EntityManager $entityManager) {
        $this->em = $entityManager;
    }

    /**
     * Get the bundle shortcut path for an entity based on it's namespace.
     *
     * As an example, if your entity is Gutensite\CmsBundle\Entity\View\ViewVersion the function will return
     * GutensiteCmsBundle:View\ViewVersion
     *
     * @param $entity
     * @return string
     */
    public function getEntityBundleShortcut($entity) {
        // wrap get_class() in the entityManager metadata function to avoid returning cached proxy class
        $path = explode('\Entity\\', $this->em->getClassMetadata(get_class($entity))->getName());
        return str_replace('\\', '', $path[0]).':'.$path[1];
    }

}

Gutensite \\ CmsBundle \\事件監聽\\ IsVersionableListener

namespace Gutensite\CmsBundle\EventListener;

use Doctrine\ORM\Event\OnFlushEventArgs;
use Gutensite\CmsBundle\Service\EntityHelper;


/**
 * Class IsVersionableListener
 * @package Gutensite\CmsBundle\EventListener
 */
class IsVersionableListener
{

    /*
    private $entityHelper;

    public function __construct(EntityHelper $entityHelper) {
        $this->entityHelper = $entityHelper;
    }
    */

    public function onFlush(OnFlushEventArgs $eventArgs)
    {

        // This never is excecuted because of the error
        print('ON FLUSH EVENT EXECUTED');
        exit;

        $em = $eventArgs->getEntityManager();
        $uow = $em->getUnitOfWork();
        $updatedEntities = $uow->getScheduledEntityUpdates();

        foreach($updatedEntities AS $entity) {

            // This is generic listener for all entities that have an isVersionable method (e.g. ViewVersion)
            // TODO: at the moment, we only want to do the following code for the viewVersion entity

            if (method_exists($entity, 'isVersionable') && $entity->isVersionable()) {

                // Get the Correct Repo for this entity
                $entityShortcut = $this->entityHelper->getEntityBundleShortcut($entity);
                $repo = $em->getRepository($entityShortcut);

                // If the repo for this entity has an onFlush method, use it.
                // This allows us to keep the functionality in the entity repo
                if(method_exists($repo, 'onFlush')) {
                    $repo->onFlush($em, $entity);
                }

            }
        }
    }
}

對此的基本解決方案(如我所指出的)是從服務定義(和服務類)中刪除EntityManager的構造或setter注入。 相反,您必須將EntityManager傳遞給需要它的函數。 這可以防止循環引用。

我選擇了這個而不是創建一個setEntityManager因為在調用該函數之前,必須在EntityHelper服務上設置它似乎很笨拙。 將它直接傳遞給需要它的函數似乎更好。

以下是更改:

Services.yml

# This is the helper class for all entities
gutensite_cms.entity_helper:
    class: Gutensite\CmsBundle\Service\EntityHelper
    # Do NOT pass in EntityManager via constructor or injector, because it causes a Circular Reference Error when this service is included in Event Listener


# An event listener for any entity that is Versionable
gutensite_cms.listener.is_versionable:
    class: Gutensite\CmsBundle\EventListener\IsVersionableListener
    #only pass in the services we need
    arguments: [ "@gutensite_cms.entity_helper" ]
    tags:
        - { name: doctrine.event_listener, event: onFlush }

Gutensite \\ CmsBundle \\服務\\ EntityHelper

namespace Gutensite\CmsBundle\Service;

use Doctrine\ORM\EntityManager;

class EntityHelper {


    /**
     * Get the bundle shortcut path for an entity based on it's namespace.
     *
     * As an example, if your entity is Gutensite\CmsBundle\Entity\View\ViewVersion the function will return
     * GutensiteCmsBundle:View\ViewVersion
     *
     * @param $entity
     * @return string
     */
    public function getEntityBundleShortcut(EventManager $eventManager, $entity) {
        // wrap get_class() in the entityManager metadata function to avoid returning cached proxy class
        $path = explode('\Entity\\', $eventManager->getClassMetadata(get_class($entity))->getName());
        return str_replace('\\', '', $path[0]).':'.$path[1];
    }

}

Gutensite \\ CmsBundle \\事件監聽\\ IsVersionableListener

namespace Gutensite\CmsBundle\EventListener;

use Doctrine\ORM\Event\OnFlushEventArgs;
use Gutensite\CmsBundle\Service\EntityHelper;


/**
 * Class IsVersionableListener
 * @package Gutensite\CmsBundle\EventListener
 */
class IsVersionableListener
{

    /*
    private $entityHelper;

    public function __construct(EntityHelper $entityHelper) {
        $this->entityHelper = $entityHelper;
    }
    */

    public function onFlush(OnFlushEventArgs $eventArgs)
    {

        $em = $eventArgs->getEntityManager();
        $uow = $em->getUnitOfWork();
        $updatedEntities = $uow->getScheduledEntityUpdates();

        foreach($updatedEntities AS $entity) {

            // This is generic listener for all entities that have an isVersionable method (e.g. ViewVersion)
            // TODO: at the moment, we only want to do the following code for the viewVersion entity

            if (method_exists($entity, 'isVersionable') && $entity->isVersionable()) {

                // Get the Correct Repo for this entity
                $entityShortcut = $this->entityHelper->getEntityBundleShortcut($em, $entity);
                $repo = $em->getRepository($entityShortcut);

                // If the repo for this entity has an onFlush method, use it.
                // This allows us to keep the functionality in the entity repo
                if(method_exists($repo, 'onFlush')) {
                    $repo->onFlush($em, $entity);
                }

            }
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM