gpt4 book ai didi

在 bundle 扩展加载时找不到 PHP Symfony 请求堆栈

转载 作者:可可西里 更新时间:2023-10-31 23:28:43 25 4
gpt4 key购买 nike

我正在尝试创建可重用的日志记录包,它可以为日志消息设置自定义格式化程序。格式化程序在主应用程序的配置文件中设置如下:

custom_logger:
formatter: AppBundle\Services\MessageFormatter

然后在 LoggerBundle/DependencyInjection/CustomLoggerExtension.php收到此配置后,我正在尝试获取记录器服务并设置格式化程序

class CustomLoggerExtension extends ConfigurableExtension
{

public function loadInternal(array $mergedConfig, ContainerBuilder $container)
{
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('services.yml');
$class = $mergedConfig['formatter'];
$obj = new $class;
$container->get('custom.logger')->setFormatter($obj);

但问题是记录器使用请求堆栈

services:
custom.logger:
class: LoggerBundle\Services\Logger
arguments: ['@request_stack']

因此,当我尝试在 loadInternal 函数中获取服务时,似乎请求堆栈尚未初始化并且我收到错误:您请求了一个不存在的服务“request_stack”

正确的做法是什么?

编辑 (2016-04-21 21:54:11)

这很奇怪。即使我删除了请求堆栈并在 loadInternal 中成功设置了格式化程序,当我从主应用程序中的 Controller 获取它时,它也不在服务中。我一定是做错了什么:)

最佳答案

好吧,我想我明白了。

当调用 load() 或在我的例子中调用 loadInternal() 方法时,symfony 将全新的容器传递给那里,然后将其合并到主容器中。因此,如果我请求一个服务并在那里创建它,它不会保存在任何地方,而是保存在临时容器中,并最终被销毁(只有服务定义被传递给主容器)。

由于服务是按需加载(创建)的,因此在 bundle 加载时实例化它是不对的。所以你想要做的是配置 definitions

这是我如何让它工作的:

use Symfony\Component\HttpKernel\DependencyInjection\ConfigurableExtension;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\Config\FileLocator;
use LoggerBundle\Formatter\MessageFormatterInterface;

class LoggerBundleExtension extends ConfigurableExtension implements CompilerPassInterface
{
protected $customFormatter;

public function loadInternal(array $mergedConfig, ContainerBuilder $container)
{
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('services.yml');

if (array_key_exists('formatter', $mergedConfig)) {
$this->customFormatter = $mergedConfig['formatter'];
}
}

public function process(ContainerBuilder $containerBuilder)
{
if ($this->customFormatter) {
$class = $this->customFormatter;

//if formatter is service id
$serviceUsed = $containerBuilder->has($this->customFormatter);
if ($serviceUsed) {
$class = $containerBuilder->getDefinition($this->customFormatter)->getClass();
}
if (!class_exists($class) || !is_a($class, MessageFormatterInterface::class, true)) {
throw new \ErrorException('Invalid logger formatter');
}
if ($serviceUsed) {
$containerBuilder
->getDefinition('custom.logger')
->addMethodCall('setFormatter', array(new Reference($this->customFormatter)));
} else {
$containerBuilder
->getDefinition('custom.logger')
->addMethodCall('setFormatter', array(new Definition($this->customFormatter)));
}
}
}
}

loadInternal() 中,我检查是否在主应用程序的配置中设置了格式化程序并保存它。但主要的事情发生在 process() 函数中(你必须实现 Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface 才能运行)。

来自docs .

As process() is called after all extensions are loaded, it allows you to edit service definitions of other extensions as well as retrieving information about service definitions.

所以,我正在做的是:

  • 检查 formatter 选项值是类名还是服务 ID(如果是这样,我从服务定义中检索类名)
  • 验证类名(检查它是否是一个有效的类并确保它实现了所需的接口(interface))
  • 向我的记录器服务添加定义,它告诉容器在创建记录器服务时(首次从容器中检索时)使用提供的参数调用 setFormatter

基本上$containerBuilder->getDefinition('custom.logger')->addMethodCall('setFormatter', array(new Reference('my_formatter')));

与在您的配置中声明的相同:

services:
custom.logger:
class: LoggerBundle\Services\Logger
arguments: ['@request_stack']
calls:
- [setFormatter, ['@my_formatter']]

关于在 bundle 扩展加载时找不到 PHP Symfony 请求堆栈,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36777841/

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