サービスに@requestを挿入しようとすると、次の例外が発生します。
ScopeWideningInjectionException:スコープ拡大インジェクションの検出:定義「service.navigation」は、より狭いスコープに属するサービス「リクエスト」を参照しています。通常、「service.navigation」をスコープ「request」に移動するか、コンテナ自体をインジェクトし、必要なたびにサービス「request」を要求することでプロバイダーパターンに依存する方が安全です。ただし、まれな特殊なケースで必要ではない場合は、参照をstrict = falseに設定してこのエラーを取り除くことができます。
続行する最善の方法は何ですか?このstrict=false
を設定しようとする必要がありますか、または要求サービスを注入するのではなく、必要な関数を呼び出すたびにコントローラーを介してサービスに渡しますか?
他の可能性は、カーネルをインジェクトしてそこから取得することですが、私のサービスでは@routerと@requestのみを使用しているため、カーネル全体をインジェクトするのは非合理的です。
公式文書に書かれていることについて誤解があったのではないかと思います。ほとんどの場合、サービス要素のscope="request"
属性を使用してリクエストを直接挿入する必要があります。これにより、スコープの拡大がなくなります。
<service
id="zayso_core.openid.rpx"
class="Zayso\CoreBundle\Component\OpenidRpx" public="true" scope="request">
またはyml
zayso_core.openid.rpx:
class: Zayso\CoreBundle\Component\OpenidRpx
public: true
scope: request
Twigエクステンションなど、コンテナをインジェクトする必要がある特定の特別な場合のみです。
また、スコープのページでもカーネルについて言及されていません。カーネルの注入は、コンテナの注入よりも(概念的に)はるかに悪いです。
更新:S2.4以降では、以下の@Blowskiの回答を使用してください。
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();
}
}
Config.ymlで:
services:
my.service:
class: Acme\DemoBundle\MyService
calls:
- [setRequest, ["@request_stack"]]
完全なドキュメントはこちら: http://symfony.com/blog/new-in-symfony-2-4-the-request-stack
コンテナ全体に依存せず、リクエストスコープを持つ必要がないサービスにリクエストサービスを使用させる最良の方法は、コンテナを取得する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;
}
}
services.ymlの
request_injector:
class: RequestInjector
public: false
arguments: ['@service_container']
some_service:
class: SomeService
arguments: ['@request_injector']
NB:この回答は、Symfony 2.0がリリースされた2012年に書き戻され、それが良い方法でした!これ以上降格しないでください:)
今日、私は同じ問題を自分で経験したので、ここに私の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;
}
このコードは、CLIでサービスにアクセスするとき(たとえば、単体テスト中)でも正常に機能しています。
私が見つけた方法は、おそらくそれが最善の方法ではないことを確信しています(推奨されないこともあります)、要求サービスを合成として定義することです。
編集:確かに、これは推奨されません。スコープの健全性チェックを無効にするためです。このスレッドには、Symfonyがその例外をスローする理由の説明が含まれています: http://groups.google .com/group/symfony-devs/browse_thread/thread/a7207406c82ef07a/e2626c00f5cb9749
あなたのservices.xml
:
<service id="request" synthetic="true" /> <service id="my_service" class="......"> <argument type="service" id="request" /> </service>
docsに従って、サービスをリクエストスコープに配置するか、単にサービスコンテナを挿入する方が良いでしょう。
RequestStackを直接使用できない場合は、RequestStackを使用して現在の要求を返すファクトリサービスを作成できます。
# services.yml
app.request:
class: Symfony\Component\HttpFoundation\RequestStack
factory: [ @request_stack, getCurrentRequest ]
その後、app.request
サービスを使用して現在のリクエストにアクセスできます。
リクエストを設定するのではなく、リクエストを取得することに集中することがより重要だと思います。ゲッターを使用することを除いて、@ Blowskiのソリューションと同様のことを行います。これは documentation の例に非常に似ています。
namespace Acme\HelloBundle\Newsletter;
use Symfony\Component\HttpFoundation\RequestStack;
class NewsletterManager
{
protected $requestStack;
public function __construct(RequestStack $requestStack)
{
$this->requestStack = $requestStack;
}
protected function getRequest()
{
return $this->requestStack->getCurrentRequest();
}
public function foo()
{
$request = $this->getRequest();
// Do something with the request
}
}
そして、services.yml設定ファイル。
services:
newsletter_manager:
class: Acme\HelloBundle\Newsletter\NewsletterManager
arguments: ["@request_stack"]
これで、正しいリクエストを取得していることを常に確認でき、リクエストの設定/再設定について心配する必要がなくなりました。
currentRequest
を直接注入する別の方法:
セッター注入:
calls:
- ['setRequest', ['@=service("request_stack").getCurrentRequest()']]
またはコンストラクター注入:
arguments:
$request: '@=service("request_stack").getCurrentRequest()'