如何使用 Laravel 的 Eloquent 实现单表继承?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26691577/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I implement single table inheritance using Laravel's Eloquent?
提问by JasonK
Currently I have a model class named Post
.
目前我有一个名为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...
}
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?
我想将帖子分为两种不同的类型;articles
和questions
。我认为最好的方法是通过继承,因此Article
并且Question
会扩展Post
. 这样做的最佳方法是什么以及从哪里开始?
回答by lukasgeiter
Before I dig into multi tableinheritance I want to lose a few words about single tableinheritance. 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:
在深入研究多表继承之前,我想对单表继承多说几句。当涉及到 db 模型的继承时,单表继承是更简单的方法。
您有多个模型绑定到同一个表和一个type
列来区分不同的模型类。然而,您通常想要实现继承的原因是因为模型具有共享属性,但也有一些是模型独有的。
使用单表继承时,您的表在某些时候看起来类似于:
id shared_column question_column article_column question_column2 article_column2 etc...
1 Lorem 62 NULL test NULL
2 Ipsum NULL x NULL true
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.
您最终会得到很多 NULL 值,因为某些类型的模型不需要某些列。对于大量记录,这会影响数据库的大小。
However for some cases it might still be the best solution. Here's a well written Tutorialthat shows how to implement it in Laravel in a pretty elegant way.
但是,对于某些情况,它可能仍然是最佳解决方案。这是一个写得很好的教程,它展示了如何以一种非常优雅的方式在 Laravel 中实现它。
Multi Table Inheritance
多表继承
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...
如果你问我,会干净很多......
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".
这里有趣的列是postable_id
和postable_type
。类型告诉我们将在哪个表上找到模型的“其余部分”,id 指定属于它的记录的主键。请注意,列名可以是您想要的任何名称,但习惯上称其为"-able"。
Lets take a look at the Eloquent models now.
现在让我们来看看 Eloquent 模型。
Post
邮政
class Post extends Eloquent {
// all your existing code
public function postable(){
return $this->morphTo();
}
}
Question/ Article/ every other postable type
问题/文章/所有其他可邮寄类型
class Question extends Post {
public function post(){
return $this->morphOne('Post', 'postable');
}
}
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.
请注意,您实际上不必扩展 fromPost
但如果您也有想要使用的方法,则可以。不管怎样,无论有没有它,多态关系都可以工作。
Ok that's the basic setup. Here's how you can use your new models:
好的,这是基本设置。以下是使用新模型的方法:
Retrieve all posts
检索所有帖子
$posts = Post::all();
Retrieve all questions
检索所有问题
$questions = Question::all();
Get question columns from a post
从帖子中获取问题列
$post = Post::find(1);
$question_column2 = $post->postable->question_column2;
Get post properties from question
从问题中获取帖子属性
$question = Question::find(1);
$shared_column = $question->post->shared_column;
Check which type a post is
检查帖子是哪种类型
$post = Post::find(1);
echo 'type: '.get_class($post->postable);
if($post->postable instanceof Question){
// Looks like we got a question here
}
Create new question
创建新问题
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.
正如您所看到的,一个干净的数据库是有代价的。处理您的模型会更复杂一些。但是,您可以将所有这些额外的逻辑(例如,创建模型所需的)放入模型类中的函数中,而不必太担心。
Also, there's a nice Tutorialfor multi table inheritance with laravel too. Maybe it helps ;)
此外,还有一个很好的教程,用于使用 laravel 进行多表继承。也许它有帮助;)
回答by Kazuya Gosho
from Laravel 5.2, Global Scope
is available:
从 Laravel 5.2 开始,Global Scope
可用:
class Article extends Post
{
protected $table = 'posts';
protected static function boot()
{
parent::boot();
static::addGlobalScope('article', function (Builder $builder) {
$builder->where('type', 'article');
});
static::creating(function ($article) {
$article->type = 'article'
});
}
}
where type = 'article'
is added to all query of Article
just like SoftDeletes
.
where type = 'article'
被添加到Article
just like 的所有查询中SoftDeletes
。
>>> App\Article::where('id', 1)->toSql()
=> "select * from `posts` where `id` = ? and `type` = ?"
Actually laravel provide SoftDeletes
trait using this feature.
实际上,laravelSoftDeletes
使用此功能提供了trait。