gpt4 book ai didi

symfony - 如何避免工厂模型中的服务容器

转载 作者:行者123 更新时间:2023-12-02 17:02:27 28 4
gpt4 key购买 nike

我在一个项目中使用 Symfony 4,我有一个关于工厂的问题。

假设我有一个取决于某种字符串的策略。

我想基于此 Prop 创建不同的服务,每个服务都有自己的依赖项,并且我想创建一个工厂服务,以便界面简单。

让我举个例子:

class ServiceBar implements Doing{
public function __construct($dep1,$dep2){
}
public function do();
}

class ServiceBaz implements Doing{
public function __construct($dep3,$dep4){
}
public function do();
}


// Factory Class
class MyServiceFactory{
protected $services = [
'bar' => 'app.service.bar',
'baz' => 'app.service.baz'
];

public function __construct(ContainerInterface $sc){
$this->sc = $sc;
}

public function factory($string){
if(!$this->sc->has($this->services[$string])){
throw new Exception("Missing Service");
}
$this->sc->get($this->services[$string])->do();

}

}

// IndexController.php
public function indexAction(Request $request, MyServiceFactory $factory)
{
$factory->factory($request->get('action'));
}

通过此实现,我创建了具有所有依赖项的服务,以及从我的 Controller 调用的工厂。

您对此解决方案还有其他想法或评论吗?我用工厂构造函数注入(inject)了服务容器;还有其他方法可以从工厂创建服务吗?这种方法有什么问题吗?

提前致谢

最佳答案

Symfony Service Locator可用于避免注入(inject)整个容器的需要。定位器就像一个容器,但只能访问有限数量的服务。

配置一切需要一点魔法。在您的情况下,您只希望定位器访问实现 Doing 接口(interface)的服务。

从定位器开始,它将像所有容器一样继承 get/has 方法:

use Symfony\Component\DependencyInjection\ServiceLocator;

class DoingLocator extends ServiceLocator
{
protected $services = [
'bar' => 'app.service.bar',
'baz' => 'app.service.baz'
];
public function locate($string) {
return $this->get($this->services[$string]);
}
}

现在魔法来了。实际上,您可以根据文档在 services.yaml 中手动配置它,但自动执行更有趣。

首先使您的内核类成为编译器通行证:

# src/Kernel.php
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
class Kernel extends BaseKernel implements CompilerPassInterface

接下来,自动标记所有实现 Doing 接口(interface)的服务:

# Kernel.php
protected function build(ContainerBuilder $container)
{
$container->registerForAutoconfiguration(Doing::class)
->addTag('doing');
}

最后,添加编译器传递来构建您的定位器服务:

# Kernel.php
public function process(ContainerBuilder $container)
{
$doingLocatorIds = [];
foreach ($container->findTaggedServiceIds('doing') as $id => $tags) {
$doingLocatorIds[$id] = new Reference($id);
}
$doingLocator = $container->getDefinition(DoingLocator::class);
$doingLocator->setArguments([$doingLocatorIds]);
}

然后很快。你完成了。您现在可以注入(inject) DoingLocator(又名 MyServiceFactory),一切都应该很好。

关于symfony - 如何避免工厂模型中的服务容器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53411936/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com