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

Php 如何让当前用户进入我的实体类?,php,symfony,doctrine-orm,doctrine,symfony4,Php,Symfony,Doctrine Orm,Doctrine,Symfony4,我正在开发我的第一个Symfony 4应用程序,并从Symfony 2+和Symfony 3+进行迁移 现在我正在开发一个后端,我的所有实体类都有一个addedBy()和updatedBy()方法,我需要记录当前登录的管理员 我希望有一个类似事件监听器的东西,我不必在所有控制器中设置这些方法 如何做到这一点?首先,为了简化问题并帮助解决问题,我将创建一个用户跟踪实体需要遵守的界面: interface UserTracking { public function addedBy(User

我正在开发我的第一个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;
}
然后,您可以创建一个条令事件侦听器,并将
安全性
组件注入其中:

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);
    }
}    
您需要适当地标记侦听器,以便它在
prePersist
preUpdate
上触发:

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

虽然上述方法应该有效,但我认为以这种方式使用条令事件通常不是一个好主意,因为您将域逻辑与条令相耦合,并且将更改隐藏在一层魔法之下,这对于其他使用您的应用程序的开发人员来说可能并不明显

我会将
createdBy
作为构造函数参数,并在需要时显式设置
updateBy
。每次只需要一行代码,但您可以获得清晰性和表达能力,并且您拥有一个更简单的系统,其中移动部件更少

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

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

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

您可能不想重新发明轮子。有一种方法已经做到了这一点。您可以通过以下方式安装它:

composer require antishov/doctrine-extensions-bundle
因为已经有一个配方来配置它。然后您可以将其与以下内容一起使用:

可归咎扩展的特定文档


我选择了事件监听器,一切正常。谢谢!
use Gedmo\Mapping\Annotation as Gedmo;

class Post {

  /**
  * @var User $createdBy
  *
  * @Gedmo\Blameable(on="create")
  * @ORM\ManyToOne(targetEntity="App\Entity\User")
  */
  private $createdBy;

}