我正在开发我的第一个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);
}
}
您需要适当地标记侦听器,因此它会在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 }
尽管上述方法可行,我相信以这种方式使用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,然后将其与类似:
一起使用可责怪的扩展名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;
}