如何处理不同实体类别的不同实体属性

时间:2013-06-05 18:01:14

标签: php doctrine-orm zend-framework2

我遇到了一个问题,也可能放在programmers.stackexchange.com上,但由于它与Doctrine和ZF2非常相关,所以我选择将它放在这里。让我向您介绍我的方案:

  • 我有一个应用程序,其中用户发布实体(BaseEntity)。
  • BaseEntity具有属性$cagetory
  • 根据$category,实体必须具有其他属性

Ab简单示例:

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怎么办?所以这个想法并不是一个安全的选择。

附加要求(使事情变得更复杂)

  • 类别和实体必须由Doctrine
  • 控制
  • 每个Category都通过单个Module
  • 提供给应用程序
  • 模块需要放入应用程序而无需太多配置(最多只需一个DB-Query来填充CategoryTable

到目前为止我做了什么

首先,我选择运行Doctrines功能单表继承。这使我能够轻松地执行MovieEntity extends BaseEntity之类的操作,并且可以像将魅力添加到数据库一样。但主要问题仍然存在:如果用户更改了类别,它将改变EntityClass,这几乎是一个禁忌。

我的意思是,我可能会以当前的方式做事情,并且在类别的更改上手动修改DiscriminatorColumn,但这太脏了。

另一种替代方法是,如果更改类别,将创建一个新实体,旧实体将被销毁,但这也有点脏。

总而言之,我认为我走向了错误的方向。可能有一个我不知道的开发模式,这使得我的所有努力工作看起来都是浪费,最终事情变得非常简单,但看起来我忽略了一些东西。

为了更好地了解我的目标,您可以查看我在GitHub上的应用程序:

提前感谢我收到的所有反馈。我完全意识到这个问题可能是SO与programmers.stackexchange存在之间的边界,但我毕竟选择了它。

2 个答案:

答案 0 :(得分: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实体在类别之间移动。事物的身份永远不会改变,只是它与类别的关系。包含在该类别中的必要属性是ThingCategory关系实体的属性,而不是Thing本身的属性。

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

答案 1 :(得分:1)

你的问题就是这句话“但主要的问题仍然存在:如果用户更改了类别,它将改变EntityClass,这几乎是一个禁忌。”

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