如何将@request注入服务?

Ton*_*nov 53 service dependency-injection symfony

当我尝试将@request注入我的任何服务时,我得到以下异常:

ScopeWideningInjectionException:检测范围扩展注入:定义"service.navigation"引用属于较窄范围的服务"请求".通常,将"service.navigation"移动到范围"请求"更安全,或者通过注入容器本身来依赖提供者模式,并在每次需要时请求服务"请求".在极少数情况下,特殊情况可能没有必要,那么您可以将引用设置为strict = false以消除此错误.

什么是最好的方法?我应该尝试设置这个strict=false以及如何,或者我应该不注入请求服务,而是每次调用我需要的函数时通过我的控制器将其传递给服务?

其他可能性是注入内核并从那里获取它,但在我的服务中我只使用@router和@request,因此注入整个内核将是不合理的.

谢谢!

Dan*_*ows 98

在Symfony 2.4中,这已经发生了变化.现在,您可以注入'request_stack'服务.

例如:

use Symfony\Component\HttpFoundation\RequestStack;

class MyService
{

    protected $request;

    public function setRequest(RequestStack $request_stack)
    {
        $this->request = $request_stack->getCurrentRequest();
    }

}
Run Code Online (Sandbox Code Playgroud)

在你的config.yml中:

services:
    my.service:
        class: Acme\DemoBundle\MyService
        calls:
            - [setRequest, ["@request_stack"]]
Run Code Online (Sandbox Code Playgroud)

完整文档在这里:http://symfony.com/blog/new-in-symfony-2-4-the-request-stack

  • @K.Weber你可以将`request_stack`注入到构造函数中,或者确实在执行构造函数之前(比如在`kernel.request` listener中). (3认同)
  • 该解决方案+1,并链接到相应的symfony博客帖子. (2认同)

Cer*_*rad 31

我认为官方文件说的可能存在一些误解.在大多数情况下,您确实希望直接使用scope="request"service元素上的属性注入请求.这使得Scope Widening消失了.

<service 
    id="zayso_core.openid.rpx" 
    class="Zayso\CoreBundle\Component\OpenidRpx" public="true" scope="request">
Run Code Online (Sandbox Code Playgroud)

或者在yml中

zayso_core.openid.rpx: 
    class: Zayso\CoreBundle\Component\OpenidRpx
    public: true
    scope: request
Run Code Online (Sandbox Code Playgroud)

它仅适用于需要注入容器的特定特殊情况,例如Twig扩展.

并且在范围页面中甚至没有提到内核.注入内核比注入容器要差得多(概念上).

更新:对于S2.4及更新版本,请使用@ Blowski的答案.

  • 这很奇怪,在YAML中它会是这样的:`service.sample:class:Company\SiteBundle\Services\Sample arguments:[@request] public:true scope:request` (6认同)

小智 6

我发现创建服务的最佳方式是使用请求服务,而不是依赖于整个容器,并且仍然不需要具有请求范围,就是创建一个接收容器的RequestInjector服务.然后将其注入要使用请求对象的服务中

class RequestInjector{

    protected $container;

    public function __construct(Container $container){

         $this->container = $container;
   }

    public function getRequest(){

        return $this->container->get('request');
    }
}

class SomeService{

    protected $requestInjector;

    public function __construct(RequestInjector $requestInjector){

        $this->requestInjector = $requestInjector;

    }
}     
Run Code Online (Sandbox Code Playgroud)

对于services.yml

request_injector:
    class: RequestInjector
    public: false
    arguments: ['@service_container']

some_service:
    class: SomeService
    arguments: ['@request_injector']
Run Code Online (Sandbox Code Playgroud)

  • 我不喜欢这种方法,你基本上仍然在某个时候注入整个容器并使用Service Locator反模式,你只是不知道它了.我没有看到这样的好处! (5认同)

Ant*_*nko 5

注意:这个答案是在2012年写的,那时Symfony 2.0已经推出,然后这是一个很好的方法!请不要再downvote :)


今天我自己也遇到了同样的问题,所以这是我的5美分.根据官方文档,通常不需要注入request您的服务.在您的服务类中,您可以传递kernel容器(注入它不是一个很大的开销,因为它听起来),然后request像这样访问:

public function __construct(\AppKernel $kernel)
{
    $this->kernel = $kernel;
}

public function getRequest()
{
    if ($this->kernel->getContainer()->has('request')) {
        $request = $this->kernel->getContainer()->get('request');
    } else {
        $request = Request::createFromGlobals();
    }
    return $request;
}
Run Code Online (Sandbox Code Playgroud)

当在CLI中访问服务时(例如,在单元测试期间),此代码也正常工作.

  • 是的,这很有效.只需稍加修改:由于`kernel - > getContainer()`返回一个service_container,最好注入它而不是内核(如文档所述).我已经做过`参数:[@ service_container]`并且它完美无缺 - 无需通过内核. (3认同)