12
votes

Référence circulaire lors de l'injection de contexte de sécurité dans la classe d'auditeur (auditeur d'entité)

Il y avait 2 questions ici indiquant l'injection de l'ensemble du conteneur de service devrait résoudre ce problème. Mais questionner ... Voir ci-dessous (nocturne différence entre TYP 2 & 3) ...

ESSAYER 1 STROND> P>

public function __construct(ContainerInterface $container) {
    $this->container = $container;  
}  


1 commentaires

Exemple de code complet s'il vous plaît. La référence circulaire signifie généralement que vous essayez d'injecter un service qui est déjà injecté d'une autre manière dans la même classe. (Le problème le plus populaire est le gestionnaire d'entité dans les auditeurs de doctrine)


4 Réponses :


24
votes

Cela se produit car votre contexte de sécurité dépend de cet auditeur, probablement via le gestionnaire d'entité étant injecté dans un fournisseur d'utilisateurs. La meilleure solution consiste à injecter le conteneur dans l'auditeur et à accéder au contexte de sécurité paresseusement.

Je n'aime généralement pas injecter tout le conteneur dans un service, mais faites une exception avec les auditeurs de doctrine, car ils sont chargés avec impatience et doivent donc être aussi paresseux que possible.


4 commentaires

Hmm, a du sens, mais je ne comprends pas comment "essayer 2" devrait échouer quand 3 réussit. Oui, son "paresseux" mais une variable d'instance gâche le fonctionnement d'une autre classe? Hmm ...


Le conteneur tient une trace de quels services il s'agit en cours de création. Si get () est appelé l'un de ces services qu'il est déjà en cours de création, une exception de référence circulaire est lancée. C'est pourquoi vous obtenez cette exception lorsque vous appelez le contexte de sécurité de l'intérieur du constructeur, mais pas autrement. Lorsque le constructeur est appelé, le conteneur travaille déjà sur la création du contexte de sécurité.


Injecter le conteneur n'est jamais «la meilleure solution». Je pense que la meilleure approche serait d'utiliser «Services paresseux».


Essayé de rendre les dépendances sur mon EventsDubscriber paresseusement chargé, mais qui a toujours entraîné la même référence circulaire: symfony.com/doc/current/service_container/lazy_services.html y aurait-il une autre façon de ne pas injecter le conteneur dans le service?



1
votes

La raison "2" échoue et "3" ne fait pas partie du fait de l'option 2, vous essayez d'accéder au contexte de sécurité immédiatement du conteneur lorsqu'il n'est probablement pas encore peuplé.

Au mieux que je puisse dire, Symfony2 analyse par la configuration et instancie le service après l'autre, puis se déplace sur la manipulation du reste de la demande.

Cela signifie que vous ne pouvez pas nécessairement accéder aux différentes parties du conteneur, car elle peut les charger dans un ordre différent. Vous disposez donc du pointeur de la mémoire sur le conteneur et de le stocker, mais laissez ensuite le cadre terminé la construction du conteneur complet avant d'essayer d'y accéder. Une exception notable à ceci est lorsque vous injectionnez directement le service dans un autre service, à quel point le conteneur veille à ce qu'il ait ce service chargé d'abord.

Vous pouvez voir les effets de cela en faisant deux services. A et B. A est passé B et B est passé A. Maintenant, vous avez une référence circulaire. Si vous avez plutôt transmis le conteneur dans A et B, vous ne pouvez pas accéder à A de B et B de A Sans problème.


0 commentaires

8
votes

AS de Symfony 2.6 Ce problème devrait être corrigé. Une demande de traction vient d'être acceptée dans le maître. Votre problème est décrit ici. https://github.com/symfony/symfony/pull/11690

AS de Symfony 2.6, vous peut injecter le Security.Token_storage dans votre auditeur. Ce service contiendra le jeton utilisé par le SecurityContext dans <= 2.5. Dans 3.0 Ce service remplacera le SecurityContext :: getToken () complètement. Vous pouvez voir une liste de modifications de base ici: http://symfony.com/blog/new-in-symfony-2-6-Security-Component-improvements#depecated-Le-Security-Context-Service

Exemple d'utilisation 2.6:

votre configuration: xxx

< votre auditeur xxx


0 commentaires

1
votes

Vous devez toujours essayer d'éviter l'injection de conteneur directement à vos services.

Je pense que la meilleure solution possible au problème «référence circulaire» ainsi qu'aux problèmes de performances possibles, seraient d'utiliser « Services paresseux » Disponible à partir de Symfony 2.3.

Il suffit de marquer votre dépendance comme paresseux dans votre configuration de conteneur de service et installez le pont proxyManager (rechercher des détails dans la documentation des services paresseux ci-dessus).

J'espère que cela aide, acclamations.


1 commentaires

Cela m'a aidé dans mon cas. Mais il est un peu étrange que Ocramius / Proxy-Manager Bibliothèque (nécessaire pour que cette fonction soit capable d'utiliser) nécessite deux bibliothèques Zendframework. Compte tenu de ces dépendances, je doute que l'utilisation de chargement paresseux pour pas trop gros graphiques de service donne un avantage rapide.