我有2个服务,BlueWorkerService
和YellowWorkerService
,都实现了相同的接口WorkerServiceInterface
。这些服务中的每一个都使用相同的实体,但是具有不同的所需逻辑。
我需要注入这些类之一,但不能同时注入两者,并在ProcessorService
中使用它们,以便在正确的Worker上使用调用接口方法。使用哪种工作程序服务取决于当前正在处理的工作程序。我将其分解:
Class WorkerProcessor {
private $workerService;
public function __construct(WorkerServiceInterface $workerServiceInterface)
{
$this->workerService = $workerServiceInterface;
}
public function getMixedColourWithRed() {
return $this->workerService->mixWithRed();
}
}
正在使用的工作程序服务将基于正在处理的工作程序具有colour
或Blue
的{{1}}属性。
我知道我可能可以使用Factory来实现此as described here,但是我的问题是如何告诉工厂我正在处理哪种Worker颜色?
在Symfony 3.4
上运行如果您需要更多信息,请问,我会更新问题。
答案 0 :(得分:1)
注意:我正在使用Symfony 4.3.1。我将这样发布,然后帮助您将所有代码从该体系结构移至Symfony 3.4。
我正在使用类似的概念在项目中加载不同的类。首先让我解释一下,然后在该文本下添加代码。
首先,我正在src/Kernel.php
(您的文件为app/AppKernel.php
)下加载自定义的编译器遍历:
/**
* {@inheritDoc}
*/
public function build(ContainerBuilder $container)
{
$container->addCompilerPass(new BannerManagerPass());
}
BannerManagerPass
在src/DependencyInjection/Compiler
下创建(在您的情况下应为src / BUNDLE / DependencyInjection / Compiler`)。
class BannerManagerPass implements CompilerPassInterface
{
/**
* {@inheritDoc}
*/
public function process(ContainerBuilder $container)
{
if (!$container->has(BannerManager::class)) {
return;
}
$definition = $container->findDefinition(BannerManager::class);
$taggedServices = $container->findTaggedServiceIds('banner.process_banners');
foreach (array_keys($taggedServices) as $id) {
$definition->addMethodCall('addBannerType', [new Reference($id)]);
}
}
}
如您所见,此类应实现CompilerPassInterface
。您会发现我在寻找标记为 banner.process_banners 的特定服务。稍后我将展示如何标记服务。然后,我从addBannerType
调用BannerManager
方法。
App \ Service \ BannerManager.php:(在您的情况下为src / BUNDLE / Service / BannerManager.php)
class BannerManager
{
/**
* @var array
*/
private $bannerTypes = [];
/**
* @param BannerInterface $banner
*/
public function addBannerType(BannerInterface $banner)
{
$this->bannerTypes[$banner->getType()] = $banner;
}
/**
* @param string $type
*
* @return BannerInterface|null
*/
public function getBannerType(string $type)
{
if (!array_key_exists($type, $this->bannerTypes)) {
return null;
}
return $this->bannerTypes[$type];
}
/**
* Process request and return banner.
*
* @param string $type
* @param Server $server
* @param Request $request
*
* @return Response
*/
public function process(string $type, Server $server, Request $request)
{
return $this->getBannerType($type)->process($request, $server);
}
}
此类具有一个自定义方法(由我创建),称为process()
。您可以随意命名,但是我认为这很冗长。所有参数都是我发送的,所以不要介意。您可以发送任何内容。
现在,我们有了Manager,并设置了编译器密码。是时候设置横幅类型(根据我的示例)并标记它们了!
我的横幅类型在 src / Service / Banner / Types (您的情况下应为 src / BUNDLE / Service / WhateverYouWant / Type )。这没关系!您可以稍后在services.yaml中进行更改。
这些类型正在实现我的BannerInterface
。在这种情况下,该类下的代码无关紧要。我还要警告您一件事!您应该在addBannerType()
内的BannerManager下看到我正在呼叫$banner->getType()
。在我的情况下,这是从BannerInterface继承的一种方法,它具有唯一的字符串(在我的示例中,我有三种横幅类型:small,normal,large)。此方法可以有任何名称,但不要忘记在您的管理器中也进行更新。
我们快要准备好了!我们应该给它们加上标签,然后就可以尝试了!
转到您的services.yaml并添加以下行:
App\Service\Banner\Types\:
resource: '../src/Service/Banner/Types/'
tags: [banner.process_banners]
请查看标签!
无论我想显示自定义横幅,我都使用带有$ _GET的简单URL来保持横幅类型,然后按以下方式加载它:
public function view(?Server $server, Request $request, BannerManager $bannerManager)
{
...
return $bannerManager->getBannerType($request->query->get('slug'))->process($request, $server);
}