4

1 対 1 の関連付けに 2 つのエンティティがあります。最初のPersonは MySQL データベースに保存され、Doctrine によって処理されます。2 番目の はAdUserRecord、ActiveDirectory ユーザー レコードを記述します。読み取り専用です。について知る必要はありませんPerson。また、 AdUserRecordプライバシー上の理由から、プロパティを MySQL db に保存しないでください。

は、またはで検索できるAdUserRecordサービス を使用して取得されます。検索が成功するたびに、サービスは対応するレコードがあるかどうかを確認し、存在しない場合はレコードを作成します。それはうまくいきます。AdSearchersamaccountnameobjectGUIDPerson

私の問題は、Personオブジェクトから始めるときに発生します。ほとんどの場合、 にアクセスする必要はないので、必要でPersonないAdUserRecord限り Active Directory にクエリを実行したくありません。つまりPerson::getAdrecord()、サービスにアクセスできる必要があると思いAdSearcherます。このようなもの:

public function getAdrecord(){
   if($this->adrecord) return $this->adrecord; 

   $searcher = ???; //get AdSearcher service somehow
   $record = $search->getRecordByUserGuid($this->ad_guid);
   if(!$record) throw new \Exception('this person no longer exists');
   
   $this->adrecord = $record;
   return $this->adrecord;
}

私はかなり熱心に Symfony のドキュメントを読んできましたが、まだ困惑しています。

質問

  • エンティティにサービスを取得するにはどうすればよいですか? コンストラクターを介して注入する必要がありますか、それともゲッターの必要な場所に注入する必要がありますか? ゲッターでのみ発生する場合、それを注入する必要がありますか、それともインポートする方法はありますか?
  • エンティティにサービスを追加することは、これらのタイプの状況を処理する標準的な方法ですか? s用のエンティティ マネージャを作成するのが望ましいでしょうAdUserRecordか?
  • エンティティ マネージャを構築する必要がある場合、どのインターフェイスを実装する必要がありますか?

Personクラス

namespace ACRD\DefaultBundle\Entity;

use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use ACRD\DefaultBundle\Entity\AdUserRecord;

/**
 * @ORM\Entity
 * @Orm\Table(name="person")
 *
 */
class Person {
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\Column(name="AD_guid", type="string", length=36, unique=true)
     */
    protected $ad_guid;

    /**
     * @var AdUserRecord
     */
    protected $adrecord;

     //usual getters and setters
}
4

2 に答える 2

1

Doctrine のpostLoadイベントが最適なソリューションのようです。

// src/Acme/DemoBundle/EventListener/ActiveDirectorySubscriber.php
namespace Acme\DemoBundle\EventListener;

use Acme\DemoBundle\Model\AdAwareInterface;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\LifecycleEventArgs;
// for doctrine 2.4: Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use Symfony\Component\DependencyInjection\ContainerAware

class ActiveDirectorySubscriber extends ContainerAware implements EventSubscriber
{
    public function getSubscribedEvents()
    {
        return array(
            'postLoad',
        );
    }

    public function postLoad(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();

        if (!($entity instanceof AdAwareInterface)) {
            return:
        }

        $adSearcher = $this->getContainer()->get('acme_demo.ad_searcher');

        if ($adPerson = $adSearcher->find($entity->getAdGuid())) {
            $entity->setAdPerson($adPerson);
        }
    }
}

また、ほとんどの場合、Active Directory のものを使用する必要がないことにも言及しました。最適化する前に、パフォーマンスへの影響がどの程度あるかを実際に測定することを強くお勧めします。ただし、パフォーマンスの問題に気付いた場合は、プロキシ オブジェクトを使用して、AdPerson実際に何かが必要になるまで検索を軽減することを検討してください。

public function postLoad(LifecycleEventArgs $args)
{
    $entity = $args->getEntity();

    if (!($entity instanceof AdAwareInterface)) {
        return:
    }

    $adSearcher = $this->getContainer()->get('acme_demo.ad_searcher');

    $entity->setAdPerson(new AdPersonProxy($adSearcher));
}

AdPersonProxy基本的にAdPersonクラスから拡張され、実際のオブジェクトをロードする呼び出しですべてのパブリック メソッドをラップしAdPerson、2 つの間のファサードとして機能します。ただし、コーディングを開始する前に、次の意味を考慮してください。

  • コードベースが複雑になります (コードが増えるほど、維持する必要が増えます)。
  • デバッグするのは面倒です。たとえば、テンプレート内で例外が発生し、長い間頭を悩ませている可能性があります(そこに行ったことがあります)。

肝心なのは、理論的には、サービスは (ほとんどの場合) エンティティ内に注入されるべきではないということです。

于 2013-08-01T02:38:50.057 に答える