How to inject the @request into a service?

2020-01-28 03:31发布

When I try to inject the @request into any of my services, I get this exception:

ScopeWideningInjectionException: Scope Widening Injection detected: The definition "service.navigation" references the service "request" which belongs to a narrower scope. Generally, it is safer to either move "service.navigation" to scope "request" or alternatively rely on the provider pattern by injecting the container itself, and requesting the service "request" each time it is needed. In rare, special cases however that might not be necessary, then you can set the reference to strict=false to get rid of this error.

What is the best way to proceed? Should I try to set this strict=false and how, or should I NOT inject the request service, but rather pass it to the service through my controller each time I call functions I need?

Other possibility would be to inject the kernel and take it from there, but in my service I am using only @router and @request, so injecting the whole kernel would be irrational.

9条回答
何必那么认真
2楼-- · 2020-01-28 04:16

NB: This answer was written back in 2012, when Symfony 2.0 was out and then it was the good way to do! Please don't downvote any more :)


Today I went through same problem myself, so here are my 5 cents. According to the official documentation it is usually not required to inject request into your services. In your service class you can pass kernel container (injecting it is not a big overhead, as it sounds), and then access request like this:

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;
}

This code is also working fine when service is accessed in CLI (eg, during unit-testing).

查看更多
一夜七次
3楼-- · 2020-01-28 04:21

As @simshaun states its best practice to place your service in the request scope. This makes the purpose of the service quite clear.

Note that this will make your service unavailable in other scopes such as the command line. However if your service relies upon the request, you should not be using it on the command line anyway (because there is no request available on the command line.

查看更多
Deceive 欺骗
4楼-- · 2020-01-28 04:24

The way I've found, and I'm sure it's probably not the best way (May not even be recommended), is to define the request service as synthetic.

Edit: Indeed, this is not recommended, because it disables the scope sanity checks. This thread contains a good explanation of why Symfony is throwing that exception: http://groups.google.com/group/symfony-devs/browse_thread/thread/a7207406c82ef07a/e2626c00f5cb9749

In your services.xml:

<service id="request" synthetic="true" />

<service id="my_service" class="......">
    <argument type="service" id="request" />
</service>

Per the docs, it's better if you place your service in the request scope, or just inject the service container.

查看更多
登录 后发表回答