Php Symfony-正在使用的注入条令存储库

Php Symfony-正在使用的注入条令存储库,php,symfony,doctrine-orm,symfony-3.4,Php,Symfony,Doctrine Orm,Symfony 3.4,据 就像 acme.custom_repository: class: Doctrine\ORM\EntityRepository factory: ['@doctrine.orm.entity_manager', getRepository] arguments: - 'Acme\FileBundle\Model\File' 但我有个例外 无效的服务“acme.custom_存储库”:类 “实体管理器5AA02DE170F88_546a8d27f194

据 就像

acme.custom_repository:
    class: Doctrine\ORM\EntityRepository
    factory: ['@doctrine.orm.entity_manager', getRepository]
    arguments:
        - 'Acme\FileBundle\Model\File'
但我有个例外

无效的服务“acme.custom_存储库”:类 “实体管理器5AA02DE170F88_546a8d27f194334ee012bfe64f629947b07e4919_uuuCG\uuuuu\document\ORM\EntityManager” 不存在

在Symfony 3.4中如何执行此操作

更新: EntityClass实际上是一个有效的类FQCN(当然也在phpstorm上使用了复制引用),只是重命名了它,因为其中有一个公司名称:)。不管怎样,我还是更新了它

解决方案 布鲁姆的作品完美。 如果不使用自动布线,则服务定义如下:

Acme\AcmeBundle\Respository\MyEntityRepository:
    arguments:
        - '@Doctrine\Common\Persistence\ManagerRegistry'
        - Acme\AcmeBundle\Model\MyEntity # '%my_entity_class_parameter%'

检查参数是否为有效类(具有FQCN或捆绑简化),例如:

acme.custom_repository:
    class: Doctrine\ORM\EntityRepository
    factory: 
        - '@doctrine.orm.entity_manager'
        - getRepository
    arguments:
        - Acme\MainBundle\Entity\MyEntity

希望这有助于正确创建自定义存储库 首先,您需要创建repository自定义类,该类从doctrine扩展默认存储库:

use Doctrine\ORM\EntityRepository;

class UserRepository extends EntityRepository
{
   // your own methods
}
然后在实体类中需要此注释:

/**
 * @ORM\Entity(repositoryClass="MyDomain\Model\UserRepository")
 */
然后在.yml文件中定义存储库:

custom_repository:
        class: MyDomain\Model\UserRepository
        factory: ["@doctrine", getRepository]
        arguments:
          - Acme\FileBundle\Model\File
确保存储库定义中的
指向自定义存储库类,而不是
条令\ORM\EntityRepository

将自定义服务注入自定义存储库: 在自定义存储库上为服务创建自定义设置器

使用条令\ORM\EntityRepository

class UserRepository extends EntityRepository
{
    protected $paginator;

    public function setPaginator(PaginatorInterface $paginator)
    {
        $this->paginator = $paginator;
    }
}
然后像这样注入它们:

custom_repository:
        class: MyDomain\Model\UserRepository

        factory: ["@doctrine", getRepository]
        arguments:
          - Acme\FileBundle\Model\File
        calls:
          - [setPaginator, ['@knp_paginator']]
<?php

namespace App\Database\Repository\Post;

use App\Database\Repository\Repository;
use App\Entity\Blog\Post;

/**
 * Class PostRepository
 * @package App\Database\Repository
 */
class PostRepository extends Repository
{
    public function test()
    {
        dd(99999, $this->getEntityName());
    }
}
将存储库注入服务:
在使用Symfony 3.4时,可以使用一种更简单的方法,即使用
ServiceEntityRepository
。只需实现您的存储库,让它
扩展
class
ServiceEntityRepository
,您就可以简单地注入它。(至少在使用自动布线时——我没有将其用于经典DI配置,但我认为它也应该工作。)

换言之:

namespace App\Repository;

use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Common\Persistence\ManagerRegistry;

class ExampleRepository extends ServiceEntityRepository
{
    /**
     * @param ManagerRegistry $managerRegistry
     */
    public function __construct(ManagerRegistry $managerRegistry)
    {
        parent::__construct($managerRegistry, YourEntity::class);
    }
}
现在,在没有任何DI配置的情况下,您可以在任何地方注入存储库,包括控制器方法


一个警告(同样适用于您尝试注入存储库的方式):如果重新设置条令连接,您将有一个对过时存储库的引用。但是,我承认这是一个风险,否则我将无法直接注入存储库。

到目前为止,我在这里看到的解决方案还不错。我从另一个角度看它。因此,我的解决方案允许您保持存储库干净,sorta强制执行一致的项目结构,并且您可以保持自动连接

这就是我在Symfony 5中解决它的方法

目标

我们希望拥有自动连接的存储库,并希望尽可能保持它们的干净。我们也希望他们是超级容易使用

问题

我们需要找出一种方法来告诉存储库它应该使用的实体

解决方案

解决方案很简单,包括以下几点:

  • 我们有一个自定义存储库类,它扩展了
    Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository
  • 我们的自定义类上有
    公共字符串$entity
    属性
  • 当我们创建新的存储库并扩展自定义存储库类时,我们有两个选择:在新存储库上,我们可以像这样指向类

  • 或者我们可以省略该属性,让新的基本存储库类自动找到它!(稍后将对此进行详细介绍。)

    代码

    让我们从代码开始,然后我将解释它:

    <?php
    
    namespace App\Database\Repository;
    
    use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
    use Doctrine\Persistence\ManagerRegistry;
    use Laminas\Code\Reflection\ClassReflection;
    use Symfony\Component\Finder\Finder;
    
    /**
     * Class Repository
     * @package App\Database\Repository
     */
    abstract class Repository extends ServiceEntityRepository
    {
        /** @var string  */
        private const REPOSITORY_FILE = 'repository';
    
        /** @var string */
        public string $entity = '';
        /** @var string */
        public string $defaultEntitiesLocation;
        /** @var string */
        public string $defaultEntitiesNamespace;
    
        /**
         * Repository constructor.
         *
         * @param ManagerRegistry $registry
         * @param $defaultEntitiesLocation
         * @param $defaultEntitiesNamespace
         * @throws \Exception
         */
        public function __construct(
            ManagerRegistry $registry,
            $defaultEntitiesLocation,
            $defaultEntitiesNamespace
        ) {
            $this->defaultEntitiesLocation = $defaultEntitiesLocation;
            $this->defaultEntitiesNamespace = $defaultEntitiesNamespace;
            $this->findEntities();
            parent::__construct($registry, $this->entity);
        }
    
        /**
         * Find entities.
         *
         * @return bool
         * @throws \ReflectionException
         */
        public function findEntities()
        {
            if (class_exists($this->entity)) {
                return true;
            }
            $repositoryReflection = (new ClassReflection($this));
            $repositoryName = strtolower(preg_replace('/Repository/', '', $repositoryReflection->getShortName()));
            $finder = new Finder();
            if ($finder->files()->in($this->defaultEntitiesLocation)->hasResults()) {
                foreach ($finder as $file) {
                    if (strtolower($file->getFilenameWithoutExtension()) === $repositoryName) {
                        if (!empty($this->entity)) {
                            throw new \Exception('Entity can\'t be matched automatically. It looks like there is' .
                                ' more than one ' . $file->getFilenameWithoutExtension() . ' entity. Please use $entity 
                                property on your repository to provide entity you want to use.');
                        }
                        $namespacePart = preg_replace(
                            '#' . $this->defaultEntitiesLocation . '#',
                            '',
                            $file->getPath() . '/' . $file->getFilenameWithoutExtension()
                        );
                        $this->entity = $this->defaultEntitiesNamespace . preg_replace('#/#', '\\', $namespacePart);
                    }
                }
            }
        }
    }
    
  • 然后在我们新的扩展类中,我知道默认情况下在哪里查找我的实体(这强制了一些一致性)

  • 非常重要的一点-我假设我们将使用完全相同的名称命名存储库和实体,例如:
    Post
    将是我们的实体,
    PostRepository
    是我们的存储库。请注意,
    Repository
    这个词不是必须的。如果它在那里,它将被移除

  • 一些聪明的逻辑将为您创建名称空间——我假设您将遵循一些好的实践,并且所有这些都是一致的

  • 完成了!要使您的存储库自动连接,您只需扩展新的基本存储库类并将实体命名为与存储库相同的名称。最终结果如下所示:

    custom_repository:
            class: MyDomain\Model\UserRepository
    
            factory: ["@doctrine", getRepository]
            arguments:
              - Acme\FileBundle\Model\File
            calls:
              - [setPaginator, ['@knp_paginator']]
    
    <?php
    
    namespace App\Database\Repository\Post;
    
    use App\Database\Repository\Repository;
    use App\Entity\Blog\Post;
    
    /**
     * Class PostRepository
     * @package App\Database\Repository
     */
    class PostRepository extends Repository
    {
        public function test()
        {
            dd(99999, $this->getEntityName());
        }
    }
    

    这可能会有帮助:遗憾的是没有。。。同样的例外,如果您碰巧使用多个实体管理器,您也需要稍微小心一点。如果同一个实体类属于多个管理器,那么您无法预测最终将使用哪个管理器。现在如何使用存储库?你能扩展这个答案吗?典型用法:构造函数注入。只需在代码中定义“public function_uu构造(ExampleRepository$repo){}”,依赖关系将在不进行配置的情况下得到解决。
    
     services:
            # default configuration for services in *this* file
            _defaults:
                autowire: true      # Automatically injects dependencies in your services.
                autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
                bind:
                    $defaultEntitiesLocation: '%kernel.project_dir%/src/Entity'
                    $defaultEntitiesNamespace: 'App\Entity'
    
    <?php
    
    namespace App\Database\Repository\Post;
    
    use App\Database\Repository\Repository;
    use App\Entity\Blog\Post;
    
    /**
     * Class PostRepository
     * @package App\Database\Repository
     */
    class PostRepository extends Repository
    {
        public function test()
        {
            dd(99999, $this->getEntityName());
        }
    }