Доктрина обвиняемого расширения «на переменах» не работает

Я на Symfony 2.6.3 с расширением Доктрина stof.

TimeStampable и SoftDeletable работают хорошо.

Также хорошо работают Blameable «при создании» и «при обновлении»:

/**
* @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;

Но «на переменах», похоже, не работает.

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

У меня настроен SoftDeletable в поле «deleteAt». SoftDeletable работает отлично, но deletedBy никогда не заполнен

Как я могу заставить это работать? Я просто хочу установить идентификатор пользователя, который удалил объект.

6

Решение

Проблема в том, что вы хотите обновить сущность (установить пользователя) при вызове метода удаления для нее.

В настоящее время не может быть идеального решения для регистрации пользователя, который удалил объект программным способом, используя расширения Softdeleteable + Blameable.

Некоторая идея может состоять в том, чтобы перезаписать SoftDeleteableListener (https://github.com/Atlantic18/DoctrineExtensions/blob/master/lib/Gedmo/SoftDeleteable/SoftDeleteableListener.php) но у меня была проблема с этим.

Мое текущее рабочее решение — использовать Entity Listener Resolver.

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();
}
}

}

Несовершенство здесь вызывает метод flush.

Регистрация службы:

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

Обновите doctrine / doctrine-bundle в composer.json:

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

Если у вас есть какие-либо другие решения, особенно если речь идет о SoftDeleteableListener, пожалуйста, опубликуйте его здесь.

1

Другие решения

Вот мое решение:

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

Это мое решение, я использую событие preSoftDelete:

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

и сервис:

<?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()),
));
}
}

Это не согласованность, потому что я проверяю, что метод setDeletedBy существует, и устанавливаю свойство deleteBy, но он работает для меня, и вы можете обновить этот код для своих нужд

1

Вот еще одно решение, которое я нашел:

Зарегистрировать услугу:

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
По вопросам рекламы [email protected]