首页 > 解决方案 > Symfony 4.2 在 vendor/acme/demo-bundle 中创建存储库作为服务

问题描述

我正在处理 vendor/ 目录中的第三方捆绑包。

我有一个看起来像这样的实体类:

/**
 * @ORM\Entity(repositoryClass="Acme\DemoBundle\Repository\ArticleRepository")
 * @ORM\Table(name="acme_demo_article")
 */
class Article

还有一个像这样的存储库类:

class ArticleRepository extends ServiceEntityRepository
{
    public function __construct(RegistryInterface $registry)
    {
        parent::__construct($registry, Article::class);
    }
}

这会产生以下错误:

“Acme\DemoBundle\Repository\ArticleRepository”实体库实现了“Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepositoryInterface”,但找不到它的服务。确保服务存在并标记为“doctrine.repository_service”。

如果我从实体定义中删除 repositoryClass,我不再有错误,我可以从我的控制器中使用学说:

this->getDoctrine()->getRepository(Article::class)->findBy([], null, $limit, ($page - 1) * $limit);

我尝试将存储库作为服务添加到捆绑服务定义中,但它没有改变任何东西:

供应商/Acme/demo-bundle/Resources/config/services.yaml

services:
  Acme\DemoBundle\Repository\:
    resource: '../../Repository/ArticleRepository.php'
    autoconfigure: true
    tags: ['doctrine.repository_service']

bin/console debug:autowire 或 debug:container 不会显示该服务。

我还尝试添加扩展名:

namespace Acme\BlogBundle\DependencyInjection;


use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;

class AcmeBlogExtension extends Extension
{
    public function load(array $configs, ContainerBuilder $container)
    {
        $loader = new YamlFileLoader(
            $container,
            new FileLocator(__DIR__.'/../Resources/config')
        );
        $loader->load('services.xml');
    }
}

也没有工作。我没有被调用扩展的印象。我尝试向它添加一个构造函数并转储,死在构造函数中,但是没有转储结果。

所以我的问题是如何将我的存储库定义为供应商目录中的服务?

源代码在这里:https ://github.com/khalid-s/sf4-bundle-test

标签: servicedoctrinerepositorysymfony4

解决方案


经过一番挣扎,我成功地完成了我的任务。我不认为应该这样做,但如果这可以帮助某人......

我在捆绑包的 DependencyInjection 文件夹中添加了:

class AcmeBlogExtension extends Extension
{
    public function load(array $configs, ContainerBuilder $container)
    {
        $loader = new YamlFileLoader(
            $container,
            new FileLocator(__DIR__.'/../Resources/config')
        );
        $loader->load('services.yaml');
    }
}

我创建了一个编译器(这是我很难弄清楚的部分)来注册我的服务

class RepositoryCompiler implements CompilerPassInterface
{
    /**
     * @inheritdoc
     */
    public function process(ContainerBuilder $container)
    {
        $container->register('acme_blog.repository', ArticleRepository::class);
    }
}

我在我的 Bundle 类中添加了:

class AcmeBlogBundle extends Bundle
{
    /** @info this function normally is useless */
    public function getContainerExtension()
    {
        // This is only useful if the naming convention is not used
        return new AcmeBlogExtension();
    }

    /**
     * @inheritDoc
     */
    public function build(ContainerBuilder $container)
    {
        $container->addCompilerPass(new RepositoryCompiler());

        parent::build($container);
    }
}

最后是服务本身:

services:
  Acme\BlogBundle\Repository\:
    resource: '../../Repository/*Repository.php'
    autoconfigure: true
    autowire: true
    tags: ['doctrine.repository_service']

autoconfigure 和 autowire 没有用,因为当我调试时没有考虑它们:container 看起来像这样:

php bin/console debug:container acme

Information for Service "acme_blog.article.repository"
=======================================================

 ---------------- -----------------------------------------------
  Option           Value
 ---------------- -----------------------------------------------
  Service ID       acme_blog.article.repository
  Class            Acme\BlogBundle\Repository\ArticleRepository
  Tags             doctrine.repository_service
  Public           yes
  Synthetic        no
  Lazy             no
  Shared           yes
  Abstract         no
  Autowired        no
  Autoconfigured   no
 ---------------- -----------------------------------------------

一个非常重要的注释让我浪费了很多时间:

每次更改服务后都要清除缓存。即使在开发模式下,它们也不会在每次刷新后重新加载


推荐阅读