gpt4 book ai didi

symfony - 在 Symfony 中基于动态值注入(inject)服务

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

我有 2 个服务,BlueWorkerServiceYellowWorkerService,它们都实现相同的接口(interface),WorkerServiceInterface。这些服务中的每一个都使用相同的实体,但具有不同的所需逻辑。

我需要注入(inject)这些类中的一个,而不是两个,并在 ProcessorService 中使用它们,以便在正确的 Worker 上调用接口(interface)方法。使用哪个 Worker 服务取决于当前正在处理的 Worker。我会分解它:

Class WorkerProcessor {

private $workerService;

public function __construct(WorkerServiceInterface $workerServiceInterface)
{
$this->workerService = $workerServiceInterface;
}

public function getMixedColourWithRed() {
return $this->workerService->mixWithRed();
}
}

正在使用的工作人员服务将基于正在处理的工作人员是否具有 BlueYellowcolour 属性。

我知道我可以使用工厂来实现这个 as described here但我的问题是如何告诉工厂我正在加工哪种 Worker 颜色?

在 Symfony 3.4 上运行

如果您需要更多信息,请提问,我会更新问题。

最佳答案

注意:我使用的是 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 的特定服务。稍后我将展示如何标记服务。然后,我从 BannerManager 调用 addBannerType 方法。

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() 的自定义方法(由我创建)。您可以随意命名,但我认为这很冗长。所有参数都是我发过来的,不用介意。您可以发送任何内容。

现在我们有了我们的管理器和编译器 channel 。是时候设置我们的横幅类型(基于我的示例)并标记它们了!

我的横幅类型在 src/Service/Banner/Types 下(在您的情况下应该是 src/BUNDLE/Service/WhateverYouWant/Type。这没关系!您可以稍后从 services.yaml 更改它。

这些类型正在实现我的 BannerInterface。在此实例中,类下的代码无关紧要。还有一件事我应该警告你!您应该看到,在 BannerManager 下,在 addBannerType() 中我正在调用 $banner->getType()。在我的例子中,这是从 BannerInterface 继承的一种方法,它有一个唯一的字符串(在我的例子中,我有三种横幅类型:小、普通、大)。此方法可以有任何名称,但不要忘记在您的管理器中更新它。

我们快准备好了!我们应该标记它们,然后我们就可以尝试它们了!

转到您的 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);
}

关于symfony - 在 Symfony 中基于动态值注入(inject)服务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56731109/

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