2013-02-11 9 views
6

Ich erstelle eine Anwendung, in der der Benutzer einige Daten bearbeiten kann und dann einen Bildschirm erhält, auf dem er seine Änderungen bestätigen (und kommentieren) kann.Symfony 2/Doctrine 2: Änderungen an PersistentCollection erhalten

Im Bestätigungsformular zeige ich die Änderungen an, die an der Entität vorgenommen wurden. Dies funktioniert für "normale" Felder. Hier ist ein Code, der für die Überprüfung ein einzelnes Feld funktioniert:

// create $form 
// bind $form 

if ($form->isValid() { 
    $data = $form->getData(); 
    // example, get changes of a "normal" field 
    if ($data['color'] != $entity->getColor()) { 
     // do something with changes 
    } 
} 

Aber ich kann nicht das Gleiche tun für eine Beziehung (zB ManyToMany mit Benutzer):

if ($data['users'] != $entity->getUsers() 

nicht, weil $ funktioniert data ['Benutzer'] und $ entity-> getUsers() beziehen sich auf die gleiche persistente Sammlung. Es ist möglich, diese Funktion aufzurufen, um zu sehen, ob es Änderungen sind:

if ($data['users']->isDirty()) 

aber es ist nicht möglich, zu sehen, welche Änderungen vorgenommen wurden. Das zweite Problem mit dem Obigen ist, dass, wenn alle Elemente aus der persistenten Sammlung entfernt werden, Doctrine es nicht als "geändert" markiert (isDirty() = true), so dass ich die spezifische Änderung nicht abfangen kann Der Benutzer entfernt alle "Benutzer" aus der Entität im Formular.

Bitte beachten Sie, dass der Code funktioniert, das einzige Problem, das ich habe, ist, dass ich nicht in der Lage bin, die im Bestätigungsschritt vorgenommenen Änderungen anzuzeigen/zu verarbeiten.

+0

$ Entity-> getUsers() vor dem Binden abrufen? Überprüfen Sie auch, ob Ihr Formulartyp das Feld durch Verweis hinzufügt. – Lighthart

+0

@Lighthart, das ist eine gute Idee (durch Bezugnahme)! Wird überprüfen und zurück zu dir ... – mogoman

+0

@Lighthart funktioniert nicht, weil der Verweis für Sammlungen und nicht für Entität für Felder – mogoman

Antwort

0

Speichern Sie die ursprüngliche Sammlung in einer Variablen vor dem Binden, und vergleichen Sie anschließend die neue Sammlung nach dem Binden. PHP hat ziemlich viele Array-Vergleichsfunktionen, und Sammlungen werden leicht in native Arrays umgewandelt durch $ collection-> toArray();

zB:

// create form 
$oldusers=$entity->getUsers()->toArray(); 
// bind form 
if ($form->isValid() { 
    $data = $form->getData(); 
    if ($data['users'] != $oldusers) { 
     // do something with changes 
    } 
} 
+0

Funktioniert nicht, nach Die Bindung $ oldusers wird ebenfalls mit den Änderungen aktualisiert. Dies liegt daran, dass sich $ oldusers auf dieselbe Sammlung bezieht. – mogoman

+0

oben bearbeitet. Wirf es einfach als Array aus. Es gibt kein Array und ein Objekt kann den gleichen Speicherort haben. – Lighthart

+0

Danke. Beendet mit dem toArray(). Ich habe auch meine endgültige Lösung hinzugefügt, falls jemand sie kommentieren/verbessern möchte. – mogoman

6

Doctrine\ORM\PersistentCollection hat interne API (public) Methoden getSnapshot, getDeleteDiff, getInsertDiff, die während des Lebenszyklus Ereignisse des Doctrine\ORM\UnitOfWork verwendet werden kann. Sie könnten zum Beispiel das Einfüge-Diff einer persistenten Sammlung während onFlush überprüfen.

+0

Dank +1 ist, aber diese Methoden funktionieren nicht, wenn die gesamte Sammlung gelöscht wurde (die IsDirty() ist auch eine Methode aus PersistentCollection) und das ist mein Hauptproblem. – mogoman

+0

Sie sollten diese Methoden verwenden, nachdem Changesets berechnet wurden (während 'flush') – Ocramius

+0

Problem ist, dass ich die Änderungen für den Benutzer zeigen muss, um zu akzeptieren/abzubrechen, was bedeutet, dass ich onFlush() nicht aufrufen kann – mogoman

3

es wie folgt gelöst:

1) Änderungen zu erhalten, die direkt an die Entity, verwenden Sie die folgende gemacht werden:

// create form 
// bind form 
// form isValid() 

$uow = $em->getUnitOfWork(); 
$uow->computeChangeSets(); 
$changeset = $uow->getEntityChangeSet($entity); 
print_r($changeset); 

2a), um erhalten Sie Änderungen an den Beziehungen, verwenden Sie die Antwort von Lighthart oben:

$oldUsers = $entity->getUsers()->toArray(); 
// bind form 
// form isValid 
$newUsers = $entity->getUsers()->toArray(); 
// compare $oldUsers and $newUsers 
Verwenden

2b) diese Methoden über persistente Collection Einsätze zu finden/löscht:

$newUsers = $entity->getUsers(); 
$inserted = $newUsers->getDeleteDiff(); 
$deleted = $newUsers->getInsertDiff(); 

Das einzige Problem mit (2b) besteht darin, dass, wenn alle Benutzer entfernt werden und keine hinzugefügt dann getDeleteDiff() ist leer, was erscheint ein Doctrine Bug sein/idiosyncrasy

+0

Ich ringe damit und frage mich, wo ich hinkriege diese Logik. Mein erster Gedanke ist Controller-Aktion, aber alle sagen, halten Sie Ihre Controller dünn. Ich schätze, ich suche nach einem Ereignis-Listener - entweder im Doctrine-Event-System oder im Event-System von Zend Framework 2 - wo ich das aufheben kann. Ich muss einen Cache löschen, wenn bestimmte Dinge mit den Assoziationen einer Entität passieren. – David

+0

Sir sein brillanter Herr! –

+0

und ich habe nicht Ihr Problem in 2b konfrontiert, getDeleteDiff() gibt Array zurück, auch wenn alle Sammlung Elemente gelöscht wurde –