I want to automatically set the createdBy
and modifiedBy
properties of an entity.
To set these properties I use the doctrine lifecycle hooks prePersist
and preUser
as described here: https://symfony.com/doc/current/doctrine/events.html#doctrine-lifecycle-callbacks.
I also created a setCreatedByValue
and setModifiedByValue
functions to set the fields ...
Is there any best practice on how to write the currently logged-in user into these properties? Is there a let's say "more elegant" way than injecting the security service into the entity?
How would you do that?
I now searched through the Symfony docs once again and chose the following approach for me:
I created an EntitySubscriber
as described here: https://symfony.com/doc/current/doctrine/events.html#doctrine-lifecycle-subscribers
After that, I created two interfaces TimestampInterface
(for createdAt
and modifiedAt
) and a UserAwareInterface
(for createdBy
and modifiedBy
).
I also created an AbstractEntity
that implements the interfaces mentioned above. Now I can extend each entity (which needs this functionality) with the AbstractEntity
class ...
Then I simply created a doctrine.event_subscriber
(as described in the docs) and checked for the interfaces to set certain fields.
To set the createdBy
and modifiedBy
fields I used the Security container.
Works pretty well - and with this solution, I don't rely on any third-party libs.
<?php
namespace Foo\Bar\EventListener;
use Doctrine\Bundle\DoctrineBundle\EventSubscriber\EventSubscriberInterface;
use Doctrine\ORM\Event\PrePersistEventArgs;
use Doctrine\ORM\Event\PreUpdateEventArgs;
use Doctrine\ORM\Events;
use Symfony\Bundle\SecurityBundle\Security;
use Foo\Bar\Entity\TimestampInterface;
use Foo\Bar\Entity\UserAwareInterface;
class EntitySubscriber implements EventSubscriberInterface
{
public function __construct(
public Security $security,
) {}
public function getSubscribedEvents(): array
{
return [
Events::prePersist,
Events::preUpdate
];
}
public function prePersist(PrePersistEventArgs $prePersistEventArgs): void
{
$object = $prePersistEventArgs->getObject();
if($object instanceof TimestampInterface){
$object->setCreatedAt(time());
$object->setModifiedAt(time());
}
if($object instanceof UserAwareInterface){
$object->setCreatedBy($this->security->getUser()->getId());
$object->setModifiedBy($this->security->getUser()->getId());
}
}
public function preUpdate(PreUpdateEventArgs $preUpdateEventArgs): void
{
$object = $preUpdateEventArgs->getObject();
if($object instanceof TimestampInterface){
$object->setModifiedAt(time());
}
if($object instanceof UserAwareInterface){
$object->setModifiedBy($this->security->getUser()->getId());
}
}
}
What do you think about that solution?