How to override bundled Doctrine repository in Symfony

被刻印的时光 ゝ 提交于 2021-02-07 14:34:20

问题


I have an independent Symfony bundle (installed with Composer) with entities and repositories to share between my applications that connect same database.

Entities are attached to every applications using configuration (yml shown):

doctrine:
    orm:
        mappings:
            acme:
                type: annotation
                dir: %kernel.root_dir%/../vendor/acme/entities/src/Entities
                prefix: Acme\Entities
                alias: Acme

Well, it was the easiest way to include external entities in application, but looks a bit ugly.

Whenever I get repository from entity manager:

$entityManager->getRepository('Acme:User');

I get either preconfigured repository (in entity configuration) or default Doctrine\ORM\EntityRepository.

Now I want to override bundled (or default) repository class for a single entity. Is there any chance to do it with some configuration/extension/etc?

I think, the best looking way is something like:

doctrine:
    orm:
         ....:
             Acme\Entities\User:
                 repositoryClass: My\Super\Repository

Or with tags:

my.super.repository:
    class: My\Super\Repository
    tags:
        - { name: doctrine.custom.repository, entity: Acme\Entities\User }

回答1:


You can use LoadClassMetadata event:

class LoadClassMetadataSubscriber implements EventSubscriber
{

    /**
     * @inheritdoc
     */
    public function getSubscribedEvents()
    {
        return [
            Events::loadClassMetadata
        ];
    }

    /**
     * @param LoadClassMetadataEventArgs $eventArgs
     */
    public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
    {
        /**
         * @var \Doctrine\ORM\Mapping\ClassMetadata $classMetadata
         */
        $classMetadata = $eventArgs->getClassMetadata();

        if ($classMetadata->getName() !== 'Acme\Entities\User') {
            return;
        }

        $classMetadata->customRepositoryClassName = 'My\Super\Repository';
    }

}

Doctrine Events

Entities are attached to every applications using configuration (yml shown): Well, it was the easiest way to include external entities in application, but looks a bit ugly.

You can enable auto_mapping




回答2:


Works for Doctrine versions <2.5

In addition to Artur Vesker answer I've found another way: override global repository_factory.

config.yml:

doctrine:
    orm:
        repository_factory: new.doctrine.repository_factory

services.yml:

new.doctrine.repository_factory:
    class: My\Super\RepositoryFactory

Repository Factory:

namespace My\Super;

use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Repository\DefaultRepositoryFactory;

class RepositoryFactory extends DefaultRepositoryFactory
{
    /**
     * @inheritdoc
     */
    protected function createRepository(EntityManagerInterface $entityManager, $entityName)
    {
        if ($entityName === Acme\Entities\User::class) {
            $metadata = $entityManager->getClassMetadata($entityName);
            return new ApplicationRepository($entityManager, $metadata);
        }

        return parent::createRepository($entityManager, $entityName);
    }
}

No doubt implementing LoadClassMetadataSubscriber is a better way.



来源:https://stackoverflow.com/questions/35942910/how-to-override-bundled-doctrine-repository-in-symfony

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!