2013-02-11 5 views
6

Я создаю приложение, в котором пользователь может редактировать некоторые данные, а затем получает экран, на котором он может подтвердить (и прокомментировать) свои изменения.Symfony 2/Doctrine 2: получить изменения в PersistentCollection

В форме подтверждения отображаются изменения, внесенные в объект. Это работает для «нормальных» полей. Вот код, который работает для проверки одного поля:

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

Но я не могу сделать то же самое для отношения (пример ManyToMany с пользователями):

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

не работает, потому что $ data ['users'] и $ entity-> getUsers() относятся к одной и той же постоянной коллекции. Можно назвать эту функцию, чтобы увидеть, если есть изменения:

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

, но это не возможно, чтобы увидеть, какие изменения были сделаны.

Вторая проблема заключается в том, что если все элементы удалены из постоянной коллекции, Doctrine не помещает ее как «измененную» (isDirty() = true), поэтому я не могу поймать конкретное изменение, пользователь удаляет всех «пользователей» из объекта в форме.

Обратите внимание, что код работает, единственная проблема заключается в том, что я не могу просмотреть/обработать изменения, сделанные на шаге подтверждения.

+0

Извлечь $ entity-> getUsers() перед связыванием? Также проверьте и посмотрите, добавляет ли ваш тип формы поле по ссылке. – Lighthart

+0

@ Lighthart это хорошая идея (по ссылке)! Будет проверять и возвращаться к вам ... – mogoman

+0

@Lighthart не работает, потому что ссылка предназначена для коллекций, а не для Entity для полей – mogoman

ответ

0

Сохраните исходную коллекцию в переменной перед связыванием, а затем сравните новую коллекцию после привязки. PHP имеет довольно много функций сравнения массива, а коллекции легко превращаются в собственные массивы с помощью $ collection-> toArray();

например:

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

Не работает, после привязка $ oldusers также обновляется с изменениями. Это связано с тем, что $ oldusers относится к одной коллекции. – mogoman

+0

Отредактировано выше. Просто бросьте его как массив. Существует _no_ way массив, и объект может быть одним и тем же местом памяти. – Lighthart

+0

Спасибо. Закончилось использование этого параметра toArray(). Я также добавил свое окончательное решение, если кто-то хочет комментировать/улучшить его. – mogoman

6

Doctrine\ORM\PersistentCollection имеет внутренний API (общественные) методы getSnapshot, getDeleteDiff, getInsertDiff, которые могут быть использованы в течение жизненного цикла событий Doctrine\ORM\UnitOfWork. Вы можете, например, проверить вставку diff постоянной записи во время onFlush.

+0

спасибо +1, но эти методы не работают, если вся коллекция была протерта (isDirty() также является методом из PersistentCollection), и это моя главная проблема. – mogoman

+0

Вы должны использовать эти методы после вычисления наборов изменений (во время 'flush') – Ocramius

+0

Проблема в том, что мне нужно показать изменения для пользователя, чтобы принять/отменить, что означает, что я не могу позвонить onFlush() – mogoman

3

решаемые это следующим образом:

1) Для того, чтобы получить изменения, которые будут сделаны непосредственно к объекту, используйте следующую команду:

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

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

2а) Для получить изменения в отношениях, использовать ответ от Lighthart выше:

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

2b) Используйте эти методы Persistent Collection найти вставки/удаления:

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

Единственная проблема с (2b) является то, что, если все пользователи будут удалены и не добавили ни то getDeleteDiff() пусто, который, как представляется, быть ошибкой Doctrine/idiosyncrasy

+0

Я борюсь с этим и задаюсь вопросом, где поставить эта логика. Моя первая мысль - это действия контроллера, но все говорят, что ваши контроллеры точены. Наверное, я ищу слушателя событий - либо в системе событий Doctrine, либо в системе событий Zend Framework 2, - где я могу это выбрать. Мне нужно очистить кеш, когда некоторые вещи происходят с ассоциациями сущности. – David

+0

Сэр его блестящий сэр! –

+0

и я не столкнулся со своей проблемой в 2b, getDeleteDiff() возвращает массив, даже если все элементы коллекции были удалены. –

Смежные вопросы