2013-06-05 48 views
5

我遇到了一个问题,它也可能放在programmers.stackexchange.com上,但由于它与Doctrine和ZF2相关联,所以我选择了放置它在这。让我向您介绍我的场景:如何为不同的实体类别处理不同的实体属性

  • 我有一个应用程序,其中用户发布实体(BaseEntity)。
  • BaseEntity拥有财产$cagetory
  • 根据$category但是实体必须有额外的属性

抗体简单的例子:

class BaseEntity { 
    protected $id; 
    protected $title; 
    protected $description; 
} 

class MovieEntity { 
    protected $id; 
    protected $title; 
    protected $description; 
    protected $airingDateStart; // new property 
    protected $airingDateEnd; // new property 
} 

现在,我可以很容易地做一个两步的表现公式用户首先选择他的类别,并根据该EntityClass将被选中 - 但我不能这样做。但是这并不好,因为如果用户在BaseEntity类别中放置了电影,然后又想要将实体更改为MovieEntity?所以这个想法并不是一个安全的选择。

附加要求(使东西更复杂)

  • 的类别以及各实体由教义来控制
  • 每个Category经由单个Module
  • 提供给应用模块需要放在应用程序中,而不需要太多配置(最多一个DB-Query填充CategoryTable

我做了迄今为止

起初我选择了与教义功能单表继承运行。这使我可以轻松完成诸如MovieEntity extends BaseEntity之类的事情,而且事情就像是将新实体添加到数据库中的魅力一样。但主要问题仍然存在:如果用户改变了Category,它会改变EntityClass,这几乎是No-Go。

我的意思是说,我可以用我目前的方式做事情,并根据类别的变化手动修改DiscriminatorColumn,但那太诡异了。

另一种替代方法是,在改变类别的事件时,将创建一个新实体并且旧实体将被销毁,但是这也感觉有点肮脏。

总而言之,我认为我走向了错误的方向。可能有一种我不知道的发展模式,使我所有的努力工作看起来像是浪费,结果事情变得超级容易,但看起来我忽略了一些东西。

为了可能得到的是什么我为更紧密的想法,你可以看看我在GitHub上的应用程序:

感谢所有反馈我可能会。我完全意识到,这个问题可能是SO与程序员之间存在的边界.stackexchange,但我选择在这里。

回答

3

如果我正确地阅读你的情况,这听起来像你最好通过避免继承关于Thing的东西来获得服务,而将有关类别特定属性的东西看作是事物和类别之间关系的属性。

什么像这样的架构:

<?php 

class Category { 
    protected $id; 
    protected $title; 
    protected $things; //@ManyToOne(targetEntity="ThingCategory") 
} 

class Thing { 
    protected $id; 
    protected $title; 
    protected $description; 
    protected $category; //@ManyToOne(targetEntity="ThingCategory") 
}  

/** 
* Use [Single|Class]-Table Inheritence to model subject-category attributes. 
* 
* ThingCategory is just a base class. Modules provide concrete subclasses 
* that encapsulate category-specific attributes. 
*/ 
class ThingCategory { 
    protected $id; //surrogate key, not strictly necessary 
    protected $thing; //@ManyToOne(targetEntity="Thing") 
    protected $category //@ManyToOne(targetEntity="Category") 
} 

class ThingMovieCategory extends ThingCategory{ 
    protected $airingStartDate; 
    protected $airingEndDate; 
} 

class ThingCarCategory extends ThingCategory { 
    protected $horespower; 
    protected $numberOfDoors; 
    protected $color; 
} 

所以,现在事情可以类别之间通过更换与它相关的ThingCategory实体移动。 Thing的身份永远不会改变,只是它与类别的关系。包含在该类别中的属性是ThingCategory关系实体的属性,而不是Thing本身的属性。

编辑:您可能会遇到的问题是,没有记录的方式来修改实体的子类时修改鉴别器映射。不幸的副作用是您的基本模块必须知道每个可能的模块。但这可能不是一个大问题。如果是这样,我相信可以通过让每个模块操作基本实体的ClassMetaData来避免这种情况,但是我从来没有为实际工作而烦恼。

+0

嘿蒂姆,感谢您的意见,设计看起来比我迄今为止在我的应用程序中做得更清楚,所以感谢您的意见。我看到的问题(虽然我可能是错的)仍然是一个类别的变化。当您选择不同的类别时,您的示例是否会自动更新“实体”内的'discriminatorColumn'?我一定会测试一下! PS:从某些模块扩展DiscriminatorMapping:参见[SubModule的myBootstrap()](https://github.com/manuakasam/DuitMarketplaceItemVehicle/blob/master/Module.php#L35-L48) – Sam

+1

Sam,I don不这么认为,只有一件“事情”(或“基本实体”)。那些与'MovieEntity'不同的'BaseEntity'已经被移到了不同​​的类别中。我在timdev的解决方案中缺少的是如何存储由“Thing”类别定义的那些属性的值。需要一个'ThingCategoryProperty'实体,它具有与'Thing'和'Category'的ManyToOne关联。顺便说一句,我喜欢你解决DiscriminatorMapping动态内容的方式! – netiul

+0

@Sam - 不,当您更改类别时,您将删除一个ThingSomeCategory并插入其他一些ThingSomeCategory。 – timdev

1

你的问题是这句话“但主要问题仍然存在:如果用户改变了类别,它会改变EntityClass,而这几乎是一个No-Go。”

类别不会真的改变,它会被删除,并被替换为新的。因此,在代码中反映这一点,创建一个新实体,坚持它,更新所有引用以指向新实体,然后删除旧实体。

+0

现在,我将采用这种设计原则,仅仅因为它意味着对我当前应用程序的最小改变。尽管当我有更多时间时,我肯定需要在稍后重构代码 – Sam

相关问题