
データベースのテーブルの多くは他のテーブルと関係性を持ちます。例えば posts
テーブルで管理されているブログの投稿は comments
テーブルで管理されている複数のコメントと関係しています。
テーブル同士の関係性をEloquent Modelを使えば簡単に定義することができます。今回はモデルを使った関係性の中でも多対多のリレーションについて定義と実際の利用方法をまとめます。
多対多を定義する
「学生」と生徒が受講している「授業」を想定してみましょう。
多対多の関係の場合、2つのテーブルとは別に中間テーブルというものを作ります。中間テーブルは両方のテーブルの id
がわかるように student_id
, class_id
のようなカラムを持ちます。
※ 中間テーブルもLaravelのMigrationで作成する必要があります。

これによって、例えば students
テーブルの1番の学生が受講している授業は、 classes
テーブルの1番だということがわかります。
また classes
テーブルの1番の授業は、 students
テーブルの1番、2番、3番の学生が受講していることがわかります。
使用するモデルの作成
Student
モデルと Class
モデルを作成します。
$ php artisan make:model Student
$ php artisan make:model Class
コマンドを実行したら app
ディレクトリ配下に Student.php
と Class.php
が作成されていればOKです👍
StudentモデルにClassモデルとのリレーションを定義する
Student
モデルにはbelongsToMany
メソッドを利用して、 Class
モデルとのリレーションを表す classes
メソッドを実装できます。(1つの Student
に対して複数の Class
が関係しているので、メソッド名は複数形です)
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Student extends Model
{
public function classes()
{
return $this->belongsToMany('App\Class');
}
}
多対多の関係を定義すると自動的に中間テーブルは2つのモデルがアルファベット順になっているものと判断されます。今回の場合は class_student
テーブルです。
中間テーブルがアルファベット順ではない、または全然別の名前の場合、 belongsToMany
メソッドの第二引数に中間テーブル名を記述してください。
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Student extends Model
{
public function classes()
{
// 中間テーブルが student_class の場合
return $this->belongsToMany('App\Class', 'student_class');
}
}
また中間テーブルに存在するカラム名がモデル名と異なる場合、belongsToMany
メソッドの第三引数、第四引数に指定することができます。第三引数にはリレーションを定義しているモデルを判別するカラム、第四引数にはリレーション先のデータを判別するカラムを指定します。
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Student extends Model
{
public function classes()
{
// 中間テーブルのカラムがstudent_idとclass_idの場合
// Studentモデルに実装されているため、第三引数はStudentモデルを判別するカラムを指定
return $this->belongsToMany('App\Class', 'student_class', 'student_id', 'class_id');
}
}
リレーションを利用する
Model同士のリレーションの定義ができたら、コントローラーとbladeでどのように利用するのかをみていきましょう。
Studentモデルに紐づいたClassをコントローラーで扱う
今回はControllerの中で利用することを想定して、以下のような StudentsController
と indexアクション
を作成しました。
※ Student
モデルを利用するためにファイル上部で use App\Student;
と書かれていることを確認してください。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Student;
class StudentsController extends Controller
{
public function index()
{
//
}
}
多対多のリレーションですが、1つのデータに対して、複数のデータが紐づいていることを表すことに変わりありません。まずはStudent
モデルを使ってデータを1つ見つけます。以下の例では id = 1
のデータを取得します。
public function index()
{
$student = Student::find(1);
}
※ モデルをつかったデータ取得方法はこちらも記事を参考にしてください。
Laravel モデルの作成とデータ取得
Student
モデルが1つ見つかると紐づく Class
モデルが見つかります。先ほど Student
モデルで belongsToMany
メソッドを使って定義した関数を利用することができます。
public function index()
{
// id = 1のデータを取得
$student = Student::find(1);
// $studentに紐づくClassをCollectionとして取得
$classes = $student->classes;
// $classesはCollectionなのでループができる
foreach ($classes as $class) {
//
}
}
これでコントローラーでモデルのリレーションを使ったデータ取得ができます。
Studentモデルに紐づいたClassをbladeで扱う
例えば StudentsController
の indexアクション
が以下のような実装だったとします。
public function index()
{
$student = Student::find(1);
return view('home', ['student' => $student]);
}
id = 1
の Student
モデルを取得して、 home.blade.php
というviewファイルを返しています。
bladeファイルで $student
に紐づいている Class
モデルを利用するにはどうすればいいでしょうか。コントローラーと同じく、 先ほど Student
モデルで belongsToMany
メソッドを使って定義した関数を利用することができます。
以下の例では仮に Student
モデルは name属性
、Class
モデルにも name属性
を持っているものとします。
{{-- $studentのname属性を表示します --}}
<p>{{ $student->name }}</p>
{{-- $studentに紐づくClassモデルをCollectionとして取得し、かつname属性を表示します --}}
@foreach($student->classes as $class)
<p>{{ $class->name }}</p>
@endforeach
※ $student
に紐づくクラスはCollectionとして取得するのでループを利用することに注意
※ 個人的にはbladeで $student->classes
のように書くのではなく、コントローラーで変数に定義してから、bladeに渡してあげた方が読みやすいと思います。
これでbladeでモデルのリレーションを使ったデータ取得、表示ができます。
逆のリレーションを定義する
今まで Student
モデルから紐づいている Class
モデルを取得する方法をみてきましたが、逆に Class
モデルから紐づいている1つの Student
モデルを取得する方法をみていきます。
belongsToMany
メソッドを利用したリレーションの逆を表現する時には同じく belongsToMany
メソッドを利用します。Class
モデルに以下のように students
メソッドを実装してください。(1つの Class
に対して複数の Student
が関係しているので、メソッド名は複数形です)
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Class extends Model
{
public function students()
{
return $this->belongsToMany('App\Student');
}
}
こちらも同じく中間テーブル名、それぞれを表すカラム名を第二引数、第三引数、第四引数で指定できます。
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Class extends Model
{
public function students()
{
// 中間テーブルが student_class の場合
// 中間テーブルのカラムがstudent_idとclass_idの場合
// Classモデルに実装されているため、第三引数はClassモデルを判別するカラムを指定
return $this->belongsToMany('App\Student', 'student_class', 'class_id', 'student_id');
}
}
リレーションの利用の仕方も今までと同じです。コントローラーでもbladeでも Class
モデルに紐づいた Student
モデルを利用することができます。
※ Class
モデルを利用するためにファイル上部で use App\Class;
と書かれていることを確認してください。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Class;
class ClassesController extends Controller
{
public function index()
{
// id = 1のデータを取得
$class = Class::find(1);
// $classに紐づくPostモデルを取得
$students = $class->students;
return view('home', ['students' => $students]);
}
}
{{-- $classのname属性を表示します --}}
<p>{{ $class->name }}</p>
{{-- $classに紐づくStudentモデルを取得し、かつname属性を表示します --}}
@foreach($class->students as $student)
<p>{{ $student->name }}</p>
@endforeach
まとめ
データベースのテーブルの多くは他のテーブルと関係性を持ちます。テーブル同士の関係性をEloquent Modelを使えば簡単に定義することができます。
今回はモデルを使った関係性の中でも多対多のリレーションについて定義と実際の利用方法をみてきました。
多対多の関係の場合、2つのテーブルとは別に中間テーブルというものを作ります。中間テーブルは両方のテーブルの id
がわかるように student_id
, class_id
のようなカラムを持ちます。
リレーション(関係性)を定義する時には各モデルに belongsToMany
メソッドを利用して実装します。
コントローラーとbladeで利用する時にはモデルに実装した関数を使ってデータ取得をします。