2013-07-11 32 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。 –