Injecting SecurityContext into a Listener prePersist or preUpdate in Symfony2 to get User in a createdBy or updatedBy Causes Circular Reference Error

前端 未结 4 1980
遥遥无期
遥遥无期 2020-11-29 01:38

I setup a listener class where i\'ll set the ownerid column on any doctrine prePersist. My services.yml file looks like this ...

services:
my.listener:
             


        
相关标签:
4条回答
  • 2020-11-29 02:15

    I use the doctrine config files to set preUpdate or prePersist methods:

    Project\MainBundle\Entity\YourEntity:
        type: entity
        table: yourentities
        repositoryClass: Project\MainBundle\Repository\YourEntitytRepository
        fields:
            id:
                type: integer
                id: true
                generator:
                    strategy: AUTO
    
        lifecycleCallbacks:
            prePersist: [methodNameHere]
            preUpdate: [anotherMethodHere]
    

    And the methods are declared in the entity, this way you don't need a listener and if you need a more general method you can make a BaseEntity to keep that method and extend the other entites from that. Hope it helps!

    0 讨论(0)
  • 2020-11-29 02:21

    There's a great answer already in this thread but everything changes. Now there're entity listeners classes in Doctrine: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html#entity-listeners-class

    So you can add an annotation to your entity like:

    /**
     * @ORM\EntityListeners({"App\Entity\Listener\PhotoListener"})
     * @ORM\Entity(repositoryClass="App\Repository\PhotoRepository")
     */
    class Photo 
    {
        // Entity code here...
    }
    

    And create a class like this:

    class PhotoListener
    {        
        private $container;
    
        function __construct(ContainerInterface $container)
        {
            $this->container = $container;
        }
    
        /** @ORM\PreRemove() */
        public function preRemoveHandler(Photo $photo, LifecycleEventArgs $event): void
        {
             // Some code here...
        }
    }
    

    Also you should define this listener in services.yml like that:

    photo_listener:
      class: App\Entity\Listener\PhotoListener
      public: false
      autowire: true
      tags:
        - {name: doctrine.orm.entity_listener}
    
    0 讨论(0)
  • 2020-11-29 02:31

    I had similar problems and the only workaround was to pass the whole container in the constructor (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');
    
            // ...
        }
    }
    
    0 讨论(0)
  • 2020-11-29 02:36

    As of Symfony 2.6 this issue should be fixed. A pull request has just been accepted into the master. Your problem is described in here. https://github.com/symfony/symfony/pull/11690

    As of Symfony 2.6, you can inject the security.token_storage into your listener. This service will contain the token as used by the SecurityContext in <=2.5. In 3.0 this service will replace the SecurityContext::getToken() altogether. You can see a basic change list here: http://symfony.com/blog/new-in-symfony-2-6-security-component-improvements#deprecated-the-security-context-service

    Example usage in 2.6:

    Your configuration:

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


    Your Listener

    namespace App\SharedBundle\Listener;
    
    use Doctrine\ORM\Event\LifecycleEventArgs;
    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());
        }
    }
    


    For a nice created_by example, you can use https://github.com/hostnet/entity-blamable-component/blob/master/src/Listener/BlamableListener.php for inspiration. It uses the hostnet/entity-tracker-component which provides a special event that is fired when an entity is changed during your request. There's also a bundle to configure this in Symfony2

    • https://github.com/hostnet/entity-tracker-component
    • https://github.com/hostnet/entity-tracker-bundle
    0 讨论(0)
提交回复
热议问题