2016-09-12 114 views
2

是否可以动态设置模型的关系?例如,我有型号Page,我想添加关系banners()而不实际更改其文件?那么这样的事情是否存在:Laravel - 雄辩 - 动态定义的关系

Page::createRelationship('banners', function(){ 
    $this->hasMany('banners'); 
}); 

或者类似的东西?因为无论如何都使用魔术方法获取它们,也许我可以动态地添加关系?

谢谢!

+0

使用多态的关系和特点,将完成你想要看看,在laravel单证 –

+0

如果我没看错你还是要定义这些原'Page'模式是什么?我正在寻找一种方法来添加这种关系,而无需编辑文件 – Giedrius

+0

我可以看到'Model'类有一个'setRelation'方法,但它不是静态的,只能在实例上调用。有什么类似的我可以使用,所以它会自动设置所有创建的实例的关系? – Giedrius

回答

1

你必须记住一些事情,Eloquent关系是关系数据库关系(即MySQL)的模型。 所以,我有两种方法。

如果要实现与数据库中的索引和foreing键全功能的口才关系,你可能要动态地改变SQL表。

例如,假设您创建了所有模型并且不想动态创建它们,只需更改Page表格,添加一个名为“banner_id”的新字段,将其索引并引用“banner_id”在横幅桌上的领域。

然后,您必须记下并支持您将使用的RDBMS。之后,您可能需要包含对迁移的支持。如果是这种情况,您可以在数据库中存储这些表进行进一步回滚的更改。

现在,对于Eloquent支持部分,您可以查看Eloquent Model Class

看出,对于每一种关系,你有一个subyacent模型(所有可以找到here,这实际上是你在relatioship方法返回:

public function hasMany($related, $foreignKey = null, $localKey = null) 
{ 
    $foreignKey = $foreignKey ?: $this->getForeignKey(); 
    $instance = new $related; 
    $localKey = $localKey ?: $this->getKeyName(); 
    return new HasMany($instance->newQuery(), $this, $instance->getTable().'.'.$foreignKey, $localKey); 
} 

所以,你必须定义一个方法在你的模型中接受关系类型和模型,创建一个新的HasMany(如果hasMany是期望的关系)实例,然后返回它。

这有点复杂,所以你可以使用:

The easy

您可以创建一个中间模型(即, PageRelationship),它存储Page和其他模型之间的所有关系。一个可能的表格模式可能是:

+-------------+---------+------------------+-------------+ 
| relation_id | page_id | foreign_model_id | model_class | 
+-------------+---------+------------------+-------------+ 
|   1 |  2 |    225 | Banner  | 
|   2 |  2 |    223 | Banner  | 
|   3 |  2 |    12 | Button  | 
+-------------+---------+------------------+-------------+ 

然后,您可以检索给定页面的所有动态相关模型。这里的问题在于,模型和页面之间实际上并没有任何真正的RDBMS关系,因此您可能必须针对加载相关模型进行多重查询,更糟糕的是,您必须自己管理数据库一致性(即,删除或更新“225”横幅也应删除或更新page_relationship_table中的行)。反向关系也会令人头痛。

结论

如果项目很大,这取决于这一点,你不能让那个通过继承来实现其他车型的典范左右,你应该使用的好办法。否则,您应该重新考虑应用程序设计,然后决定是否选择第二种方法。

+0

感谢您的广泛答复。我可以看到如何使用任何一种解决方案,但是如果我没有弄错,两者都需要编辑“Page”模型类。由于我的系统是完全模块化的,因此我试图找到扩展其他模块的模块方式,而不会使模型本身过度复杂化。 – Giedrius

+1

您必须对其进行修改,使其能够处理动态关系功能,因为它不是本地实施的,但您不必稍后再进行更改。模块化系统的正确方法是具有继承模型结构,所以Banner模型扩展了PageElement模型,并建立了Page和PageElement之间的关系。无论如何,使模块化的东西[将复杂化你的模型](http://stackoverflow.com/questions/23973850/model-inheritance-in-laravel)。 – vpedrosa

+1

我将拥有自己的Model类的扩展,它可以被所有模型扩展以获得自定义功能,或者可以将动态关系功能添加到laravel框架中并提交拉取请求,以防更多人觉得有用。一旦我找到一个明确的解决方案,将会发布一个答案。 – Giedrius

0

您可以使用macro呼吁你这样的动态关系:

你应该在你的服务提供商的引导方法编写代码。

\Illuminate\Database\Eloquent\Builder::macro('yourRelation', function() { 
    return $this->getModel()->belongsTo('class'); 
});