首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Symfony中向服务工厂传递动态参数

在Symfony中向服务工厂传递动态参数
EN

Stack Overflow用户
提问于 2021-12-09 13:39:05
回答 1查看 1.7K关注 0票数 1

我正在将Symfony集成到一个旧的应用程序中,它基于PSR-11拥有自己的依赖容器。一直在寻找将DI容器合并到Symfony使用的解决方案,但一无所获。为了让它发挥作用,我带了一个我不喜欢的“讨厌”的解决方案。

我创造了这门课。它在其中创建一个旧DI容器的实例:

代码语言:javascript
复制
class OldAppServiceFactory
{
    private ContainerInterface $container;

    public function __construct()
    {
        $this->container = OldContainerFactory::create();
    }

    public function factory(string $className)
    {
        return $this->container->get($className);
    }
}

并向services.yaml添加了适当的条目。

代码语言:javascript
复制
    oldapp.service_factory:
        class: Next\Service\LeonContainer\LeonServiceFactory

    OldApp\Repository\Repository1:
        factory: ['@oldapp.service_factory', 'factory']
        arguments:
            - 'OldApp\Repository\Repository1'

    OldApp\Repository\Repository2:
        factory: ['@oldapp.service_factory', 'factory']
        arguments:
            - 'OldApp\Repository\Repository2'

    OldApp\configuration\ConfigurationProviderInterface:
        factory: ['@oldapp.service_factory', 'factory']
        arguments:
            - 'OldApp\configuration\ConfigurationProviderInterface'

使用上面的黑客,将这些类放到服务类构造函数中可以工作。不幸的是,它看起来很糟糕,如果用更多的这些存储库来扩展它将会很痛苦(特别是当有50个存储库的时候)。在services.yaml中能实现这样的目标吗?

代码语言:javascript
复制
    OldApp\Repository\:
        factory: ['@oldapp.service_factory', 'factory']
        arguments:
            - << PASS FQCN HERE >>

这将使我在services.yaml中只为旧应用程序的单个名称空间留出一个条目。

但是,也许我的问题还有其他的解决办法?一直在尝试配置Kernel.phpprepareContainer(...)方法,但由于旧的依赖项位于返回数组的一个PHP文件中,所以我也什么也没有完成:

代码语言:javascript
复制
return array [
    RepositoryMetadataCache::class => static fn () => RepositoryMetadataCache::createFromCacheFile(),
    EntityCollection::class => autowire(EntityCollection::class),
    'Model\Repository\*' => static function (ContainerInterface $container, RequestedEntry $entry) { ... }
];
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-12-09 14:11:08

您可能可以通过自定义编译器传递来轻松地完成这一任务。

首先,通过加载存在的目录来标记所有旧存储库类:

代码语言:javascript
复制
OldApp\Repository\:
    resource: '../src/OldApp/Repository/*'
    autowire: false
    autoconfigure: false
    tags: ['oldapp_repository']

(我认为您可能还需要将src/OldApp排除在默认的自动服务加载之外。例如:

代码语言:javascript
复制
App\:
    resource: '../src/*'
    exclude: '../src/{OldApp/Repository,DependencyInjection,Entity,Tests,Kernel.php}'

..。但我不能百分之百确定,测试这个)。

然后创建编译器传递以遍历标记,并为每个标记定义一个工厂:

代码语言:javascript
复制
class OldAppRepositoryCompilerPass implements CompilerPassInterface
{

    public function process(ContainerBuilder $container): void
    {
        $taggedServices = $container->findTaggedServiceIds('oldapp_repository');

        foreach ($taggedServices as $serviceId => $tags) {

            $definition = $container->getDefinition($serviceId);
            $definition
                    ->setFactory([new Reference('oldapp.service_factory'), 'factory'])
                    ->addArgument($serviceId);
        }

    }
}

在应用程序内核build()方法中添加编译器传递:

代码语言:javascript
复制
// src/Kernel.php
namespace App;

use Symfony\Component\HttpKernel\Kernel as BaseKernel;
// ...

class Kernel extends BaseKernel
{
    // ...

    protected function build(ContainerBuilder $container): void
    {
        $container->addCompilerPass(new OldAppRepositoryCompilerPass());
    }
}

现在不能测试这个问题,但这应该会让你朝着正确的方向前进。有关其他详细信息,请查看文档:

您可以检查此示例回购上面的实现和工作地点。在这个repo上,OldApp名称空间位于Appsrc之外,因此不需要将它排除在自动服务加载之外。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70290903

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档