現在、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...
}
投稿を2つのタイプに分けたいと思います。 articles
およびquestions
。これを行う最良の方法は継承によるものだと思ったので、Article
とQuestion
はPost
を拡張します。これを行う最善の方法は何ですか?
multi table継承について詳しく調べる前に、single table継承について少し説明しておきます。単一テーブルの継承は、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
特定のタイプのモデルには不要な列があるため、多くの場合、NULL値が多くなります。そして、多くのレコードがあると、これはデータベースのサイズに影響を与える可能性があります。
ただし、場合によっては、それでも最善の解決策になることがあります。これはよく書かれた Tutorial で、これをLaravelで非常にエレガントな方法で実装する方法を示しています。
次に、マルチテーブルの継承を見てみましょう。この方法を使用して、単一のテーブルを複数のテーブルに分割します(名前はすでにそのようなものを付けていると思いますが;)) Polymorphism という手法を使用します
上記の例のスキーマは次のようになります。
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
あなたが私に尋ねれば、もっときれいに...
ここで興味深い列はpostable_id
およびpostable_type
。タイプにより、モデルの「残りの部分」が見つかるテーブルがわかります。IDは、それに属するレコードの主キーを指定します。カラム名は好きなようにすることができますが、それを呼び出すのは慣習です "-able"。
Eloquentモデルを見てみましょう。
投稿
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
から拡張する必要はありませんが、使用したいメソッドがある場合は拡張できます。とにかく、ポリモーフィックな関係は、それがあってもなくても機能します。
それが基本的なセットアップです。新しいモデルの使用方法は次のとおりです。
すべての投稿を取得
$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
}
新しい質問を作成
モデルの作成はもう少し複雑です。アプリケーションの複数の場所で行う必要がある場合は、再利用可能な関数を作成することをお勧めします。
// 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);
ご覧のとおり、クリーンなデータベースには価格が付いています。モデルの処理は少し複雑になります。ただし、これらすべての追加ロジック(モデルの作成に必要なロジックなど)をモデルクラスの関数に配置でき、あまり心配する必要はありません。
また、laravelを使用した複数テーブルの継承のための素敵な Tutorial もあります。多分それは役に立ちます;)
から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'
は、Article
と同様に、SoftDeletes
のすべてのクエリに追加されます。
>>> App\Article::where('id', 1)->toSql()
=> "select * from `posts` where `id` = ? and `type` = ?"
実際にlaravelこの機能を使用してSoftDeletes
特性を提供します。