如何让当前用户进入我的实体 类?

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

我正在开发我的第一个 Symfony 4 应用程序,我正在从 Symfony 2+ 和 symfony 3+ 迁移。

现在我正在开发一个后端,我的所有实体 类 都有一个 addedBy()updatedBy() 方法,我需要在其中记录当前登录的管理员。

我想要一个类似事件侦听器的东西,这样我就不必在所有控制器中设置这些方法。

如何实现?

首先,为了简化问题并在以后提供帮助,我将创建一个该用户跟踪实体需要遵守的界面:

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

然后你可以创建一个 Doctrine 事件侦听器,并在那里注入 Security 组件:

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);
    }
}    

您需要适当地标记侦听器,因此它会在 prePersistpreUpdate 上触发:

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

虽然上面的方法应该有效,我认为以这种方式使用 Doctrine 事件通常不是一个好主意,因为你正在将你的域逻辑与 Doctrine 耦合,并且正在隐藏在使用您的应用程序的其他开发人员可能不会立即显现的魔法层下进行更改。

我将 createdBy 作为构造函数参数,并在需要时显式设置 updateBy。每次只是一行代码,但您获得了清晰度和表现力,并且您拥有了一个包含更少活动部件的更简单的系统。

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

    public function updatedBy(UserInterface $user)
    {
        $this->updatedBy = $user;
    }
}

这更好地表达了域中发生的事情,您的应用程序中的未来编码人员不必四处寻找您可能已安装和启用的可能扩展,或正在触发的事件。

您可能不想重新发明轮子。 Blameable Doctrine Extension 已经这样做了。您可以使用 :

安装它
composer require antishov/doctrine-extensions-bundle

因为已经有配置它的配方。然后你可以 activate the extension 然后将它与类似的东西一起使用:

Blameable 扩展的特定文档 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;

}