Lorsque j'essaie d'injecter la @ demande dans l'un de mes services, j'obtiens cette exception:
ScopeWideningInjectionException: injection d'élargissement de la portée détectée: La définition "service.navigation" fait référence au service "demande" qui appartient à une portée plus étroite. Généralement, il est plus sûr de l’un ou l’autre déplacez "service.navigation" vers la portée "demande" ou utilisez le système le modèle de fournisseur en injectant le conteneur lui-même et en demandant le service "demande" à chaque fois que cela est nécessaire. Dans de rares cas spéciaux cependant, cela peut ne pas être nécessaire, vous pouvez alors définir la référence sur strict = false pour se débarrasser de cette erreur.
Quelle est la meilleure façon de procéder? Devrais-je essayer de définir ce strict=false
et comment, ou dois-je NE PAS injecter le service de requête, mais plutôt le transmettre au service par le biais de mon contrôleur chaque fois que j'appelle les fonctions dont j'ai besoin?
Une autre possibilité serait d’injecter le noyau et de l’utiliser à partir de là, mais dans mon service, j’utilise uniquement @router et @request, l’injection de tout le noyau serait donc irrationnelle.
Merci!
Je pense qu'il y a peut-être eu un malentendu sur ce que dit la documentation officielle. Dans la plupart des cas, vous souhaitez injecter directement la demande avec un attribut scope="request"
sur l'élément de service. Cela fait disparaître l'élargissement de la portée.
<service
id="zayso_core.openid.rpx"
class="Zayso\CoreBundle\Component\OpenidRpx" public="true" scope="request">
ou dans yml
zayso_core.openid.rpx:
class: Zayso\CoreBundle\Component\OpenidRpx
public: true
scope: request
Ce n'est que dans des cas particuliers, tels que les extensions Twig, que vous devez injecter le conteneur.
Et le noyau n'est même pas mentionné dans la page sur les portées. L'injection du noyau est bien pire (conceptuellement) que l'injection d'un conteneur.
UPDATE: Pour la version 2.4 ou ultérieure, utilisez la réponse de @ Blowski ci-dessous.
Dans Symfony 2.4, cela a changé. Maintenant, vous pouvez injecter le service 'request_stack'.
Par exemple:
use Symfony\Component\HttpFoundation\RequestStack;
class MyService
{
protected $request;
public function setRequest(RequestStack $request_stack)
{
$this->request = $request_stack->getCurrentRequest();
}
}
Dans votre config.yml:
services:
my.service:
class: Acme\DemoBundle\MyService
calls:
- [setRequest, ["@request_stack"]]
La documentation complète est ici: http://symfony.com/blog/new-in-symfony-2-4-the-request-stack
Le meilleur moyen que j'ai trouvé pour faire en sorte qu'un service utilise le service de demande, ne repose pas sur le conteneur entier et ne soit toujours pas obligé d'avoir l'étendue de la demande, était de créer un service RequestInjector prenant le conteneur. alors vous injectez cela dans le service qui veut utiliser l'objet de requête
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;
}
}
pour services.yml
request_injector:
class: RequestInjector
public: false
arguments: ['@service_container']
some_service:
class: SomeService
arguments: ['@request_injector']
La façon dont j'ai trouvé, et je suis sûr que ce n'est probablement pas la meilleure façon (peut même pas être recommandé), est de définir le service de demande comme étant synthétique.
Edit: En effet, ce n'est pas recommandé, car il désactive les contrôles de validité de l'étendue. Ce fil contient une bonne explication de la raison pour laquelle Symfony lève cette exception: http://groups.google.com/group/symfony-devs/browse_thread/thread/a7207406c82ef07a/e2626c00f5cb9749
Dans votre services.xml
:
<service id="request" synthetic="true" /> <service id="my_service" class="......"> <argument type="service" id="request" /> </service>
Selon le docs, il est préférable de placer votre service dans l'étendue de la demande ou simplement d'injecter le conteneur de service.
NB: Cette réponse a été écrite en 2012, lorsque Symfony 2.0 était disponible et que c'était la bonne façon de le faire! S'il vous plaît ne plus downvote :)
Aujourd'hui, j'ai vécu le même problème moi-même, alors voici mes 5 centimes. Selon la documentation officielle il n’est généralement pas nécessaire d’injecter request
dans vos services. Dans votre classe de service, vous pouvez passer le conteneur kernel
(l'injecter ne représente pas une surcharge importante, comme cela semble), puis accéder à request
comme ceci:
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;
}
Ce code fonctionne également bien lorsque vous accédez au service dans l'interface de ligne de commande (par exemple, lors des tests unitaires).
Si vous ne pouvez pas utiliser RequestStack directement, vous pouvez créer un service d'usine qui renvoie la demande en cours à l'aide de RequestStack.
# services.yml
app.request:
class: Symfony\Component\HttpFoundation\RequestStack
factory: [ @request_stack, getCurrentRequest ]
Ensuite, vous pouvez accéder à la demande en cours à l’aide du service app.request
.
Je pense qu'il est plus important de chercher à obtenir la demande au lieu de la définir. Je ferais quelque chose de similaire à la solution de @ Blowski, excepté l'utilisation d'un getter. Ceci est très similaire à l'exemple de documentation .
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
}
}
Et votre fichier de configuration services.yml.
services:
newsletter_manager:
class: Acme\HelloBundle\Newsletter\NewsletterManager
arguments: ["@request_stack"]
Maintenant, vous êtes toujours sûr d'obtenir la demande correcte et vous n'avez pas à vous soucier de la définition/modification de la demande.
une autre façon d’injecter currentRequest
directement:
injection de poseur:
calls:
- ['setRequest', ['@=service("request_stack").getCurrentRequest()']]
ou injection de constricteur:
arguments:
$request: '@=service("request_stack").getCurrentRequest()'