2015-02-02 4 views
6

Ich bin auf Symfony 2.6.3 mit Stof Doctrine Erweiterung.Doctrine fehlerhafte Verlängerung 'on change' funktioniert nicht

TimeStampable und SoftDeletable funktionieren gut.

auch tadelnswert „auf erstellen“ und „auf update“ arbeitet gut zu:

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

Aber „bei Änderung“ scheint nicht zu funktionieren.

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

Ich habe SoftDelelable auf "deletedAt" -Feld konfiguriert. SoftDeletable funktioniert gut, aber deletedBy wird nie gefüllt.

Wie kann ich es schaffen, damit es funktioniert? Ich möchte nur Benutzer-ID, die die Entität gelöscht hat.

Antwort

1

Das Problem ist, dass Sie Entity aktualisieren (Benutzer festlegen), wenn Sie remove-Methode darauf aufrufen.

Momentan kann es keine perfekte Lösung für die Registrierung von Benutzern geben, die ein Objekt mit Softdeleteable + Blameable-Erweiterungen gelöscht haben.

Eine Idee könnte sein, SoftDeleteableListener (https://github.com/Atlantic18/DoctrineExtensions/blob/master/lib/Gedmo/SoftDeleteable/SoftDeleteableListener.php) zu überschreiben, aber ich hatte ein Problem damit.

Meine aktuelle Arbeitslösung ist die Verwendung von 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(); 
    } 
} 

} 

Eine Unvollkommenheit hier bündig Methode aufrufen.

Register Service:

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

aktualisieren Lehre/Lehre Bündel in composer.json:

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

Wenn Sie irgendwelche anderen Lösungen, vor allem wenn es um SoftDeleteableListener ist, bitte hier posten .

1

Hier ist meine Lösung:

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

Diese meine Lösung ist, verwende ich preSoftDelete Veranstaltung:

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

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

Es ist nicht Konsistenz, weil ich setDeletedBy Methode existiert und legen deletedBy Eigenschaft überprüfen, aber es für mich arbeiten, und Sie diesen Code für Ihre Bedürfnisse aktualisieren können

0

Hier ist eine andere Lösung ich fand:

Registrieren Sie einen Dienst:

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