Come iniettare @request in un servizio?

Quando provo a iniettare @request in uno qualsiasi dei miei servizi, ottengo questa eccezione:

ScopeWideningInjectionException: Rilevazione dell’ampiezza dell’oscilloscopio rilevata: la definizione “service.navigation” fa riferimento alla “richiesta” di servizio che appartiene a un ambito più ristretto. In generale, è più sicuro spostare “service.navigation” su scope “request” o in alternativa fare affidamento sul modello del provider iniettando il contenitore stesso e richiedendo il servizio “request” ogni volta che è necessario. In rari casi speciali, tuttavia, che potrebbero non essere necessari, è ansible impostare il riferimento a strict = false per eliminare questo errore.

Qual è il modo migliore di procedere? Dovrei provare a impostare strict=false e come, o NON dovrei iniettare il servizio di richiesta, ma piuttosto passarlo al servizio attraverso il mio controller ogni volta che chiamo funzioni di cui ho bisogno?

Un’altra possibilità sarebbe quella di iniettare il kernel e portarlo da lì, ma nel mio servizio sto usando solo @router e @request, quindi iniettare l’intero kernel sarebbe irrazionale.

Grazie!

Penso che possa esserci stato qualche malinteso su ciò che dice la documentazione ufficiale. Nella maggior parte dei casi, si desidera iniettare la richiesta direttamente con un attributo scope="request" sull’elemento del servizio. Questo fa sparire l’ampliamento dell’oscilloscopio.

  

o in yml

 zayso_core.openid.rpx: class: Zayso\CoreBundle\Component\OpenidRpx public: true scope: request 

È solo in casi particolari specifici come le estensioni di Twig dove è necessario iniettare il contenitore.

E il kernel non è nemmeno menzionato nella pagina sugli ambiti. Iniettare il kernel è molto peggio (concettualmente) dell’iniettare un contenitore.

AGGIORNAMENTO: per S2.4 e versioni successive, utilizzare la risposta di @ Blowski di seguito.

In Symfony 2.4, questo è cambiato. Ora puoi inserire il servizio ‘request_stack’.

Per esempio:

 use Symfony\Component\HttpFoundation\RequestStack; class MyService { protected $request; public function setRequest(RequestStack $request_stack) { $this->request = $request_stack->getCurrentRequest(); } } 

Nel tuo config.yml:

 services: my.service: class: Acme\DemoBundle\MyService calls: - [setRequest, ["@request_stack"]] 

La documentazione completa è disponibile qui: http://symfony.com/blog/new-in-symfony-2-4-the-request-stack

Il modo migliore in cui ho trovato che un servizio utilizza il servizio di richiesta, non si basa sull’intero contenitore e non è ancora richiesto di avere l’ambito di richiesta, era quello di creare un servizio RequestInjector che prende il contenitore. quindi lo si inietta nel servizio che vuole utilizzare l’object richiesta

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

per services.yml

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

Il modo in cui ho trovato, e sono sicuro che probabilmente non è il modo migliore (potrebbe anche non essere raccomandato), è quello di definire il servizio di richiesta come sintetico.

Modifica: in effetti, questo non è raccomandato, poiché disabilita i controlli di integrità dell’ambito. Questa discussione contiene una buona spiegazione del motivo per cui Symfony lancia questa eccezione: http://groups.google.com/group/symfony-devs/browse_thread/thread/a7207406c82ef07a/e2626c00f5cb9749

Nel tuo services.xml :

     

Per i documenti , è meglio se si posiziona il proprio servizio nell’ambito della richiesta, o semplicemente si inietta il contenitore del servizio.

NB: Questa risposta è stata scritta nel 2012, quando Symfony 2.0 era fuori e quindi era il modo migliore per farlo! Si prega di non più downvote 🙂


Oggi ho subito lo stesso problema, quindi ecco i miei 5 centesimi. Secondo la documentazione ufficiale di solito non è richiesto di iniettare una request nei tuoi servizi. Nella tua class di servizio puoi passare il contenitore del kernel (iniettarlo non è un grande sovraccarico, come sembra), e quindi accedere alla request questo modo:

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

Anche questo codice funziona correttamente quando si accede al servizio in CLI (ad es. Durante il test dell’unità).

Se non è ansible utilizzare direttamente RequestStack, è ansible creare un servizio di fabbrica che restituisca la richiesta corrente utilizzando RequestStack.

 # services.yml app.request: class: Symfony\Component\HttpFoundation\RequestStack factory: [ @request_stack, getCurrentRequest ] 

Quindi puoi accedere alla richiesta corrente utilizzando il servizio app.request .

Penso che sia più importante concentrarsi su come ottenere la richiesta invece di impostarla. Vorrei fare qualcosa di simile alla soluzione di @ Blowski, tranne che usando un getter. Questo è molto simile all’esempio della documentazione .

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

E il tuo file di configurazione services.yml.

 services: newsletter_manager: class: Acme\HelloBundle\Newsletter\NewsletterManager arguments: ["@request_stack"] 

Ora sei sempre sicuro che stai ricevendo la richiesta corretta e non devi preoccuparti di impostare / reimpostare la richiesta.

un altro modo per iniettare direttamente la richiesta:

iniezione setter:

 calls: - ['setRequest', ["@=service('request_stack').getCurrentRequest"]] 

o iniezione del limitatore:

 arguments: $request: "@=service('request_stack').getCurrentRequest" 

Come @simshaun afferma la sua migliore pratica per inserire il tuo servizio nell’ambito della richiesta. Questo rende lo scopo del servizio abbastanza chiaro.

Notare che ciò renderà il servizio non disponibile in altri ambiti come la riga di comando. Tuttavia, se il tuo servizio si basa sulla richiesta, non dovresti usarlo comunque sulla riga di comando (perché non c’è richiesta disponibile sulla riga di comando.