Search code examples
phpsymfonyencapsulation

Symfony2 : get security.context inside entity class


Is it possible to get security.context inside an entity class?

I know the following doesn't work. I don't know how to implement the $user part.

/**
 * Set createdAt
 *
 * @ORM\PrePersist
 */
public function setCreatedAt()
{
    $user = $this->get('security.context')->getToken()->getUser();

    $this->owner = $user->getId();
    $this->createdAt = new \DateTime();
    $this->updatedAt = new \DateTime();
}

Solution

  • For datetimes:

    For the timestamps you are probably best of using the @hasLifeCycleCallback annotation and some additional methods marked as @prePersist and @preUpdate. For created you could even just do it in the __constructor itself.

    Note that you must use @preUpdate for the $updatedAt property, @prePersist is only for new entities.

    If you have a lot of entities that need this, you might consider a Doctrine2 listener to prevent repeated code.

    For ownership properties:

    If you always want to set the ownership of an entity to the "currently logged in user", you are probably best of using a Doctrine2 listener or subscriber. This way you don't have to add this logic to your controller, or wherever you need to create an entity.

    http://symfony.com/doc/current/cookbook/doctrine/event_listeners_subscribers.html http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html#onflush

    Create a listener-service as documented, make sure it gets the security-context using the constructor. Set it to the event onFlush, this way you can adjust the entity just prior to actual saving. This is the best event to handle this kind of thing.

    Make sure you follow the footnotes in the onFlush chapter on the Doctrine documentation, otherwise the last-minute-change won't be picked up by Doctrine.

    Your listener should probably look something like:

    class FlushExampleListener
    {
        public function onFlush(OnFlushEventArgs $eventArgs)
        {
            $em = $eventArgs->getEntityManager();
            $uow = $em->getUnitOfWork();
    
            foreach ($uow->getScheduledEntityInsertions() as $entity) {
                if ($entity instanceof YourClass) {
                    // change owner
                    $entity->setOwner($this->securityContext->getToken()->getUser());
                    // tell doctrine you changed it
                    $uow->recomputeSingleEntityChangeSet($em->getClassMetadata(get_class($entity)), $entity);
                }
            }
    
            foreach ($uow->getScheduledEntityUpdates() as $entity) {
                if ($entity instanceof YourClass) {
                    // change owner
                    $entity->setOwner($this->securityContext->getToken()->getUser());
                    // tell doctrine you changed it
                    $uow->recomputeSingleEntityChangeSet($em->getClassMetadata(get_class($entity)), $entity);
                }
            }
        }
    }
    

    Please note that this does not check if a user is actually logged in...