2013-01-24 3 views
5

私は現在、ロード時に少し変更したいエンティティを持っています。この変更は1回の変更となり、エンティティと一緒に新しいフィールドに保持されます。アソシエーションのドクトリンpostLoadイベント

現在の目的を明確にする:エンティティは「場所」であり、ネストされたセットの一部を形成します。それは名前、lft/rgtの値とIdを持っています。私がこのエンティティで実行していた計算上高価な作業の1つは、完全な場所パスを取得してテキストとして表示することでした。たとえば、ロケーションエンティティ "Waterloo"では、 "Waterloo | London | United Kingdom"として表示したいと考えています。これには、セット全体を(ルートノードに)トラバースすることが含まれます。

この値を減らすために、私はLocationエンティティにこの値でスタンプすることができる新しいフィールドを作成しました(場所(またはツリー内の任意の場所)が変更されたときに/として更新されます)。私のアプリケーションがライブ状態になっていることを考えれば、これを一度のプロセスとして実行するのを避ける必要があります。これは、DBに対する集中的なワンタイムヒットを引き起こすためです。代わりに、このアップデートを、その値)が読み込まれます。私はDoctrineのpostLoadイベントメカニズムがこれを達成するのには完璧だと思っていました。

ロケーションエンティティは私のアプリケーションによって直接ロードされません。それらは常にリレーションの逆側になります。これは心、そして教義のポストロードイベントという事実であると:

  • がロードされない
  • しか所有しているエンティティ

私は方法がないために解雇された任意の関連するデータ(へのアクセスを許可)これらの変更を静かに行うこと。

誰でもアドバイスや経験がありますか?

+0

個人的なアドバイスとして、私はパーシスタンスレイヤーでファンシーロジックでこれを処理しません。代わりに、エンティティへの呼び出しを代理し、最終的に親アイテムの取得を処理する集約モデルを構築します。これはあなたのサービス層に合っています – Ocramius

答えて

5

Entity ManagerでinitializeObject()メソッドを使用して、関連するLocationオブジェクトをpostLoadイベント内でロードすることができました。

/** 
* Upon loading the object, if the location text isn't set, set it 
* @param \Doctrine\ORM\Event\LifecycleEventArgs $args 
*/ 
public function postLoad(\Doctrine\ORM\Event\LifecycleEventArgs $args) 
{ 
    $this->em = $args->getEntityManager(); 
    $entity = $args->getEntity(); 

    if ($entity instanceof \Entities\Location) 
    { 
     if (is_null($entity->getPathText())) 
     { 
      $entity->setPathText("new value"); 
      $this->em->flush($entity); 
     } 
    } elseif ($entity instanceof {parent Entity}) 
    { 
     $location = $entity->getLocation(); 
     // This triggers the postLoad event again, but this time with Location as the parent Entity 
     $this->em->initializeObject($location); 
    } 
}