Как ввести @request в службу? - программирование
Подтвердить что ты не робот

Как ввести @request в службу?

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

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

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

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

Спасибо!

4b9b3361

Ответ 1

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

И ядро ​​даже не упоминается на странице в области. Инъекция ядра намного хуже (концептуально), чем инъекция контейнера.

UPDATE: для S2.4 и новее используйте @Blowski ответ ниже.

Ответ 2

В 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

Ответ 3

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

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

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

Забастовкa >

В docs лучше разместить свою службу в области запроса или просто ввести контейнер службы.

Ответ 5

NB: Этот ответ был написан в 2012 году, когда Symfony 2.0 вышел, и тогда это был хороший способ сделать! Пожалуйста, не спускайте вниз:)


Сегодня я сам пережил одну и ту же проблему, так что вот мои 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 (например, во время модульного тестирования).

Ответ 6

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

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

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

Ответ 7

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

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

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

Ответ 8

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

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