Eloquentはとても簡単にリレーションを操作できるようになっています。よくある1対多のリレーションも非常に短いコードで操作できるのでとても便利です。

今回は一人のユーザーが複数のポストを持っているというリレーションを実際に書いていきます。

環境

  • Laravel 5.4.23
  • MySQL 5.7.16 (InnoDB)

テーブル

まずはテーブル設計です。ユーザーモデルが1、ポストモデルが多に相当します。

ここで外部キーの設定が必要になります。日本語ドキュメントではこう書かれています。

Eloquentは、Commentモデルに対する外部キーを自動的に決めることを心に留めてください。規約によりEloquentは、自分自身のモデル名の「スネークケース」に_idのサフィックスをつけた名前と想定します。ですから今回の例でEloquentは、Commentモデルの外部キーをpost_idであると想定します。

今回は、postテーブルにuser_idというカラムがあればOKということです。ユーザーモデルはすでにあるのでポストモデルを作成しましょう。

$ php artisan make:model Post -m

これでポストモデルとマイグレーションが作成されました。

その他のカラムも設定したマイグレーションが以下になります。

usersテーブル

postsテーブル

postsテーブルにはタイトルと内容のカラムを定義しました。

また、データベースレベルで外部キー制約を定義しましょう。

$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');

これは、user_idusersテーブルのidカラムを参照するという意味です。onDelete()は参照先のレコードが削除された時の挙動を定義します。cascadeは参照先が削除されると同時に削除されるというものです。今回の場合の参照先はusersテーブルのレコードなので、あるユーザーが削除されるとそのユーザーに紐づくポストも削除されることになります。その他、restrictset nullno actionがありますので調べるといいかもしれません。

ついでにシーダーで適当にデータを入れておきましょう。横着してひとつのファイルに全て書いています。

では、実際にマイグレーションとシーダーを走らせましょう。

$ php artisan migrate --seed

エラーがなければ成功です。

usersテーブルとpostsテーブルは以下のようになるはずです。

usersテーブル

postsテーブル

モデル

次に本題のリレーションの定義です。

まずは一人のユーザーが多くのポストを持つリレーションです。

初期からあるユーザーモデルには余計なものまでありますが、重要なのは新しく追加したposts()です。

そのposts()hasMeny()を返すようにします。引数にはポストモデルを指定します。

リレーションはこれで終わりです。

ルーティングとコントローラーとビュー

複数のポストモデルに実際にアクセスしましょう。

適当にルーティングとコントローラーとビューを書きます。※本当に適当なんで参考にしないように。

[ルーティング]
特定のユーザーのポストを表示するためにuser/1のようなURLにします。

[コントローラー]
上のURLの数字はusersテーブルのidで、そのユーザーが持つポストモデルを取得しています。Eloquentは動的プロパティを提供していますので、先ほどユーザーモデルで定義したposts()は以下のようにして書くことができます。

[ビュー]
取得したポストモデルをただループして表示しているだけです。

ローカルサーバーを立ち上げて、localhost:8000/user/1にアクセスすると5件のリストが表示されていると思います。また、localhost:8000/user/2でも同様に5件表示されますが、表示内容は違います。それぞれのユーザーが持つポストモデルの内容になっていると思います。

ちなみに、この時に走るSQLは次の2つです。

select * from `users` where `users`.`id` = '2' limit 1
select * from `posts` where `posts`.`user_id` = '2' and `posts`.`user_id` is not null

1つ目のSQLは特定のユーザーを、2つ目のSQLはそのユーザーが持つポストを取得しています。

逆のリレーション

最後に逆のリレーションについてです。だいたい同じように記述するんでさらっといきますが、例のごとく、ルーティング、コントローラー、ビューは適当です。

まずはモデルからです。先ほどのリレーションはユーザーが持つポストモデルでした。その逆なので、あるポストを持っているユーザーモデルを取得します。

使うのはbelongsTo()です。

[ルーティング]
特定のポストに対するユーザーモデルを表示するためにpost/1のようなURLにします。

[コントローラー]
idでポストを探し、そのポストモデルを持つユーザーモデルを取得しているだけです。

[ビュー
ただ名前を表示しているだけです。

例えばlocalhost:8000/post/2にアクセスした時に走るSQLは次の2つです。

select * from `posts` where `posts`.`id` = '2' limit 1
select * from `users` where `users`.`id` = '1' limit 1

まとめ

1対多のリレーションは使う場面がかなり多いと思います。とても簡単に使えるのでうまく使っていきましょう。