2015-11-30 23 views
5

私は、共通の関係と属性を持ついくつかのエンタテイを持っています。ですから、継承マッピングを使用してスキーマを単純化したいと思います。多対1、継承マッピングによる自己参照

私はBaseData mappedスーパークラスを作成し、他のエンティティを展開しました。このBaseDataクラスは、各エンティティで必要な共通の関係を持っています。

それは

/** 
* @ORM\MappedSuperclass 
*/ 
class BaseData 
{ 

    /** 
    * @ORM\ManyToOne(targetEntity="Service") 
    * @ORM\JoinColumn(name="service_id", referencedColumnName="id") 
    */ 
    protected $service; 

のように、多対一の関係で動作します。しかし、それは自己参照して、もう少しトリッキーになります。 QLSTATE[42S02]: Base table or view not found: 1146 Table 'project.base_data' doesn't exist:私はこのエンティティを照会しようとすると、

/** 
* @ORM\MappedSuperclass 
*/ 
class BaseData 
{ 

    /** 
    * @ORM\ManyToOne(targetEntity="BaseData") 
    * @ORM\JoinColumn(name="parent_id", referencedColumnName="id", nullable=true) 
    */ 
    protected $parent; 

は明らかに、それはTableNotFoundExceptionにつながる:私は親の参照を作成したいので、

は例えば、私はそれを試してみました。

したがって、私はAssociationOverridesを試しましたが、Target Entityを変更できないようです。

したがって、MappedSuperclassにいくつかの自己参照を構築する方法はありますか?そして、それは理にかなっていますか?

事前に感謝します。ここで

更新

はanwserです:

予定通り、私は私のBaseData mappedSuperClassでprotected $parentprotected $childrenを定義しました。私は彼らに必要なその他の情報を注釈しました。例:

/** 
* @ORM\MappedSuperclass 
*/ 
class BaseData 
{ 

    /** 
    * @Datagrid\Column(field="parent.id", title="datagrid.parent_id", visible=false, safe=false) 
    * @Serializer\Expose 
    * @Serializer\Groups({"foo"}) 
    */ 
    protected $parent; 

    /** 
    * @Serializer\Expose 
    * @Serializer\Groups({"elastica"}) 
    */ 
    protected $children; 

次に、イベントloadClassMetadataでORMリレーションシップを追加します。

/** 
* @param LoadClassMetadataEventArgs $eventArgs 
*/ 
public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs) 
{ 
    // the $metadata is all the mapping info for this class 
    $classMetadata = $eventArgs->getClassMetadata(); 
    $reflObj = new \ReflectionClass($classMetadata->name); 
    if($reflObj) { 
     if ($reflObj->isSubclassOf('CoreBundle\Entity\BaseData')) { 
      $fieldMapping = array(
       'targetEntity' => $classMetadata->name, 
       'fieldName'  => 'parent', 
       'inversedBy' => 'children', 
       'JoinColumn' => array(
        'name'     => 'parent_id', 
        'referencedColumnName' => 'id', 
        'nullable'    => true, 
        'onDelete'    => 'SET NULL', 
       ), 
      ); 

      $classMetadata->mapManyToOne($fieldMapping); 


      $fieldMapping = array(
       'fieldName'  => 'children', 
       'targetEntity' => $classMetadata->name, 
       'mappedBy'  => 'parent', 
      ); 
      $classMetadata->mapOneToMany($fieldMapping); 
     } 
    } 
} 

イベントを登録すると、それだけです。

ここで、BaseDataのsuperClassを拡張するすべてのクラスがリレーションを取得します。例えば、php app/console doctrine:generate:entities MyBundle意志は、サブクラスのエンティティの内部で、次のコードを生成します。

/** 
* Set parent 
* 
* @param \MyBundle\Entity\Subclass $parent 
* 
* @return Subclass 
*/ 
public function setParent(\MyBundle\Entity\Subclass $parent = null) 
{ 
    $this->parent = $parent; 

    return $this; 
} 

/** 
* Get parent 
* 
* @return \MyBundle\Entity\Subclass 
*/ 
public function getParent() 
{ 
    return $this->parent; 
} 

/** 
* Add child 
* 
* @param \MyBundle\Entity\Subclass $child 
* 
* @return Subclass 
*/ 
public function addChild(\MyBundle\Entity\Subclass $child) 
{ 
    $this->children[] = $child; 

    return $this; 
} 

/** 
* Remove child 
* 
* @param \MyBundle\Entity\Subclass $child 
*/ 
public function removeChild(\MyBundle\Entity\Subclass $child) 
{ 
    $this->children->removeElement($child); 
} 

/** 
* Get children 
* 
* @return \Doctrine\Common\Collections\Collection 
*/ 
public function getChildren() 
{ 
    return $this->children; 
} 
+0

を参照してください。 docs: マップされたスーパークラスはエンティティにすることはできませんが、クエリ可能ではなく、マップされたスーパークラスによって定義された永続的な関係は単方向でなければなりません(所有側のみ)。つまり、マップされたスーパークラスでは、1対多の関連付けはまったく不可能です。さらに、多対多の関連付けは、マッピングされたスーパークラスが現時点でただ1つのエンティティでのみ使用されている場合にのみ可能です。 –

+0

私は確かにそれを推測しましたが、私の目標は、各子クラスの自己参照を機能させることでした。つまり、 'targetEntity =" BaseData "'と書くことで、すべての子クラスが独自の名前を使用することを期待していました。だから、私は、それぞれの子クラスで親の自己参照を手動で作成する必要があると思いますか? ご協力いただきありがとうございます。 – TiPi

+1

問題ありません! @MappedSuperclassはエンティティ自体ではありませんので、子供クラスでのみ行うことができます。 p.s. IMHO、@MappedSuperclassはすべての種類の辞書に非常に便利です。たとえば、最後のプロジェクトでは、idとsysNameの2つのフィールドを持つBaseDictionaryDocumentが1つあります。そして、すべての辞書は単に 'class BlahBlahDocument extends BaseDictionaryDocument {}'のように見えていました。もちろん、テーブル/コレクション名の注釈が一番上にあります。 –

答えて

2

あなたはマッピング@ORM\ManyToOne(targetEntity="BaseData")を削除し、イベントloadClassMetadataのイベントリスナーを作成することができます。 (私はこれは単なる出発点で、次のコードをテストしていない)、このような何か:注目すべき

class TestEvent 
{ 
    public function loadClassMetadata(\Doctrine\ORM\Event\LoadClassMetadataEventArgs $eventArgs) 
    { 
     $classMetadata = $eventArgs->getClassMetadata(); 
     $class = $classMetadata->getName(); 
     $fieldMapping = array(
      'fieldName' => 'parent', 
      'targetEntity' => $class, 
     ); 
     $classMetadata->mapManyToOne($fieldMapping); 
    } 
} 

一つ重要なことは、リスナーが自分のアプリケーション内のすべてのエンティティをリッスンするということです。

はMappedSupperclassが実体そのものではないとして、あなたは唯一の子クラスのための自己参照を行うことができますDoctrine docs about events そしてHow to register event listener in symfony2

+0

私はあなたのソリューションを試してみました。私はanwserを統合するために私の質問を更新します。 – TiPi

+0

私はそれが助けてうれしい –