44 votes

L'injection de SecurityContext dans un pré-écouteur ou une pré-actualisation de Listener dans Symfony2 pour obtenir l'utilisateur dans un createdBy ou updatedBy provoque une erreur de référenc

- Je configurer un port d'écoute en classe où je vais mettre le ownerid colonne sur toute doctrine prePersist. Mes services.fichier yml ressemble à ceci ...

services:
my.listener:
    class: App\SharedBundle\Listener\EntityListener
    arguments: ["@security.context"]
    tags:
        - { name: doctrine.event_listener, event: prePersist }

et ma classe ressemble à ceci ...

use Doctrine\ORM\Event\LifecycleEventArgs;
use Symfony\Component\Security\Core\SecurityContextInterface;

class EntityListener
{

protected $securityContext;

public function __construct(SecurityContextInterface $securityContext)
{
    $this->securityContext = $securityContext;
}


/**
 *
 * @param LifecycleEventArgs $args 
 */
public function prePersist(LifecycleEventArgs $args)
{

    $entity = $args->getEntity();
    $entityManager = $args->getEntityManager();

    $entity->setCreatedby();

}
}

Le résultat de ceci est l'erreur suivante.

ServiceCircularReferenceException: référence Circulaire détecté pour le service "de la doctrine.orm.default_entity_manager", chemin d'accès: "la doctrine.orm.default_entity_manager -> doctrine.dbal.default_connection -> mon.auditeur -> sécurité.contexte -> sécurité.l'authentification.manager -> fos_user.user_manager".

Mon hypothèse est que le contexte de sécurité a déjà été injecté quelque part dans la chaîne, mais je ne sais pas comment y accéder. Des idées?

68voto

gilden Points 6202

J'ai eu des problèmes similaires et la seule solution de contournement était de passer le conteneur entier dans le constructeur ( arguments: ['@service_container'] ).

 use Doctrine\ORM\Event\LifecycleEventArgs;
use Symfony\Component\DependencyInjection\ContainerInterface;

class MyListener
{
    protected $container;

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

    // ...

    public function prePersist(LifeCycleEventArgs $args)
    {
        $securityContext = $this->container->get('security.context');

        // ...
    }
}
 

36voto

Anyone Points 1386

Comme de Symfony 2.6 ce problème devrait être résolu. Une demande d'extraction a été accepté dans le maître. Votre problème est décrit ici. https://github.com/symfony/symfony/pull/11690

Comme de Symfony 2.6, on peut injecter de l' security.token_storage à votre écoute. Ce service permettra de contenir le jeton comme utilisé par l' SecurityContext à <=2.5. Dans la version 3.0 ce service vous permettra de remplacer l' SecurityContext::getToken() tout à fait. Vous pouvez voir un changement de base de la liste ici: http://symfony.com/blog/new-in-symfony-2-6-security-component-improvements#deprecated-the-security-context-service

Exemple d'utilisation dans 2.6:

Votre configuration:

services:
    my.listener:
        class: App\SharedBundle\Listener\EntityListener
        arguments:
            - "@security.token_storage"
        tags:
            - { name: doctrine.event_listener, event: prePersist }


Votre Écouteur

namespace App\SharedBundle\Listener;

use Doctrine\ORM\Event\LifecycleEventArgs;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

class EntityListener
{
    private $token_storage;

    public function __construct(TokenStorageInterface $token_storage)
    {
        $this->token_storage = $token_storage;
    }

    public function prePersist(LifeCycleEventArgs $args)
    {
        $entity = $args->getEntity();
        $entity->setCreatedBy($this->token_storage->getToken()->getUsername());
    }
}


Pour une belle created_by exemple, vous pouvez utiliser https://github.com/hostnet/entity-blamable-component/blob/master/src/Listener/BlamableListener.php pour l'inspiration. Il utilise le hostnet/entité-tracker-composant qui fournit un événement spécial qui est déclenché lorsqu'une entité est modifiée au cours de votre demande. Il y a également un bundle pour configurer cela dans Symfony2

0voto

Calin Bolea Points 71

J'utilise la doctrine des fichiers de configuration pour définir preUpdate ou prePersist méthodes:

Projet\MainBundle\Entity\YourEntity: type: entité tableau: yourentities repositoryClass: Projet\MainBundle\Repository\YourEntitytRepository champs: id: type: entier id: vrai générateur: stratégie: AUTO

lifecycleCallbacks:
    prePersist: [methodNameHere]
    preUpdate: [anotherMethodHere]

Et les méthodes sont déclarées dans l'entité, de cette façon, vous n'avez pas besoin d'un auditeur, et si vous avez besoin d'une méthode plus générale, vous pouvez faire un BaseEntity garder que la méthode et de l'étendre aux autres entités de que. Espérons que cela aide!

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X