Как внедрить @request в сервис? - PullRequest
50 голосов
/ 17 февраля 2012

Когда я пытаюсь внедрить @request в любой из моих сервисов, я получаю следующее исключение:

ScopeWideningInjectionException: Обнаружено расширение охвата области: определение «service.navigation» ссылается на запрос сервиса »«который принадлежит к более узкой области.Как правило, безопаснее либо переместить «service.navigation» в область «запрос», либо, альтернативно, полагаться на шаблон провайдера, внедряя сам контейнер и запрашивая «запрос» службы каждый раз, когда это необходимо.Однако в редких особых случаях, в которых это может не потребоваться, вы можете установить ссылку на strict = false, чтобы избавиться от этой ошибки.

Как лучше всего продолжить?Должен ли я попытаться установить это strict=false и как, или я НЕ должен вводить службу запросов, а вместо этого передавать ее службе через мой контроллер каждый раз, когда я вызываю нужные мне функции?

Другая возможность заключается ввнедрить ядро ​​и взять его оттуда, но в моем сервисе я использую только @router и @request, поэтому внедрение всего ядра было бы нерациональным.

Спасибо!

Ответы [ 9 ]

98 голосов
/ 10 декабря 2013

В 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

31 голосов
/ 18 февраля 2012

Я думаю, что могло быть какое-то недопонимание относительно того, что говорится в официальной документации.В большинстве случаев вы хотите внедрить запрос напрямую с атрибутом 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 ниже.

6 голосов
/ 19 июля 2012

Лучший способ, с помощью которого я нашел службу, использующую службу запросов, не полагаясь на весь контейнер и все же не требующую наличия области запроса, - создать службу 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']
4 голосов
/ 10 сентября 2015

Если вы не можете использовать RequestStack напрямую, вы можете создать фабричную службу, которая возвращает текущий запрос, используя RequestStack.

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

Затем вы можете получить доступ к текущему запросу, используя сервис app.request.

4 голосов
/ 17 февраля 2012

Способ, который я нашел, и я уверен, что это, вероятно, не самый лучший способ (может даже и не быть рекомендованным), - определить службу запросов как синтетическую.

Редактировать: Действительно, это не рекомендуется, поскольку оно отключает проверки работоспособности области. Эта ветка содержит хорошее объяснение того, почему 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>

Согласно документам , лучше, если вы поместите свой сервис в область запроса или просто добавите контейнер сервисов.

1 голос
/ 23 мая 2016

Я думаю, что более важно сосредоточиться на получении запроса, а не на его настройке. Я бы сделал что-то похожее на решение @ Blowski, за исключением использования геттера. Это очень похоже на пример документации .

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"]

Теперь вы всегда уверены, что получаете правильный запрос, и вам не нужно беспокоиться о настройке / переустановке запроса.

0 голосов
/ 07 сентября 2018

другой способ введения currentRequest напрямую:

сеттер впрыска:

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

или инжектор ограничителя:

arguments:
     $request: '@=service("request_stack").getCurrentRequest()'
0 голосов
/ 23 февраля 2012

Поскольку @simshaun заявляет о своей лучшей практике, поместите ваш сервис в область запроса. Это делает цель службы совершенно ясной.

Обратите внимание , что это сделает вашу службу недоступной в других областях, таких как командная строка. Однако, если ваша служба полагается на запрос, вам все равно не следует использовать его в командной строке (поскольку в командной строке нет запроса.

...