How I can get the current user into my entity classes?

后端 未结 2 1513
甜味超标
甜味超标 2021-01-21 22:57

I am developing my first Symfony 4 application and I migrating from Symfony 2+ and symfony 3+.

Right now I am developing a back-end and all of my entity classes have a <

相关标签:
2条回答
  • 2021-01-21 23:19

    First, to simplify matters and help down the road I would create an interface this user-tracking entities would need to comply with:

    interface UserTracking
    {
        public function addedBy(UserInterface $user);
        public function updatedby(UserInterface $user);
        public function getAddedBy(): ?UserInterface;
        public function getUpdatedBy(): ?UserInterface;
    }
    

    Then you can create a Doctrine event listener, and inject the Security component there:

    class UserDataListener 
    {
        protected $security;
    
        public function __construct(Security $security)
        {
            $this->security = $security;
        }
    
        public function prePersist(LifecycleEventArgs $event): void
        {
            $entity =  $event->getObject();
            $user   = $this->security->getUser();
    
            // only do stuff if $entity cares about user data and we have a logged in user
            if ( ! $entity instanceof UserTracking || null === $user ) {
                return;
            }
    
            $this->setUserData($entity, $user);
        }
    
        private function preUpdate(LifecycleEventArgs $event) {
            $this->prePersist($event);
        } 
    
        private function setUserData(UserTracking $entity, UserInterface $user)
        {
    
            if (null === $entity->getAddedBy()) {
                $entity->addedBy($user);
            }
    
            $entity->updatedBy($user);
        }
    }    
    

    You'd need to tag the listener appropriately, so it triggers on prePersist and preUpdate:

    services:
      user_data_listener:
        class: App\Infrastructure\Doctrine\Listener\UserDataListener
        tags:
          - { name: doctrine.event_listener, event: prePersist }
          - { name: doctrine.event_listener, event: preUpdate }
    

    While the above should work, I believe it's generally not such a great idea to use Doctrine events this way, since you are coupling your domain logic with Doctrine, and are hiding changing under a layer of magic that may not be immediately evident for other developers working with your application.

    I'd put the createdBy as a constructor parameter, and set updateBy explicitly when needed. It's just one line of code each time, but you gain clarity and expressiveness, and you have a simpler system with less moving parts.

    class FooEntity
    {    
        private $addedBy;
        private $updatedBy;
        public function __construct(UserInterface $user)
        {
            $this->addedBy = $user;
        }
    
        public function updatedBy(UserInterface $user)
        {
            $this->updatedBy = $user;
        }
    }
    

    This expresses much better what's happening with the domain, and future coders in your application do no have to dig around for the possible extensions you may have installed and enabled, or what events are being triggered.

    0 讨论(0)
  • 2021-01-21 23:25

    You probably do not want to reinvent the wheel. There is the Blameable Doctrine Extension that already does that. You can install it with :

    composer require antishov/doctrine-extensions-bundle
    

    As there is already a recipe to configure it. Then you can activate the extension and then use it with something like :

    Specific documentation for the Blameable extension can be found here

    use Gedmo\Mapping\Annotation as Gedmo;
    
    class Post {
    
      /**
      * @var User $createdBy
      *
      * @Gedmo\Blameable(on="create")
      * @ORM\ManyToOne(targetEntity="App\Entity\User")
      */
      private $createdBy;
    
    }
    
    0 讨论(0)
提交回复
热议问题