mogoman
mogoman

Reputation: 2298

Symfony 2 / Doctrine 2 : get changes to PersistentCollection

I am building an application where the user can edit some data and then gets presented with a screen where he can confirm (and comment on) his edits.

In the confirmation form I display the changes that have been made to the entity. This works for "normal" fields. Here is some code that works for checking a single field:

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

But I can't do the same for a relation (example ManyToMany with Users) :

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

doesn't work because $data['users'] and $entity->getUsers() refer to the same persistent collection. It is possible to call this function to see if there are changes:

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

but it isn't possible to see what changes were made.

The second problem with the above is that if all items are removed from the persistent collection, Doctrine does not mark it as "changed" (isDirty() = true), so I can't catch the specific change where the user removes all "users" from the entity in the form.

Please note that the code all works, the only problem I have is that I am unable to view/process the changes made on the confirmation step.

Upvotes: 6

Views: 10288

Answers (3)

Lighthart
Lighthart

Reputation: 3656

Store the original collection in a variable before bind and then compared the new collection after bind. PHP has quite a few array comparison functions, and collections are readily turned into native arrays by $collection->toArray();

eg:

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

Upvotes: 0

mogoman
mogoman

Reputation: 2298

Solved it like this:

1) To get changes that will be made directly to the Entity, use the following:

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

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

2a) To get changes to the relations, use the answer from Lighthart above:

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

2b) Use these methods on Persistent Collection to find inserts / deletes:

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

The only problem with (2b) is that if ALL users are removed and none added then getDeleteDiff() is empty which appears to be a Doctrine bug/idiosyncrasy

Upvotes: 6

Ocramius
Ocramius

Reputation: 25431

Doctrine\ORM\PersistentCollection has internal API (public) methods getSnapshot, getDeleteDiff, getInsertDiff that can be used during lifecycle events of the Doctrine\ORM\UnitOfWork. You could for example check the insert diff of a persistent collection during onFlush.

Upvotes: 8

Related Questions