Laravelでモデルのリレーションのメモ
モデルのリレーションとは、複数のテーブルを組み合わせて利用することです。
例えば以下のようなテーブルがあるとします。
◎messagesテーブル(従テーブル)
参照用の外部キーを持つ側を従テーブルといいます。
外部キーは主テーブル名の単数_idにする必要があります。
別の名前をつけたい場合は、リレーションの設定をする際に指定が必要です(後述)。
今回の例でいくと、テーブル名がusers
なので、外部キーのカラム名はuser_id
になります。
id | message | user_id |
---|---|---|
1 | こんにちは | 2 |
2 | こんばんは | 7 |
◎usersテーブル(主テーブル)
外部キーを持たいない参照される側のテーブルを主テーブルといいます。
id | name | age | |
---|---|---|---|
2 | 佐藤一郎 | sato@sample.com | 30 |
7 | 鈴木次郎 | jsuzuki@sample.com | 40 |
messagesテーブルに、メッセージを書いたユーザーidを入れておくことで、ユーザーの詳細情報をusersテーブルから取得することができます。
ユーザーの関連したメッセージを表示してみる
usersテーブルと、messagesテーブルをリレーションして、ユーザーに関連したメッセージを表示してみます。
Controller
/app/Http/Controllers/UserController.php
<?php namespace App\Http\Controllers; use App\User; use Illuminate\Http\Request; class UserController extends Controller { public function index(Request $request) { $items = User::all(); return view('user.index', ['items' => $items]); } }
Model
User
/app/User.php
外部キーを持たない、Userテーブル(主テーブル)に、従テーブルを取得する為の定義を追加します。
1対1の関連づけの場合はhasOne
を利用します。
<?php namespace App; use Illuminate\Database\Eloquent\Model; class User extends Model { protected $guarded = array('id'); public function message(){ return $this->hasOne('App\Message'); } }
以下のようなメソッドを追加します。
hasOneは引数に指定したモデルへの関連付けを設定し、関連あるモデルのインスタンスを取得できるようになります。
public function message(){
return $this->hasOne('App\Message');
}
上のほうで、従テーブルの外部キーは主テーブル名の単数_idにする必要があると書きましたが、外部キーを指定することもできます。
ちょっとややこしいのですが、
第二引数に外部キーのカラム名(foreignKey)を指定し、第三引数にローカルキー(localKey)を指定します。これでusersテーブルのlocal_keyとmessagesテーブルのforeign_keyをリレーションします。
$this->hasOne('App\Message', 'foreign_key(外部キーのカラム名)', 'local_key(ローカルキーのカラム名)');
Message
/app/Message.php
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Message extends Model { protected $guarded = array('id'); public function getData() { return $this->message; } }
View
/resources/views/user/index.blade.php
Userモデルで定義したmessage()
はプロパティとしてアクセスすることができます。
プロパティとしてアクセスした、message
にはMessageモデルのインスタンが入っているので、インスタンスのメソッドも自由に利用することができます。
<table> <tr> <th>name</th> <th>mail</th> <th>age</th> <th>message</th> </tr> @foreach ($items as $item) <tr> <td>{{$item->name}}</td> <td>{{$item->mail}}</td> <td>{{$item->age}}</td> <td>{{$item->message->getData()}}</td> </tr> @endforeach </table>
表示
結果
name | age | message | |
---|---|---|---|
佐藤一郎 | sato@sample.com | 30 | こんにちは |
鈴木次郎 | jsuzuki@sample.com | 40 | こんばんは |
hasMany
hasOne
は1だけの情報を取得しました。
複数の関連情報がある場合はhasMany
を利用します。
以下のような従テーブルがあるとします。
id | message | user_id |
---|---|---|
1 | こんにちは | 2 |
2 | さようなら | 2 |
3 | こんばんは | 7 |
4 | はじめまして | 7 |
Model
<?php namespace App; use Illuminate\Database\Eloquent\Model; class User extends Model { protected $guarded = array('id'); public function messages(){ return $this->hasMany('App\Message'); } }
view
<table> <tr> <th>name</th> <th>mail</th> <th>age</th> <th>message</th> </tr> @foreach ($items as $item) <tr> <td>{{$item->name}}</td> <td>{{$item->mail}}</td> <td>{{$item->age}}</td> <td> <ul> @foreach($item->messages as $obj) <li>{{$obj->getData()}}</li> @endforeach </ul> </td> </tr> @endforeach </table>
結果
name | age | message | |
---|---|---|---|
佐藤一郎 | sato@sample.com | 30 | こんにちは さようなら |
鈴木次郎 | jsuzuki@sample.com | 40 | こんばんは はじめまして |
belongsTo
hasOneやhasManyは主テーブルから外部キー(user_id)が設定されている従テーブルの情報を取得していました。
belongsTo
は逆に従テーブルから主テーブルの情報を取得します。
belongsTo
は1つ(この場合は該当のuser情報)のデータを取得します。
Model
Message
belongsTo
でUserモデルと結合します。
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Message extends Model { protected $guarded = array('id'); public function user(){ return $this->belongsTo('App\User'); } }
User
getDataメソッドを用意します。
<?php namespace App; use Illuminate\Database\Eloquent\Model; class User extends Model { protected $guarded = array('id'); public function getData(){ return $this->name; } }
Controller
リレーションをとることで、userモデルのインスタンスを取得できるので、userモデルのgetDataメソッドを利用できます。
<table> <tr> <th>user_id</th> <th>message</th> <th>user</th> </tr> @foreach ($items as $item) <tr> <td>{{$item->user_id}}</td> <td>{{$item->message}}</td> <td>{{$item->user->getData()}}</td> </tr> @endforeach </table>
表示
user_id | message | user |
---|---|---|
2 | こんにちは | 佐藤一郎 |
2 | さようなら | 佐藤一郎 |
7 | こんばんは | 鈴木次郎 |
7 | はじめまして | 鈴木次郎 |
その他
指定のリレーション値を持っているもののみ取得
モデル::has(リレーション名)->get();
例
class UserController extends Controller { public function index(Request $request) { $items = User::has('message')->get(); return view('user.index', ['items' => $items]); } }
指定のリレーションの値をもたないもののみ取得
モデル::doesntHave(リレーション名)->get();
例
class UserController extends Controller { public function index(Request $request) { $items = User::doesntHave('message')->get(); return view('user.index', ['items' => $items]); } }