如何使用 Laravel 的 Eloquent 实现单表继承?
目前我有一个名为 Post
的模型类.
Currently I have a model class named Post
.
class Post extends Eloquent {
protected $table = 'posts';
protected $fillable = array('user_id', 'title', 'description', 'views');
/*
* Relationships
*/
public function user()
{
return $this->belongsTo('User');
}
public function tags()
{
return $this->belongsToMany('Tag', 'post_tags');
}
public function reactions()
{
return $this->hasMany('Reaction');
}
public function votes()
{
return $this->hasMany('PostVote');
}
//Scopes and functions...
}
我想把帖子分成两种不同的类型;文章
和问题
.我认为最好的方法是通过继承,所以 Article
和 Question
将扩展 Post
.执行此操作的最佳方法是什么?从哪里开始?
I would like to divide posts into two different types; articles
and questions
. I thought the best way to do this is by inheritance, so Article
and Question
would extend Post
. What is the best way to do this and where to start?
推荐答案
在深入研究多表继承之前,我想对单表继承多说几句.当涉及到 db 模型的继承时,单表继承是更简单的方法.
您有多个模型绑定到同一个表和一个 type
列来区分不同的模型类.然而,您通常想要实现继承的原因是因为模型具有共享属性,但也有一些是模型独有的.
使用单表继承时,您的表在某些时候看起来类似于:
Before I dig into multi table inheritance I want to lose a few words about single table inheritance. Single table inheritance is the more easy way when it comes to inheritance with db models.
You have multiple models bound to the same table and a type
column to distinguish between the different model classes. However the reason you normally want to implement inheritance is because the models have shared properties but also some that are unique to the model.
When using single table inheritance your table looks similar to that at some point:
id shared_column question_column article_column question_column2 article_column2 etc...
1 Lorem 62 NULL test NULL
2 Ipsum NULL x NULL true
您最终会得到很多 NULL 值,因为某些类型的模型不需要某些列.并且有很多记录,这会影响数据库的大小.
You end up having a lot of NULL values because there are columns not needed for a certain type of model. And with a lot of records this can influence the size of database.
但是在某些情况下,它可能仍然是最佳解决方案.这是一个写得很好的教程,展示了如何实现它在 Laravel 中以一种非常优雅的方式.
However for some cases it might still be the best solution. Here's a well written Tutorial that shows how to implement it in Laravel in a pretty elegant way.
现在让我们看看多表继承.使用这种方法,您可以将单个表拆分为多个表(好吧,我猜这个名字已经给出了这种方式;))我们将使用一种称为 多态
Now lets look at multi table inheritance. With this method you split your single table into multiple ones (well I guess the name gave that kind of away already ;)) We are going to use a technique called Polymorphism
我们上面示例中的架构如下所示:
Our schema from the example above would look like this:
posts table:
id shared_column postable_id postable_type
1 Lorem 1 Question
2 Ipsum 1 Article
questions table:
id question_column question_column2
1 62 test
articles table:
id article_column article_column2
1 x true
如果你问我的话,会干净很多......
A lot cleaner if you ask me...
这里有趣的列是 postable_id
和 postable_type
.类型告诉我们将在哪张桌子上找到我们的休息".模型和 id 指定属于它的记录的主键.请注意,列名可以是您想要的任何名称,但习惯上称其为-able".
The interesting columns here are postable_id
and postable_type
. The type tells us on which table we will find our "rest" of the model and the id specifies the primary key of the record that belongs to it. Note that the column names could be whatever you want, but it is convention to call it "-able".
现在让我们来看看 Eloquent 模型.
Lets take a look at the Eloquent models now.
发布
class Post extends Eloquent {
// all your existing code
public function postable(){
return $this->morphTo();
}
}
问题/文章/所有其他可发布类型
class Question extends Post {
public function post(){
return $this->morphOne('Post', 'postable');
}
}
请注意,您实际上不必从 Post
扩展,但如果您也有想要使用的方法,则可以.不管怎样,无论有没有多态关系都可以工作.
Note that you actually don't have to extend from Post
but you can if you maybe have methods that you want to use too. Anyways, the polymorphic relationship will work with or without it.
好的,这是基本设置.以下是使用新模型的方法:
Ok that's the basic setup. Here's how you can use your new models:
检索所有帖子
$posts = Post::all();
检索所有问题
$questions = Question::all();
从帖子中获取问题列
$post = Post::find(1);
$question_column2 = $post->postable->question_column2;
从问题中获取帖子属性
$question = Question::find(1);
$shared_column = $question->post->shared_column;
检查帖子的类型
$post = Post::find(1);
echo 'type: '.get_class($post->postable);
if($post->postable instanceof Question){
// Looks like we got a question here
}
创建新问题
现在容忍我,创建模型有点复杂.如果您必须在应用程序的多个位置执行此操作,我建议您为它编写一个可重用的函数.
Now bear with me, creating a model is a bit more complicated. If you have to do it at multiple places in your application I suggest you write a reusable function for it.
// create a record in the questions and posts table
$question = new Question();
$question->question_column = 'test';
$question->save();
$post = new Post();
$post->shared_column = 'New Question Post';
$post->save();
// link them together
$question->post()->save($post);
如您所见,干净的数据库是有代价的.处理您的模型会更复杂一些.但是,您可以将所有这些额外的逻辑(例如创建模型所需的)放入模型类中的函数中,而不必太担心.
So as you can see, a clean database comes with it's price. It will be a bit more complex to handle your model. However you can put all these extra logic (e.g. that's required to create a model) into a function in your model class and don't worry about it too much.
此外,还有一个不错的 教程 也用于 Laravel 的多表继承.也许它有帮助;)
Also, there's a nice Tutorial for multi table inheritance with laravel too. Maybe it helps ;)
相关文章