2013-02-11 8 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 
    } 
} 

は、しかし、私は関係(ユーザーとの例多対多)のために同じことを行うことはできません。

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

は$ので動作しません。 data ['users']と$ entity-> getUsers()は同じ永続コレクションを参照します。この関数を呼び出して、変更があるかどうかを確認することができます。

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

ただし、どのような変更が加えられたかはわかりません。

上記の2番目の問題は、すべてのアイテムが永続コレクションから削除された場合、Doctrineはそれを「変更済み」(isDirty()= true)としてマークしないため、ユーザーはフォーム内のエンティティからすべての「ユーザー」を削除します。

コードはすべて動作しますが、唯一の問題は、確認手順で行った変更を表示/処理できないことです。

+0

bind前に$ entity-> getUsers()を取得しますか?また、あなたのフォームタイプが参照によってフィールドを追加しているかどうかを確認してください。 – Lighthart

+0

@ライトハートそれは良いアイデアです(参考)!確認して、あなたに戻ってきます... – 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(パブリック)メソッドgetSnapshotgetDeleteDiffDoctrine\ORM\UnitOfWorkのライフサイクルイベント中に使用することができるgetInsertDiffを有しています。たとえば、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); 

2A)へリレーションシップを変更するには、上のLighthartの答えを使用してください:

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

2b)に挿入を見つけるために、永続的なコレクションにこれらのメソッドを使用します/削除:

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

の唯一の問題(2b)は、すべてのユーザーが削除され、何も追加されていない場合は、その後getDeleteDiffは()に表示される空であるということですDoctrineのバグ/特有である

+0

私はこれに取り組んで、この論理。私の最初の考えはコントローラアクションですが、誰もがあなたのコントローラをスキニーにしておきます。私は、Doctrineイベントシステム、またはZend Framework 2のイベントシステムのいずれかで、イベントリスナーを探していると思います。エンティティの関連に特定のことが起こったときにキャッシュをクリアする必要があります。 – David

+0

華麗な卿! –

+0

私は2bであなたの問題に直面しませんでした。すべてのコレクションアイテムが削除されてもgetDeleteDiff()は配列を返します。 –

関連する問題