Vulnerable Doctrine extension 'on change' does not work

I am on symfony 2.6.3 with the extension Doctrine stof.

TimeStampable and SoftDeletable work well.

Also, Blameable "on create" and "on update" also work well:

/** * @var User $createdBy * * @Gedmo\Blameable(on="create") * @ORM\ManyToOne(targetEntity="my\TestBundle\Entity\User") * @ORM\JoinColumn(name="createdBy", referencedColumnName="id") */ protected $createdBy; /** * @var User $updatedBy * * @Gedmo\Blameable(on="update") * @ORM\ManyToOne(targetEntity="my\TestBundle\Entity\User") * @ORM\JoinColumn(name="updatedBy", referencedColumnName="id") */ protected $updatedBy; 

But "on change" doesn't seem to work.

 /** * @var User $deletedBy * * @Gedmo\Blameable(on="change", field="deletedAt") * @ORM\ManyToOne(targetEntity="my\UserBundle\Entity\User") * @ORM\JoinColumn(name="deletedBy", referencedColumnName="id") */ protected $deletedBy; 

I have SoftDeletable configured in the "deletedAt" field. SoftDeletable works fine, but deletedBy never populated.

How can I make it work? I just want to set the id of the user who deleted the object.

+6
source share
4 answers

The problem is that you want to update the object (install the user) when you call the remove method on it.

Currently, there may not be an ideal solution for registering a user who deleted an object using Softdeleteable + Blameable extensions.

Some idea might be to overwrite SoftDeleteableListener ( https://github.com/Atlantic18/DoctrineExtensions/blob/master/lib/Gedmo/SoftDeleteable/SoftDeleteableListener.php ), but I had a problem with this.

My current working solution is to use the Entity receiver-receiver.

MyEntity.php

 /** * @ORM\EntityListeners({β€žAcme\MyBundle\Entity\Listener\MyEntityListener" }) */ class MyEntity { /** * @ORM\ManyToOne(targetEntity="Acme\UserBundle\Entity\User") * @ORM\JoinColumn(name="deleted_by", referencedColumnName="id") */ private $deletedBy; public function getDeletedBy() { return $this->deletedBy; } public function setDeletedBy($deletedBy) { $this->deletedBy = $deletedBy; } 

MyEntityListener.php

 use Doctrine\ORM\Event\LifecycleEventArgs; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Acme\MyBundle\Entity\MyEntity; class MyEntityListener { /** * @var TokenStorageInterface */ private $token_storage; public function __construct(TokenStorageInterface $token_storage) { $this->token_storage = $token_storage; } public function preRemove(MyEntity $myentity, LifecycleEventArgs $event) { $token = $this->token_storage->getToken(); if (null !== $token) { $entityManager = $event->getObjectManager(); $myentity->setDeletedBy($token->getUser()); $entityManager->persist($myentity); $entityManager->flush(); } } } 

Imperfection here calls the flush method.

Registration Service:

 services: myentity.listener.resolver: class: Acme\MyBundle\Entity\Listener\MyEntityListener arguments: - @security.token_storage tags: - { name: doctrine.orm.entity_listener, event: preRemove } 

Update doctrine / doctrine in composer.json:

 "doctrine/doctrine-bundle": "1.3.x-dev" 

If you have other solutions, especially when it comes to SoftDeleteableListener, post it here.

+1
source

Here is my solution:

 mybundle.soft_delete: class: Listener\SoftDeleteListener arguments: - @security.token_storage tags: - { name: doctrine_mongodb.odm.event_listener, event: preSoftDelete } 
 class SoftDeleteListener { /** * @var TokenStorageInterface */ private $tokenStorage; public function __construct(TokenStorageInterface $tokenStorage) { $this->tokenStorage = $tokenStorage; } /** * Method called before "soft delete" system happened. * * @param LifecycleEventArgs $lifeCycleEvent Event details. */ public function preSoftDelete(LifecycleEventArgs $lifeCycleEvent) { $document = $lifeCycleEvent->getDocument(); if ($document instanceof SoftDeletedByInterface) { $token = $this->tokenStorage->getToken(); if (is_object($token)) { $oldValue = $document->getDeletedBy(); $user = $token->getUser(); $document->setDeletedBy($user); $uow = $lifeCycleEvent->getObjectManager()->getUnitOfWork(); $uow->propertyChanged($document, 'deletedBy', $oldValue, $user); $uow->scheduleExtraUpdate($document, array('deletedBy' => array($oldValue, $user))); } } } 

}

+1
source

This is my solution, I am using the preSoftDelete event:

 app.event.entity_delete: class: AppBundle\EventListener\EntityDeleteListener arguments: - @security.token_storage tags: - { name: doctrine.event_listener, event: preSoftDelete, connection: default } 

and service:

 <?php namespace AppBundle\EventListener; use Doctrine\ORM\Event\LifecycleEventArgs; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Exception\AccessDeniedException; class EntityDeleteListener { /** * @var TokenStorageInterface */ private $tokenStorage; public function __construct(TokenStorageInterface $tokenStorage) { $this->tokenStorage = $tokenStorage; } public function preSoftDelete(LifecycleEventArgs $args) { $token = $this->tokenStorage->getToken(); $object = $args->getEntity(); $om = $args->getEntityManager(); $uow = $om->getUnitOfWork(); if (!method_exists($object, 'setDeletedBy')) { return; } if (null == $token) { throw new AccessDeniedException('Only authorized users can delete entities'); } $meta = $om->getClassMetadata(get_class($object)); $reflProp = $meta->getReflectionProperty('deletedBy'); $oldValue = $reflProp->getValue($object); $reflProp->setValue($object, $token->getUser()->getUsername()); $om->persist($object); $uow->propertyChanged($object, 'deletedBy', $oldValue, $token->getUser()->getUsername()); $uow->scheduleExtraUpdate($object, array( 'deletedBy' => array($oldValue, $token->getUser()->getUsername()), )); } } 

This is not a consistency because I am checking the setDeletedBy method and setting the deletedBy property, but it works for me and you can update this code for your needs

+1
source

Here is another solution I found:

Register service:

 softdeleteable.listener: class: AppBundle\EventListener\SoftDeleteableListener arguments: - '@security.token_storage' tags: - { name: doctrine.event_listener, event: preFlush, method: preFlush } 

SoftDeleteableListener:

 /** * @var TokenStorageInterface|null */ private $tokenStorage; /** * DoctrineListener constructor. * * @param TokenStorageInterface|null $tokenStorage */ public function __construct(TokenStorageInterface $tokenStorage) { $this->tokenStorage = $tokenStorage; } /** * @param PreFlushEventArgs $event */ public function preFlush(PreFlushEventArgs $event) { $user = $this->getUser(); $em = $event->getEntityManager(); foreach ($em->getUnitOfWork()->getScheduledEntityDeletions() as $object) { /** @var SoftDeleteableEntity|BlameableEntity $object */ if (method_exists($object, 'getDeletedBy') && $user instanceof User) { $object->setDeletedBy($user); $em->merge($object); // Persist and Flush allready managed by other doctrine extensions. } } } /** * @return User|void */ public function getUser() { if (!$this->tokenStorage || !$this->tokenStorage instanceof TokenStorageInterface) { throw new \LogicException('The SecurityBundle is not registered in your application.'); } $token = $this->tokenStorage->getToken(); if (!$token) { /** @noinspection PhpInconsistentReturnPointsInspection */ return; } $user = $token->getUser(); if (!$user instanceof User) { /** @noinspection PhpInconsistentReturnPointsInspection */ return; } return $user; } 
0
source

Source: https://habr.com/ru/post/981863/


All Articles