我正面临一个问题,这可能是放在programmers.stackexchange.com,太,但因为它是相当绑定到Doctrine和ZF2,我选择把它放在这里。让我给你介绍一下我的场景:
- 我有一个应用程序,用户发布实体(
BaseEntity
)。 -
BaseEntity
具有$cagetory
属性 - 根据
$category
,实体必须有额外的属性
Ab simple示例:
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
)
我做了什么
首先,我选择使用doctrine功能单表继承运行。这使我能够轻松地做MovieEntity extends BaseEntity
之类的事情,并像向数据库添加新实体一样发挥作用。但是主要的问题仍然存在:如果用户改变Category,它会改变EntityClass,这几乎是一个No-Go。
我的意思是,是的,我可以用我现在的方式做事情,在更改类别时手动修改DiscriminatorColumn
,但那太脏了。
另一种替代方法是,在更改类别的事件中,将创建一个新的实体,而旧的实体将被销毁,但这也感觉有点脏。
总而言之,我觉得我走错方向了。可能有一种我不知道的发展模式,使我所有的努力看起来像浪费,事情最终变得超级容易,但似乎我忽略了一些东西。也许得到一个更接近我的想法,你可以看看我在GitHub上的应用程序:
- DuitMarketplace -这是带有基本类别,所有控制器等的主要应用程序。
ItemController#editAction()
可能会提供更多的线索,我打算如何自动制造一些东西。 - DuitMarketplaceItemVehicle -一个被放入主应用 的类别
提前感谢我可能得到的所有反馈。我完全意识到这个问题可能是存在于SO和程序员之间的边界。但是我还是选择把它放在这里
如果我对您的情况理解正确的话,听起来您最好避免在Thing上继承,而是将特定于类别的属性作为Things和Categories之间关系的属性。
这样的架构呢:
<?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实体在类别之间移动。事物的身份从未改变,改变的只是它与范畴的关系。必须包含在该类别中的属性是ThingCategory关系实体的属性,而不是Thing本身的属性。
编辑:您可能遇到的问题是,当子类化实体时,没有记录修改标识符映射的方法。不幸的副作用是,您的基本模块必须了解每个可能的模块。但这可能不是一个大问题。如果是的话,我相信可以通过让每个模块操作基实体的ClassMetaData来避免这种情况,但我从来没有真正让它工作。
你的问题是这句话"但主要问题仍然是:如果用户改变Category,它会改变EntityClass,这几乎是一个No-Go。"
一个类别实际上不会改变,它会被删除,并被一个新的类别所取代。因此,在代码中反映这一点,创建一个新实体,持久化它,更新所有指向新实体的引用,然后删除旧实体。