在我的数据库模式中,我有几个与父表相关的表。解决关系问题的“丑陋”方法是在模式中手动包含依赖项:
sfArea:
columns:
id: integer
name: string
sfCity:
columns:
name: string
area_id: integer
relations:
Area:
class: sfArea
local: area_id
foreignType: many
foreignAlias: Cities
sfItem:
columns:
name: string
area_id: integer
relations:
Area:
class: sfArea
local: area_id
foreignType: many
foreignAlias: Items
但是,每次我要添加一个要附加到该区域的类时,我都需要添加关系以及随之而来的所有行(copy / paste => future hell)。这是我决定使用Doctrine_Template的地方,它允许我实现同样的目的:
sfArea:
columns:
id: integer
name: string
sfCity:
actAs:
AreaRelated: { foreignAlias: Cities }
columns:
name: string
sfItem:
actAs:
AreaRelated: { foreignAlias: Items }
columns:
name: string
模板类:
class AreaRelated extends Doctrine_Template
{
protected $_options = array(
'foreignAlias' => ''
);
public function setTableDefinition()
{
$this->hasColumn('area_id', 'integer');
}
public function setUp()
{
$this->hasOne('sfArea as Area', array(
'local' => 'area_id',
'foreign' => 'id',
'foreignType' => 'many',
'foreignAlias' => $this->_options['foreignAlias']
)
);
}
}
正确生成表格,并且关系在$ sfCity-> Area方向上有效。但是,不应创建应在sfArea类中设置的关系($ sf_area-> Cities给出错误“未知记录属性/相关组件”城市“on”sfArea“”)。
如何创建其他关系?我甚至尝试过(没有成功):
//...
public function setUp()
{
$thisTable = $this->_table;
$areaTable = Doctrine::getTable("smArea");
$thisTable->hasOne('smArea as Area', array(
'local' => 'area_id',
'foreign' => 'id',
'foreignType' => Doctrine_Relation::MANY
)
);
$areaTable->hasMany($thisTable->getOption('name') . ' as ' . $this->_options['foreignAlias'], array(
'local' => 'id',
'foreign' => 'area_id',
'foreignType' => Doctrine_Relation::ONE
)
);
}
答案 0 :(得分:0)
到目前为止,为了记录,我最好的猜测是在模式文件中以手动方式进行。由于Nathan提到的模式变化很少,我认为如果行为无法实现(这将作为一个副项目继续尝试),这是最好的方法。行为方法的好处是,它可以在依赖于此中心对象的所有对象上自动且一致地生成与特定非常中心对象的关系。
另一个可以使用的有用示例是,例如,多站点博客引擎,其中所有帖子,用户,类别,媒体上传,......都与特定博客相关。
sfArea:
columns:
id: integer
name: string
sfCity:
columns:
name: string
area_id: integer
relations:
Area:
class: sfArea
local: area_id
foreignType: many
foreignAlias: Cities
sfItem:
columns:
name: string
area_id: integer
relations:
Area:
class: sfArea
local: area_id
foreignType: many
foreignAlias: Items
答案 1 :(得分:0)
不幸的是,如果没有至少一些额外的定义*,我认为没有办法做到这一点。要做到这一点的一种方法是需要最少的添加,那就是通过一个选项枚举区域上的关系:
Area:
options:
models_with_areas: [Cities, Items]
然后在Area::setUp
public function setUp()
{
parent::setUp();
$models = $this->getTable()->getOption('models_with_areas');
foreach($models as $model)
{
$this->hasMany($model, array(
'local' => 'id',
'foreign' => Doctrine_Inflector::tablize($model) . '_id'
));
}
}
当然,这种方法是不灵活的,如果你想要更复杂的逻辑或选项,这种方法效果不是很好。你总是可以在Area上定义关系,但是继续在关系的许多方面使用行为。
与其他一些答案相反,我确实认为这是一种合理的方法,可能是一个好主意。 Symfony / Doctrine哲学的核心原则是不要重复自己。这个解决方案坚持这个想法。如果在AreaRelated的类之间共享逻辑,它还提供了显着的好处。
*除了一个丑陋的:你可以遍历每个表并找到任何具有模板AreaRelated的表。这需要在每次加载区域记录时实例化每个表,这听起来像是一个绝对可怕的想法。
答案 2 :(得分:-1)
我认为你有一个很大的模型问题,在数据库上代表这种雇佣只会让你头疼不已。我正在为一个有类似东西的主要网站做一些淘汰,并且很糟糕。
我的建议是,如果真的需要在数据库中存在,或者在建模关系数据库时你正在考虑对象,那就考虑一下并重新分析。
使用您在示例中提供的信息,City和类似“类别”,因此如果将它们放在参考表中,则可以对区域进行分类,从而最大限度地减少代码复制。一个类别可能有其他关系,或者只是一个包含大量字段的大表。
所以这是我建议的那种模型(推进):
Area:
tableName: area_table
description: Area
columns:
id:
name:
category_id:
type: integer
foreignClass: Category
foreignReference: id
required: true
Category
tableName: categor_table
description: An area specialization
columns:
id:
model_class_name:
type: varchar(255)
description: the model Class that will represent this piece of information
field1:
field2:
relation:1
使用mode_class_name作为提示知道如何处理原始数据,您可以执行以下操作:
CategoryClass >>
public function getObjectRepresentation()
{
return new $this->getModelClassName()($this);
}
[...]
RealObjectRepresentation1 >>
public function __construct(Category $category)
{
//Initialize proper object using category information
}
因此,您已将DatabaseHirearchy移至PhpObjectHirearchy
希望这在某种程度上有所帮助,如果您需要更多细节我会很乐意提供帮助!