1

異なる情報を持つ任意の数のAdProvider構成フィールドを含むことができるサイトレコードがあります。残念ながら、fieldNames(プロバイダーの名前)は一意であり、今後さらに増える予定です。ドキュメント内のそれぞれをハッシュタイプとしてハードコーディングすることもできますが、新しいプロバイダーが追加されるたびにドキュメントを更新する必要があります。

別のMongoコレクションから取得できるプロバイダーのリストを見てドキュメント自体を動的に変更したいのですが、これを行う方法がわかりません。

私の最初の試みは、loadClassMetaDataイベントでリスナーを作成し、新しいフィールドをマップすることでした。フィールドマッピングが表示されていますが、ドキュメントに反映されていません。明らかに、これらのフィールドにはゲッターとセッターがないので、魔法の__getメソッドと__setメソッドを使用してアクセスしようとしましたが、存在しないというエラーが発生します。

多分私はこれについて間違った方法で行っているのですか?

Mongoレコードの例:

{
    "_id" : ObjectId("4ff1d29d99c6667722000000"),
    "_type" : [
        "Models_Site"
    ],
    "enabledAdProviders" : [
        "provider1",
        "provider2",
        "provider3",
        "provider4"
    ],
    "provider1" : {
        "id" : "4028cbff38e2d7c00666fd2fdc770208"
    },
    "provider2" : {
        "placements" : {
            "Top_300x50" : "477",
            "Btm_300x50" : "478",
            "Top_320x50" : "477",
            "Btm_320x50" : "478"
        }
    },
    "provider3" : {
        "id" : "8a809449013331fdcdc6662708532b20"
    },
    "siteId" : "PsTl",
    "siteName" : "Publisher Site",
    "provider4" : {
        "placements" : {
            "Top_300x50" : "430",
            "Btm_300x50" : "430"
        }
    }
}

私のリスナー:

<?php
namespace BIM\DataBundle\Listener;

use BIM\DataBundle\Document\AdPublisherRecord;
use BIM\DataBundle\Document\AdProviderRecord;
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;

class AdPublisherSiteSetup
{
private $serviceContainer;

/**
 * This service is called every time Ads doctrine odm loads a document. 
 * We are dynamically creating the ad provider setting nodes on the AdPublisher Record 
 * 
 */
public function __construct($serv){
    $this->serviceContainer = $serv;
}

public function loadClassMetadata(\Doctrine\ODM\MongoDB\Event\LoadClassMetadataEventArgs $args)
{
    $metaData = $args->getClassMetadata();
    $document = (string)$metaData->getName();

    if($document == "BIM\DataBundle\Document\AdPublisherRecord"){
        //query for ad providers
        //create as a hash type to store each providers settings.
        $providerList = $this->serviceContainer->get('ads.publisher.factory')->getProviderList();
        foreach ($providerList as $name => $value) {
            $metaData->mapField(array('fieldName' => $name, 'type' => 'hash'));
        }   
    }
}
}
4

3 に答える 3

4

単純なDoctrine-odmではこれを行うことはできませんが、私は簡単なトリックを使用してほぼ同じことを行いました。


MongodDBドキュメントはネストできるため、@Hashドキュメントにプロパティを作成するだけで、スキーマのないプロパティが含まれます(ハッシュバッグと考えてください)。

class Doc {

   /** 
    * Schema-less dynamic properties goes here:
    * @MongoDB\Hash 
    */
   public $extraFields;

   /** @MongoDB\Date */
   public $createdDate;

   //Other static properties...
}

唯一の注意点は、スキーマのないプロパティが$extraFieldsルートではなくプロパティに含まれることです。

ただし、これは美的な問題にすぎません。これらのフィールド(インデックス、クエリ、マップリデュース、ecc)ですべてを実行できます。

このようにして、静的に定義されたプロパティ(Id、createdDate、eccなど)と動的プロパティのハッシュバッグのいずれかを使用できます。

これらの動的プロパティのいくつかの存在を文書化する(そして同僚によくあるタイプミスの問題を回避する)場合は、ドキュメントでいくつかのアクセス方法を定義できます。

class Doc {

    public getExtraName() {
        if(empty($this->extraFields['name'])) return null;
         return $this->extraFields['name'];
    }
}
于 2013-04-29T10:13:40.373 に答える
2

私はSymfony2とDoctrine2-ODM用の広範なEAVシステムを作成しました。このシステムでは、任意のドキュメントを従来のフィールドと属性の「ハイブリッド」に変換できます。属性はすべて、特定のタイプ(住所、電話番号、文字列、ドキュメント参照など)を持つ別のドキュメントで定義されています。会社の所有物であるため共有できませんが、要点は以下のとおりです。

  • 属性のすべての値は、ドキュメントのハッシュフィールドに格納されるため、配列に簡略化できる必要があります(多次元でも問題ありません)。
  • ドキュメントで拡張できる抽象クラス(AbstractAttributeAware)を作成して、私が使用したものです。そのクラスの中には次のようなものがあるはずです。
    • 'updateCount'またはそれらの行に沿った何かと呼ばれるフィールド。属性が変更されるたびに、この更新カウントを更新して、ドキュメントの更新を強制します。
    • 収縮した値を格納するためのハッシュフィールド。
    • オブジェクトが格納されているプロパティ(DBには格納されていません)。
    • ハッシュ値を取得してオブジェクトに変換する「deflate」メソッドと「inflate」メソッド、またはオブジェクトを取得してハッシュに変換するメソッド。
  • 永続化、更新、およびロードをリッスンするリスナーを作成します。これらのリスナーは、AbstractAttributeAwareクラスを拡張するすべてのドキュメントを「膨張」および「収縮」する必要があります。
  • インフレとデフレを処理する「AttributeHandler」となるクラスを作成します。基本的に、膨張および収縮機能を収容するクラス。私はあなたが望む代わりにあなたがあなたのリスナーにそれらを置くことができると思います。

申し訳ありませんが、これ以上お断りすることはできませんでしたが、さらに詳しい説明が必要な場合は、喜んでお手伝いさせていただきます。重要なのは太字のupdateCountフィールドです(その下に到達するのに永遠にかかりました)。

于 2012-12-26T20:37:41.930 に答える
0

多くの研究を行った後、私は次の解決策を思いつきました。お役に立てば幸いです...1。services.ymlにイベントリスナーを登録します

サービス:my_doctrine_listener:クラス:Test \ SamplerestBundle \ Listener \ ModifiedColumnタグ:-{名前:doctrine_mongodb.odm.event_listener、イベント:loadClassMetadata}

  1. Test \ SamplerestBundle \ Listener\ModifyColumnに次のメソッドを追加します

public function loadClassMetadata(LoadClassMetadataEventArgs $ eventArgs){$ classMetadata = $ eventArgs-> getClassMetadata(); $ document =(string)$ classMetadata-> getName();

    if($document == "TestBundle\\Document\\TestDocument"){
        $fieldMapping = array(
            'fieldName' => 'columnTest',
            'type' => 'string'
        );

        /*
        the field is registered as private method
        */
        $classMetadata->reflFields['columnTest'] = new \ReflectionProperty($classMetadata->name,'about');
        $classMetadata->mapField($fieldMapping);
    }

}
  1. ドキュメントに魔法のメソッドを追加する

    public function __set($column,$value){
        $this->$column = $value;
    }
    
    public function __get($column){
        return $this->$column;
    }
    
于 2015-02-14T20:51:39.670 に答える