我想要一项服务取决于某些参数,如下所示:
# services.yaml
parameters:
schemes: '%env(json:SCHEMES)%'
default_scheme: '%env(DEFAULT_SCHEME)%'
active_scheme: ''
services:
App\Service\SoapClient:
arguments:
$scheme: '%active_scheme%'
我这样使用这项服务:
class MyController extends AbstractController
{
public function createClient(SoapClient $soapClient): JsonResponse
{
...
return $this->json([
...
]);
}
}
问题是
active_scheme
可能会根据请求进行更改。所以 active_scheme
可能是 schemes
之一,具体取决于请求
我尝试通过创建事件监听器来解决它:
final class RequestListener
{
public function __construct(
#[Autowire(service: 'service_container')]
private readonly ContainerInterface $container,
#[Autowire(param: 'kernel.environment')]
private readonly string $env
)
{
}
#[AsEventListener(event: KernelEvents::REQUEST)]
public function onKernelRequest(RequestEvent $event): void
{
$schemes = $this->container->getParameter('schemes');
$defaultScheme = $this->container->getParameter('default_scheme');
if ($this->env === 'prod') {
$this->container->setParameter('active_scheme', $schemes[$defaultScheme]);
} else {
if (!$event->getRequest()->request->has('scheme')) {
throw new BadRequestHttpException('...');
}
$this->container->setParameter('active_scheme', $event->getRequest()->request->getString('scheme'));
}
}
}
此代码引发异常:无法在冻结的 ParameterBag 上调用 set()。
我可以从服务中删除我的 SoapClient 并将代码从上面移动到控制器,但我不喜欢这个解决方案,因为现在我需要手动创建 SoapClient 实例。
有没有办法让代码尽可能干净并允许动态实例化服务参数?
不要注入该参数,而是直接从参数包中获取:
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
class SoapClient
{
private string $scheme;
public function __construct(ParameterBagInterface $params)
{
}
public function call(): string
{
// Dynamically resolved when calling this method.
$this->scheme = $this->params->resolve('%active_scheme%');
}
}