2013-07-11 36 views
6

當前我們正在開發一個Zend Framework 2和Doctrine 2的非常靈活和模塊化的應用程序。在這個應用程序中有多個Doctrine實體,例如,假設模塊Products中的實體Product。該模塊Products是產品管理的基礎/默認模塊。原則繼承替換

我們希望能夠爲客戶創建自定義Products模塊(XProducts)。因此,我創建了一個新實體XProduct(帶有一些額外字段),它擴展了Product

因此,如果自定義模塊啓用,我想使用XProduct和其他Product,但從來沒有在一起(在同一個項目中)。

如果我使用@Entity對兩個實體進行了註釋,它將部分工作;例如findAll工作完美,但find不起作用:創建的SELECT語句包含正確的列,但WHERE子句錯誤。例如:

SELECT t1.id AS id2, t1.name AS name3 FROM products t1 WHERE t0.id = ? 

我想t1代表ProductXt0Product但我想不出爲什麼列是正確的(t1),但在where子句不是(t0)。

我知道Doctrine提供了Single Table Inheritance來實現繼承,但是因此必須有DiscriminatorColumn並且需要在base/default實體上定義DiscriminatorMap。這不適合我們,因爲如果我們爲客戶添加一個新的自定義模塊(而這不是我們想要的),我們需要更改基本/默認模塊。

有沒有人有解決這個問題的線索?謝謝!

回答

7

我終於解決了這個問題。對於所有的默認/基類,我創建了一個額外的抽象MappedSuperclass(如Jurian Sluiman提到的)。例如,對於一個客戶特定Product實體,我需要如下:

  • AbstractProduct(包含所有缺省的/基礎功能)
  • 產品(默認/基類裏面是空的,並延伸AbstractProduct)
  • XProduct(其中包含額外的功能爲我們的客戶和擴展AbstractProduct)

要修復與關聯的問題上MappedSuperclass我指的是抽象類,例如: @ORM\OneToOne(targetEntity="ProductManagement\Entity\AbstractProduct")

然後我用主義的EntityResolver的(見http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/cookbook/resolve-target-entity-listener.html)映射的抽象類(或接口)關聯到一個真正的實體(取決於配置):

'entity_resolver' => array(
    'orm_default' => array(
     'resolvers' => array(
      // Note: Use only one 
      'ProductManagement\Entity\AbstractProduct' => 'ProductManagement\Entity\Product', // Default 
      'ProductManagement\Entity\AbstractProduct' => 'XProductManagement\Entity\XProduct', // For customer X 
     ) 
    ) 
) 

這樣我能夠覆蓋我的實體爲我的客戶提供特定的實體,而無需更改默認/基本模塊和實體(這正是我所需要的)。

+0

我正在嘗試相同的方法,但問題是抽象實體類(AbstractProduct)不能在DQL查詢中使用。根據[手冊](http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/inheritance-mapping.html)映射的超類不能查詢。你如何編寫適用於Product和XProduct的查詢? – aimfeld

3

我們使用這種模式以及與Doctrine一起工作最簡單(儘管它可以使OOP明智得多,但有很多醜陋的代碼)。以我們的Portfolio模塊爲例,其中Portfolio實例可能佔用多個Item實例。

我們使用Portfolio實體,該實體從映射的超類AbstractPortfolio擴展而來。如果我們有一個需要特殊字段的客戶端,我們創建一個擴展映射超類的ClientPortfolio,所以它正確地重載了​​所有的屬性。

類名稱爲specified in the config,該字符串用於例如factory for the repository。您永遠不會加載Portfolio存儲庫,但即使您在服務管理器中以默認組合名稱請求存儲庫類時,始終也會加載ClientPortfolio

此方法可以正常使用存儲庫功能like here(儘管此類是Item而不是Portfolio的存儲庫)。我不會使用單個表繼承,因爲您不需要使用多個實體。至少,這是我們的情況。

+1

感謝您的回答。一個MappedSuperclass聽起來很有趣,但我需要爲所有實體(抽象和默認/基類)創建額外的類。但是,如果它有效;沒關係 :)。只有一個問題:MappedSuperclass不能有一對多和一對一的關係,這正是我想要的;例如'ProductGroup'有一個引用自己的父屬性。所以我認爲使用MappedSuperclass是不可能的。 –

+0

我現在在手機上,所以無法輕鬆檢查,但上面的投資組合模塊有一個包含項目的投資組合容器,具有適當的關係(這是一對多)。檢查Github存儲庫,應該有一些內容來完成這項工作。 –

+0

我可以在模塊中找到的唯一關係是AbstractItem中的Many-to-One關係。當然,另一方面它是一對多的關係,但在我的情況下,我想定義這一邊的關係,這不適用於MappedSuperclass。 –