Когда я пытаюсь вставить @request в любую из моих служб, я получаю это исключение:
ScopeWideningInjectionException: Область расширения Расширение Инъекция обнаружена: Определение "service.navigation" ссылается на запрос "запрос" , который относится к более узкому пространству. Как правило, безопаснее переместите "service.navigation" в область "запрос" или, альтернативно, полагайтесь на шаблона поставщика путем ввода самого контейнера и запроса "запрос" услуги каждый раз, когда это необходимо. В редких особых случаях однако это может быть необязательно, тогда вы можете установить ссылку на 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, где вам нужно вставлять контейнер.
И ядро даже не упоминается на странице в области. Инъекция ядра намного хуже (концептуально), чем инъекция контейнера.
UPDATE: для 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: Этот ответ был написан в 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 (например, во время модульного тестирования).
kernel -> getContainer()
возвращает service_container, лучше внедрить его вместо ядра (как указано в документации). Я уже arguments: [@service_container]
и он отлично работает - не нужно проходить ядро.
То, как я нашел, и я уверен, что это, вероятно, не самый лучший способ (даже не рекомендуется), заключается в том, чтобы определить службу запросов как синтетическую.
Правка: действительно, это не рекомендуется, поскольку оно отключает проверку уровня видимости области. Этот поток содержит хорошее объяснение того, почему 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 лучше разместить свою службу в области запроса или просто ввести контейнер службы.
Если вы не можете напрямую использовать RequestStack, вы можете создать службу factory, которая возвращает текущий запрос с помощью RequestStack.
# services.yml
app.request:
class: Symfony\Component\HttpFoundation\RequestStack
factory: [ @request_stack, getCurrentRequest ]
Затем вы можете получить доступ к текущему запросу с помощью службы app.request
.
Я думаю, что более важно сосредоточиться на получении запроса вместо его установки. Я бы сделал что-то подобное решению @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"]
Теперь вы всегда уверены, что получаете правильный запрос, и вам не нужно беспокоиться о настройке/повторной настройке запроса.
Как @simshaun заявляет о своей лучшей практике разместить свое обслуживание в области запроса. Это делает цель обслуживания понятной.
Примечание, что сделает вашу службу недоступной в других областях, таких как командная строка. Однако, если ваша служба зависит от запроса, вы все равно не должны использовать его в командной строке (потому что в командной строке нет запроса.
service.sample: class: Company\SiteBundle\Services\Sample arguments: [@request] public: true scope: request