2011-11-08 7 views
1

Doctrine2でクラスのマッピングを設定する方法がわかりません。 (アドレスは、それ自体で存在することができDoctrine2:継承したクラスの効率的なマッピング

  • :以下の要件を考慮すると

    class Address{} 
    class BusinessAddress extends Address{} 
    class PersonalAddress extends Address{} 
    

    Address table 
    --------------------- 
    - id 
    - civic_no 
    - road 
    - state 
    - country 
    
    PersonnalAddress table 
    --------------------- 
    - id 
    - base_address_id 
    - type 
    - is_primary 
    
    BusinessAddress table 
    --------------------- 
    - id 
    - base_address_id 
    - business_name 
    - shipping_phone 
    - is_primary 
    

    そしてthoses PHPオブジェクト:

    レッツは、私はこれらのテーブルをしたと言いますアドレスクラスは抽象ではありません)

  • 個人的住所とbusinessAddressは全く同じ住所データを持つことができます
  • 住所を削除または編集すると、その住所がビジネスまたは個人の住所から継承されたすべての住所に影響します。
  • 私はデータベースにデータの複製をしたくありません(これは2番目の正規形式の要件です)
  • プロキシの方法はコードの重複を意味し、私は持っていない方がいいです。
  • マジックメソッドはテスト容易性の点では良くありません。

より良い問題を説明するために、私は、データベース内のデータがどのように見えることを期待:論文の要件を満たすソリューションを実装するための最良の戦略だろう何

Address table: 
id | civic_no | road | state | country 
1  123 test  qc  ca 

PersonnalAddress table: 
id | base_address_id | type | is_primary 
1     1  A   0 
2     1  B   1 

BusinessAddress table: 
id | base_address_id | business_name | shipping_phone | is_primary 
1     1  chic choc   1231234   1 

答えて

1

[OK]を、これは長い1のビットですが、私はそれはすべてあなたの拠点をカバーだと思い、質問があれば、その後に感じ、このような何かお気軽にお問い合わせください。

MappedSuperclassでMany-To-Oneを実行できるかどうかわからない警告が表示されます。それが不可能な場合は、Class Table Inheritanceを代わりに使用することができます。試してみて、効果があるかどうか教えてください。

私はこのコードを非常に素早くプッシュしましたが、テストされていないので正しいとは限りませんが、うまくいけばその仕組みがわかります。

ここに行きます!

インターフェイスは、簡単にそして、抽象クラスを作成するメソッドをオーバーライドし、「悪いデザイン」感を引き起こすことなく、「アドレスが何であるか」と言って作る;)あなたが本当にない

interface Address { 

    function getCivicNo(); 

    function getRoad(); 

    function getState(); 

    function getCountry(); 
} 

抽象エンティティをあなたがIDコードを複製する必要がある場合はそれを使用する必要はありません。

/** 
* @ORM\MappedSuperclass 
*/ 
abstract class AbstractEntity { 

    /** 
    * Entity ID column. 
    * 
    * @var integer 
    * 
    * @ORM\Id 
    * @ORM\Column(type="integer") 
    * @ORM\GeneratedValue 
    */ 
    private $id; 

    public function getId() { 
     return $id; 
    } 

} 

あなただけ保存することができますまたは「ComplexAddress」

/** 
* @ORM\Entity 
*/ 
class BasicAddress extends AbstractEntity implements Address { 

    /** @ORM\Column() */ 
    private $road; 

    public function getRoad() { 
     return $this->road; 
    } 

    // etc etc 

} 

「ComplexAddress」にリンクされているBasicAddressは、基本的なアドレスへの呼び出しを委任するためのコードを再利用できるようにするだけでここにあります。

/** 
* @ORM\MappedSuperclass 
*/ 
abstract class ComplexAddress extends AbstractEntity implements Address { 

    /** @ORM\Many-To-One(targetEntity="BasicAddress") 
    private $basicAddress; 

    public function __construct(BasicAddress $basicAddress) { 
     $this->basicAddress = $basicAddress; 
    } 

    public function getRoad() { 
     return $this->basicAddress->getRoad(); 
    } 

    // other methods for implementing "Address" just delegate to BasicAddress 

} 

PublicAddress

/** 
* @ORM\Entity() 
*/ 
class PersonalAddress extends ComplexAddress { 

    /** @ORM\Column(type="boolean") */ 
    private $isPrimary; 

    public function isPrimary() { 
     return $isPrimary; 
    } 

    // other personal address methods here 

} 

BusinessAddress

/** 
* @ORM\Entity() 
*/ 
class BusinessAddress extends ComplexAddress { 

    /** @ORM\Column() */ 
    private $businessName; 

    public function getBusinessName() { 
     return $this->businessName; 
    } 

    // other business address methods here 

} 

編集:ちょうど私が削除のためにカスケードパラメータを入れるのを忘れに気づいた、あなたはかかわらず、直接これを処理する必要があるかもしれません - BasicAddressが削除されましたそれを使用する他のアドレスも削除してください。

+0

これはうまくいくと思います。マニュアルでは、「マップされたスーパークラスでは1対多の関連付けが不可能である」ということを示しています。また、他の2種類の継承は、 2つの異なるタイプが同じ親を持つことは不可能です。 – FMaz008

0

代わりアドレスクラスを拡張するには、住所PersonalAddressBusinessAddressManyToOne関係上OneToMany関係を作成する必要があります。

<?php 

// ... 

use Doctrine\Common\Collections\ArrayCollection; 

// ... 
class Address 
{ 
    // ... 

    /** 
    * @ORM\OneToMany(targetEntity="PersonalAddress", mappedBy="address") 
    */ 
    private $personalAddresses; 

    /** 
    * @ORM\OneToMany(targetEntity="BusinessAddress", mappedBy="address") 
    */ 
    private $businessAddresses; 

    public function __construct() 
    { 
     $this->personalAddresses = new ArrayCollection(); 
     $this->businessAddresses = new ArrayCollection(); 
    } 

    // ... 
} 

そして、子クラスのために:

<?php 

// ... 

// ... 
class PersonalAddress 
{ 
    // ... 

    /** 
    * @ORM\ManyToOne(targetEntity="Address", inversedBy="personalAddresses") 
    * @ORM\JoinColumn(name="base_address_id", referencedColumnName="id") 
    */ 
    private $address; 

    // ... 
} 
+0

興味深いですが、なぜ私のAddressオブジェクトはpersonalAddressとbusinessAddressについて知っていますか?また、プロキシメソッドを使用せずにPersonnalAddressクラスからAddressメソッドにアクセスするにはどうすればよいですか? – FMaz008

+0

'' 'PersonalAddressClass'''から' '' 'Address''クラスにどうやってアクセスできますか? '' 'doctrine:generate:entities'''を実行するgetterとsetterを作成し、' '$ personalAddress-> getAddress()' ''を実行できます。 –

+0

これは私の最初の実装の試みでした。 PHPの観点からは、私が望むものではありません。クラスを使用する人は、オブジェクトを処理する必要があります。オブジェクトには2つのオブジェクトがあります。だから、オブジェクトを使用できるようにするためには、私はpersonAddress、businessAddressなどのようなプロキシメソッドを作成する必要があります。public function getStreet(){return $ this-> address-> getRoad (); }それは非常に悪い練習です(教義のコミュニティでよく使われていると思われるイベント) – FMaz008

関連する問題