1

Doctrine/Symfony2 の prePersist/preUpdate リスナーの使用に問題があります。

多対一の関係には 2 つのエンティティがあります (1 つの場所を多くの人が参照できます)。私は、ユーザーが既に存在する新しい人物の場所を選択できるように、いくつかの AJAX-Stuff を実行するフォームを作成しました。したがって、「entity_id」フォーム フィールドを使用しています。また、データベースに存在しない新しい人物の新しい場所を作成する可能性をユーザーに提供したいと思います。これは、ユーザーが新しい場所の名前を挿入できるフォームの 2 番目のフィールドによって処理されます。Person のエンティティを永続化するときに、参照されている場所がデータベースに存在するかどうかを確認しています。そうでない場合は、新しい Location-Entity を生成しています。これは(要するに)Entity-Class Person での私の prePersist-Lifecyclecallback です。

public function prePersist() {
   if($this->ort == null) 
       $this->ort = new Ort($this->ortsname);
}

これは、新しい人物を作成するときに完全に機能します。問題は更新手順です。そのため、以前に人に接続された場所があり、同じ手順で (preUpdate-Listener を使用して) 新しい場所を作成したい場合、次のような通知が表示されます。

Notice: Undefined index: 000000004a0010250000000058426bec in ...Doctrine/ORM/UnitOfWork.php line 983

これを解決する方法がわかりません。Person オブジェクトを参照する前に Location-Object を使用する必要があると思いますが、Person を参照する Location-Object が新しいエンティティであることを Entity-Manager に伝える方法がわかりません。私はまた、次のようなリスナークラスでこれを試しました:

if( $entity instanceof Person) {
    if( $entity->getLocation() == null ) {
         $entity->setLocation( new Location( $entity->getLocatioName() );
         $em->persist($entity->getLocation());
         $em->flush();
    }
}

マッピングでは「cascade={persist}」表記が有効になっているため、$em->persist ... は問題になりません。

4

1 に答える 1

2

でトラブルになると思いますpreUpdatepreUpdateが次のような状況に最適なイベント ハンドラーではないことを意味する 2 つのことがあります。

  • 渡されたエンティティの関連付けに対する変更は、フラッシュ操作によって認識されなくなりました。
  • UnitOfWork API と組み合わせた場合でも、EntityManager#persist() または EntityManager#remove() の呼び出しは強く推奨されず、フラッシュ操作以外では期待どおりに動作しません。

(これらの 2 つのポイントは、このセクションの下部から取得されます: http://docs.doctrine-project.org/en/2.0.x/reference/events.html#preupdate )

さらに、preUpdateDoctrine のフラッシュ操作の途中で呼び出されるため、flush再度呼び出すと問題が発生します。

onFlushしたがって、代わりに使用することをお勧めします: http://docs.doctrine-project.org/en/2.0.x/reference/events.html#onflush

これを行う場合、ロケーションを追加した後に Person エンティティが変更されたことを Doctrine に伝える必要があります。変更された Person オブジェクト自体を取得するのも少し複雑です。onFlushハンドラーで次のようなことを試してください。

public function onFlush(OnFlushEventArgs $args)
{
    $em = $args->getEntityManager();
    $uow = $em->getUnitOfWork();

    foreach ($uow->getScheduledEntityUpdates() AS $entity) {
        if ($entity instanceof Person) {
            if ($entity->getLocation() == null ) {
                $entity->setLocation( new Location( $entity->getLocationName() ));

                // have to tell Doctrine that the Location has been updated
                $cmf = $args->getEntityManager()->getMetadataFactory();
                $class = $cmf->getMetadataFor(get_class($entity));
                $args->getEntityManager()->getUnitOfWork()->computeChangeSet($class, $entity); // don't use recomputeSingleEntityChangeSet here - that doesn't care about relationships
            }
        }
    }
}
于 2012-12-07T10:51:20.867 に答える