Symfony 4 - 如何在自动装配整个路径时使用服务标签

时间:2018-03-31 08:19:08

标签: php symfony service configuration autowired

我正在研究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)

$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']

所以,我想知道是否有一个我无法找到的解决方法,或者我应该手动添加每个服务?

修改 能够在课堂上使用注释是一个很好的功能,所以当它被加载时它会知道"它的标签,但我认为它的工作方式相反,加载一个类,因为它被标记了某个标记。

5 个答案:

答案 0 :(得分:1)

您可以在Kernel / Main Bundle Class中自动配置标记:

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');
    }
}

答案 1 :(得分:1)

从3.4升级到symfony 4.4之后,我有相同的错误消息。

问题似乎是该实体对@ORM\Entity(repositoryClass="App\Repository\MyRepository")有注释 而存储库扩展了ServiceEntityRepository,而在构造函数中则指向实体parent::__construct($registry, MyEntity::class);

删除实体上的注释可解决此问题。

答案 2 :(得分:0)

使用PhpStorm 2019.2重构(重新命名)某些实体和相关存储库后,我遇到了相同的错误消息.2重构未更新实体的doc块中的存储库类名称:

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

因此,我使用了右键单击> Copy Reference以获取NewRepository的完全限定名称,并将其粘贴到doc块引用中:

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

PhpStorm用反斜杠作为类的前缀,直到尝试了针对此错误的建议解决方案的许多组合之后,我才注意到。我只需要删除反斜杠,错误就消失了:

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

答案 3 :(得分:0)

您可以标记所有存储库,如下所示:

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

答案 4 :(得分:0)

感谢@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'