在由bundle动态创建的服务上调用方法

时间:2017-09-15 10:48:10

标签: symfony service dependency-injection yaml

我使用m6web_guzzle包来注册几个http客户端:

m6web_guzzlehttp:
    clients:
        myclient:
            timeout: 3
            headers:
                "Accept": "application/json"
            delay: 0
            verify: false

我想在动态生成的服务上调用方法。在这种情况下,生成的服务名称为:

@m6web_guzzlehttp.guzzle.handlerstack.myclient

以下是我在服务构造函数中的操作:(注入的第三个参数是'@ m6web_guzzlehttp.guzzle.handlerstack.myclient')

/**
 * @param array        $parameters
 * @param Client       $client
 * @param HandlerStack $handlerStack
 */
public function __construct(array $parameters, Client $client, HandlerStack $handlerStack)
{
    $this->parameters = $parameters;
    $this->client = $client;
    $this->handlerStack->push(Middleware::retry([$this, 'retryDecider']));
}

到目前为止,它运行良好,但如何在push文件中传输最后一行(services.yml调用)?或者另一种清理方法来注册这个重试处理程序?

3 个答案:

答案 0 :(得分:3)

在您的包的Extension.php文件中,您可以覆盖加载方法并添加:

$definition = $container->getDefinition('m6web_guzzlehttp.guzzle.handlerstack.myclient');
$definition->addMethodCall('push', [Middleware::retry([$this, 'retryDecider'])]);

答案 1 :(得分:3)

之前提到了编译器传递。这是一种选择。

使用工厂创建实例

但您也可以几乎直接在您的服务定义中表达这一点。我说几乎,因为你需要某种代码,因为Symfony服务定义不能(AFAIK)评估为Closure - 这就是我们对Guzzle Middleware所需要的。

我写了这个services.yml作为例子:

m6web_guzzlehttp.guzzle.handlerstack.myclient:
    class: GuzzleHttp\HandlerStack
    factory: ['GuzzleHttp\HandlerStack', create]

retry_decider:
    class: MyBundle\RetryDecider
    factory: ['MyBundle\RetryDecider', createInstance]

retry_handler:
    class: GuzzleHttp\Middleware
    factory: ['GuzzleHttp\Middleware', retry]
    arguments:
        - '@retry_decider'

handlerstack_pushed:
    parent: m6web_guzzlehttp.guzzle.handlerstack.myclient
    calls:
        - [push, ['@retry_handler']]

什么是什么?

  • m6web_guzzlehttp.guzzle.handlerstack.myclient - 您的动态服务 - 从已经创建的示例中删除示例。
  • retry_decider - 你的决策者。我们在createInstance方法中返回一个Closure。如果需要,可以添加更多参数,只需在YML中添加参数即可。
  • retry_handler - 这里我们使用我们的决策程序
  • 组成中间件
  • handlerstack_pushed - 这里我们将push()我们的处理程序放入堆栈,使用动态服务作为父服务。

Etvoilà - 我们拥有动态服务定义的堆栈,但推送了我们的重试中间件。

以下是我们决策者的来源:

<?php

namespace MyBundle;

class RetryDecider {

    public static function createInstance() {
        return function() {
            // do your deciding here
        };
    }

}

- &GT;您现在拥有服务handlerstack_pushed,这是完整的堆栈。

配置更多

请注意,您可以将m6web_guzzlehttp.guzzle.handlerstack.myclient添加到parameters.yml

parameters:
    baseHandlerStackService: m6web_guzzlehttp.guzzle.handlerstack.myclient

然后在handlerstack_pushed上使用它:

handlerstack_pushed:
    parent: "%baseHandlerStackService%"
    calls:
        - [push, ['@retry_handler']]

就像那样更好; - )

答案 2 :(得分:1)

您可以编写一个compiler pass来抓取有问题的定义,并将方法调用添加到其中。