6

我正在使用带有 stof Doctrine 扩展的 symfony 2.6.3。

TimeStampable 和 SoftDeletable 运行良好。

Blameable “on create” 和 “on update” 也运行良好:

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

我在“deletedAt”字段上配置了 SoftDeletable。SoftDeletable 工作正常,但deletedBy永远不会被填充。

我怎样才能让它发挥作用?我只想设置删除实体的用户 ID。

4

4 回答 4

2

这是我的解决方案:

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

}

于 2015-03-26T03:42:19.303 回答
1

问题是当你调用它的 remove 方法时你想更新实体(设置用户)。

目前可能没有完美的解决方案来注册使用 Softdeleteable + Blameable 扩展软删除对象的用户。

一些想法可能是覆盖 SoftDeleteableListener (https://github.com/Atlantic18/DoctrineExtensions/blob/master/lib/Gedmo/SoftDeleteable/SoftDeleteableListener.php),但我在这样做时遇到了问题。

我目前的工作解决方案是使用实体侦听器解析器。

我的实体.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 }

更新 composer.json 中的学说/学说包:

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

如果您有任何其他解决方案,尤其是有关 SoftDeleteableListener 的解决方案,请在此处发布。

于 2015-02-12T05:05:25.737 回答
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 方法是否存在并设置了 deletedBy 属性,但它对我有用,您可以根据需要升级此代码

于 2015-06-12T05:46:30.047 回答
0

这是我找到的另一个解决方案:

注册服务:

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;
}
于 2016-09-07T07:08:53.267 回答