wake-up-neo.com

Wie füge ich die @ -Anfrage in einen Dienst ein?

Wenn ich versuche, die @ -Anfrage in einen meiner Dienste zu injizieren, erhalte ich folgende Ausnahme:

ScopeWideningInjectionException: Scope Wandering Injection erkannt: Die Definition "service.navigation" verweist auf die Dienst "request" das gehört zu einem engeren Bereich. Im Allgemeinen ist es sicherer, entweder Verschieben Sie "service.navigation" in den Bereich "request" oder verlassen Sie sich alternativ auf das Anbietermuster, indem der Container selbst eingespritzt wird und Der Dienst "fordert" jedes Mal an, wenn es benötigt wird. In seltenen Sonderfällen Dies ist jedoch möglicherweise nicht erforderlich. Dann können Sie die Referenz auf .__ setzen. strict = false, um diesen Fehler zu beseitigen.

Wie gehe ich am besten vor? Sollte ich versuchen, diesen strict=false und wie festzulegen, oder sollte ich den Anfragedienst NICHT einspeisen, sondern ihn bei jedem Aufruf von Funktionen, die ich benötige, über meinen Controller an den Dienst übergeben?

Eine andere Möglichkeit wäre, den Kernel zu injizieren und von dort zu übernehmen, aber in meinem Dienst verwende ich nur @router und @request. Das Injizieren des gesamten Kernels wäre also irrational.

Vielen Dank!

50
Tony Bogdanov

Ich denke, dass es einige Missverständnisse darüber gegeben hat, was in der offiziellen Dokumentation steht. In den meisten Fällen möchten Sie die Anforderung direkt mit einem scope="request"-Attribut für das Serviceelement einfügen. Dadurch wird die Scope-Verbreiterung entfernt.

<service 
    id="zayso_core.openid.rpx" 
    class="Zayso\CoreBundle\Component\OpenidRpx" public="true" scope="request">

oder in yml

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

Nur in bestimmten speziellen Fällen, wie Twig-Erweiterungen, müssen Sie den Behälter injizieren.

Und der Kernel wird auf der Seite zu den Bereichen nicht einmal erwähnt. Das Einspritzen des Kernels ist (konzeptionell) weitaus schlimmer als das Einspritzen eines Containers.

UPDATE: Für S2.4 und neuer verwenden Sie die Antwort von @ Blowski.

31
Cerad

In Symfony 2.4 hat sich dies geändert. Jetzt können Sie den Dienst 'request_stack' einfügen.

Zum Beispiel:

use Symfony\Component\HttpFoundation\RequestStack;

class MyService
{

    protected $request;

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

}

In Ihrer config.yml:

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

Die vollständige Dokumentation finden Sie hier: http://symfony.com/blog/new-in-symfony-2-4-the-request-stack

96
Dan Blows

Der beste Weg, einen Dienst für die Verwendung des Anfragedienstes zu verwenden, nicht auf den gesamten Container angewiesen zu sein und nicht für den Anforderungsumfang erforderlich zu sein, bestand darin, einen RequestInjector-Dienst zu erstellen, der den Container übernimmt. dann injizieren Sie das in den Dienst, der das Anforderungsobjekt verwenden möchte

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;

    }
}     

für services.yml

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

some_service:
    class: SomeService
    arguments: ['@request_injector']
6
yderay

Der Weg, den ich gefunden habe, und ich bin sicher, es ist wahrscheinlich nicht der beste Weg (kann nicht einmal empfohlen werden), den Anforderungsservice als synthetisch zu definieren.

Bearbeiten: Dies wird in der Tat nicht empfohlen, da die Überprüfung des Gültigkeitsbereichs deaktiviert ist. Dieser Thread enthält eine gute Erklärung, warum Symfony diese Ausnahme auslöst: http://groups.google.com/group/symfony-devs/browse_thread/thread/a7207406c82ef07a/e2626c00f5cb9749

In deinem services.xml:

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

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

Nach dem docs ist es besser, wenn Sie Ihren Dienst in den Anforderungsbereich einordnen oder einfach den Dienstcontainer einschleusen.

5
simshaun

NB: Diese Antwort wurde im Jahr 2012 geschrieben, als Symfony 2.0 herauskam und dann war es der richtige Weg! Bitte nicht mehr abstimmen :)


Heute habe ich dasselbe Problem selbst durchgemacht, hier also meine 5 Cent. Gemäß der offiziellen Dokumentation ist es normalerweise nicht erforderlich, request in Ihre Dienste einzufügen. In Ihrer Service-Klasse können Sie kernel-Container übergeben (das Einspritzen ist kein großer Aufwand, wie es klingt) und dann auf request wie folgt zugreifen:

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

Dieser Code funktioniert auch gut, wenn auf den Dienst in der CLI zugegriffen wird (z. B. während des Komponententests).

5
Anton Babenko

Wenn Sie RequestStack nicht direkt verwenden können, können Sie einen Factory-Service erstellen, der die aktuelle Anforderung mithilfe von RequestStack zurückgibt.

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

Anschließend können Sie mit dem Dienst app.request auf die aktuelle Anforderung zugreifen.

4
mloberg

Ich denke, es ist wichtiger, sich auf die Anforderung zu konzentrieren, anstatt sie zu setzen. Ich würde etwas Ähnliches zu @ Blowskis Lösung tun, außer einen Getter zu verwenden. Dies ist dem Beispiel von documentation sehr ähnlich.

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

Und Ihre services.yml-Konfigurationsdatei.

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

Jetzt sind Sie immer sicher, dass Sie die richtige Anfrage erhalten, und Sie müssen sich keine Gedanken darüber machen, ob Sie die Anfrage setzen oder neu einstellen.

1
GreeKatrina

eine andere Möglichkeit, currentRequest direkt zu injizieren:

setterinjektion: 

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

oder constrauctor Injektion:

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