【Laravel6】多対多のリレーションと実装(ホテル予約システム5)
多対多について
予約(Reservation)と部屋(Room)はお互いが相手に対して多の関係が成立する、
- ・一つの予約には、たとえば団体客の場合などは複数の部屋を予約する。
- ・一つの部屋には、時間を変えて複数の予約が行われる。
この多対多という関係はデータベース上に直接表現することは推奨されません。表現できなくはないのですが、効率が悪いデータベースになってしまいます。
興味ある人はこれ読んでください。
そういったデータベースの無駄を防ぐために、
参考:Laravel6.x Eloquent: リレーション 多対多
多対多の実装
今回は、予約と部屋の間にできるリレーションになるので、Reserveモデルに実装していきます。
引数として、前から順番に下記の内容を書きます。
- 1.相手のモデル
- 2.中間テーブルの名前、
- 3.中間テーブル上の相手のモデルの外部キー
- 4.中間テーブル上の自分のモデルの外部キー
なお、これを実装するまでに、
Reserve.php
class Reserve extends Model { protected $primaryKey = 'reserve_id'; // 前回のguestとの1対多のリレーション public function guest() { return $this->belongsTo('App\Guest','guest_id','guest_id'); } // 今回のroomとの多対多のリレーション public function rooms() { // belongsToMany(相手のモデル、中間テーブルの名前、中間テーブル上の自分のモデルの外部キー、中間テーブル上の相手のモデルの外部キー) return $this->belongsToMany('App\Room','reserve_room','reserve_id','room_id') }
Viewでこのroom()メソッドを利用してみましょう。
Reserve/index.blade.php
@extends('layouts.hotel') @section('body') <table> <th>予約ID</th><th>お名前</th><th>ご住所</th><th>電話番号</th><th>人数</th><th>チェックイン日</th><th>チェックアウト日</th> <th>料金</th> @foreach($items as $item) <tr> <!-- 略 --> <!-- roomメソッドのbelongToManyでroomモデルとその中間テーブルreserve_roomテーブルにアクセス --> <td>{{$item->rooms}}</td> </tr> @endforeach </table> @endsection
$item->roomで表示される内容の例
// 中間テーブルの1つ目のデータと対応するRoomsテーブル [{"room_id":1,"room_type_id":1,"room_number":"101","created_at":null,"updated_at":null, "pivot":{"reserve_id":1,"room_id":1}}, // 中間テーブルの2つ目のデータと対応するRoomsテーブル {"room_id":1,"room_type_id":1,"room_number":"101","created_at":null,"updated_at":null, "pivot":{"reserve_id":1,"room_id":1}}]
roomメソッドによるリレーションにより、データベースからRoomsテーブルの情報を取得できたことが分かります。
ここで利用したメソッドはbelongsToitem->rooms
で取得できるデータは
なので、配列を表す[ ]
が使われています。
とりあえず
<td>{{$item->rooms->first()}}</td>
$item->rooms->first()で表示される内容の例
// 中間テーブルの1つ目のデータと対応するRoomsテーブルのレコード {"room_id":1,"room_type_id":1,"room_number":"101","created_at":null,"updated_at":null, "pivot":{"reserve_id":1,"room_id":1}}
これからさらに対応するRoomsテーブルのレコードを取得するには、
<td>{{$item->rooms->first()->room_number}}</td>
としましょう。
中間テーブルのデータを取得する。
中間テーブルのデータはこのpivotプロパティを介して取得できます。
<td>{{$item->rooms->first()->pivot}}</td>
$item->rooms->first()->pivot で表示される内容の例
// 中間テーブルの1つ目のデータと対応するRoomsテーブルのレコード {"reserve_id":1,"room_id":1}
ただし、このままでは対応する外部キーの値しか表示されません。
中間テーブルのそれ以外のカラムも表示するには、モデルのbelongsToMany
のあとに、withPivot()
を追加します。
Reserve.php
public function rooms() { return $this->belongsToMany('App\Room','reserve_room','room_id','reserve_id') ->withPivot('days','price'); }
修正後の$item->rooms->first()->pivot で表示される内容の例
// 中間テーブルの1つ目のデータと対応するRoomsテーブルのレコード {"reserve_id":1,"room_id":1,"days":"2021-10-23","price":8000}}