本記事では、Laravel上でポリモーフィック関連となるデータ構造をEloquentのリレーションでどう実装するか について紹介を行います。
1つの子テーブルから複数の親テーブルを参照する関連のことを指します。
例えば、ブログや商品にコメントを添付する機能を実装する場合、ポリモーフィック関連を利用するのが良いとされています。
テーブル構造は以下のような形になります。
posts
- id : 主キー
- tilte : ブログタイトル
- content : 内容
products
- id : 主キー
- name : 商品名
- discription : 商品説明
comments
- id : 主キー
- content : コメント内容
- commentable_type : 関連レコードのモデル名
- commentable_id : 関連レコードの主キー
commentsテーブル
のcommentable_id
とcommentable_type
がポリモーフィック関連における外部キーとなり、postsテーブル
やproductsテーブル
のレコードと関連付けられます。
commentable_type
によって、コメントがどのテーブルに属するのかを特定できます。
Laravelではポリモーフィック関連のサポートが行われているため、簡単にMigrationを記述できます。
例で示したcommentsテーブル
のMigration記述例は以下になります。
Schema::create('comments', function (Blueprint $table) {
$table->text('comment')->comment('コメント内容');
$table->morphs('commentable');
});
$table->morphs('〇〇');
こちらの記述により、 ポリモーフィック関連における外部キー用のカラム(〇〇_type
,〇〇_id
)の作成が一括で行えます。
Laravelのモデルでリレーションの記述を行うことによって、 子テーブルのモデル
から、親テーブルのモデル
の取得が行えるようになります。
リレーションの記述、利用方法について紹介を行っていきます。
親テーブルと子テーブルが1対1である場合のリレーションの記述、利用方式について紹介していきます。
テーブルの構造は以下とします
posts
- id : 主キー
- tilte : ブログタイトル
- content : 内容
products
- id : 主キー
- name : 商品名
- discription : 商品説明
comments
- id : 主キー
- content : コメント内容
- commentable_type : 関連レコードのモデル名
- commentable_id : 関連レコードの主キー
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
public function comment()
{
return $this->morphOne(Comment::class, 'commentable');
}
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
public function comment()
{
return $this->morphOne(Comment::class, 'commentable');
}
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
public function commentable()
{
return $this->morphTo(__FUNCTION__, 'commentable_type', 'commentable_id');
}
}
親モデルから子モデルを取得する方法は
use App\Models\Post;
$post = Post::find(1);
$comment = $post->comment;
となります。
こちらにより、親モデル(Postモデル
)から、子モデル(commentモデル
)を取得することができます。
逆に、子モデルから親モデルを取得する方法は
use App\Models\Comment;
$comment = Comment::find(1);
$value = $comment->commentable;
となります。
こちらにより、子モデル(commentモデル
)から親モデル(Postモデル
, Productモデル
)を取得することができます。
取得されるモデルはcomment.commentable_type
に記述されているモデル名に応じて変化します。
親テーブルと子テーブルが1対多である場合のリレーションの記述、利用方式について紹介していきます。
1対多の場合でも、1対1と同じようなテーブル構造・リレーションの記述になります。
テーブルの構造は以下とします。
posts
- id : 主キー
- tilte : ブログタイトル
- content : 内容
products
- id : 主キー
- name : 商品名
- discription : 商品説明
comments
- id : 主キー
- content : コメント内容
- commentable_type : 関連レコードのモデル名
- commentable_id : 関連レコードの主キー
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
public function commentable()
{
return $this->morphTo(__FUNCTION__, 'commentable_type', 'commentable_id');
}
}
親モデルから子モデルを取得する方法は
use App\Models\Post;
$post = Post::find(1);
$comments = $post->comments;
となります。
こちらにより、親モデル(Postモデル
)から、紐づくすべての子モデル(commentモデル
)を取得することができます。
逆に、子モデルから親モデルを取得する方法は
use App\Models\Comment;
$comment = Comment::find(1);
$value = $comment->commentable;
となります。
こちらにより、子モデル(commentモデル
)から親モデル(Postモデル
, Productモデル
)を取得することができます。
取得されるモデルはcomment.commentable_type
に記述されているモデル名に応じて変化します。
親テーブルと子テーブルが多対多である場合のリレーションの記述、利用方式について紹介していきます。
テーブルの構造は以下とします
posts
- id : 主キー
- tilte : ブログタイトル
- content : 内容
products
- id : 主キー
- name : 商品名
- discription : 商品説明
comments
- id : 主キー
- content : コメント内容
commentables
- comment_id : コメントID
- commentable_type : 関連レコードのモデル名
- commentable_id : 関連レコードの主キー
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
public function comments()
{
return $this->morphToMany(Comment::class, 'commentable');
}
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
public function comments()
{
return $this->morphToMany(Comment::class, 'commentable');
}
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
public function Posts()
{
return $this->morphedByMany(Post::class, 'commentable');
}
public function Products()
{
return $this->morphedByMany(Product::class, 'commentable');
}
}
親モデルから子モデルを取得する方法は
use App\Models\Post;
$post = Post::find(1);
$comments = $post->comments;
となります。
こちらにより、親モデル(Postモデル
)から、紐づくすべての子モデル(commentモデル
)を取得することができます。
逆に、子モデルから親モデルを取得する方法は
use App\Models\Comment;
$comment = Comment::find(1);
$posts = $comment->posts;
$products = $comment->products;
となります。
こちらにより、子モデル(commentモデル
)からそれぞれの親モデル(Postモデル
, Productモデル
)を取得することができます。
今回紹介したリレーションによって、 Laravelではポリモーフィック関連のテーブルの場合でも、簡単に関連テーブルの取得が行えるようになります。
実務で行っている案件上で、ポリモーフィック関連のテーブルを扱う際に「Laravel上でどのように行えばよいのか」が理解しづらかったので、今回紹介させていただきました。
Laravelを利用した開発の手助けの一因になれれば幸いです。
ここまで読んでいただきありがとうございました。