LaravelのEloqunetでリレーションを作る方法をまとめてみました。
Laravelのバージョン8で挙動を確認しています。
モデルから関連するモデルにリレーションを作成しておくと、簡単に関連先のデータを取得することが可能です。
複雑な条件などが不要な場合は、クエリビルダーでJoinを使わずにこちらで取得すると良いかと思います。
公式のこちらの内容をわかりやすくしてみました。
今回はこちらの中から、hasOneとhasManyをピックアップして記事にしています。
hasOne, hasMany検証用のテーブル構成
今回リレーションを試してみるために作成したテーブル構成は下記です。
掲示板のアプリケーションを考えたときのテーブルになります。
Boardsが掲示板で、Messagesが返信です。
Boardsモデル(テーブル名:boards)
項目名 | 型 |
---|---|
id | bigint(20) |
title | varchar(255) |
user_name | varchar(255) |
content | varchar(255) |
Messagesモデル(テーブル名:messages)
項目名 | 型 |
---|---|
id | bigint(20) |
board_id | bigint(20) |
user_name | varchar(255) |
message | varchar(255) |
1対1でリレーションする(hasOneを使用する)
モデルにhasOne
を書くことで、引数で渡したクラスのモデルを1つだけ返してくれます。
class Board extends Model
{
// --- 省略 ---
public function message()
{
return $this->hasOne(Message::class);
}
}
引数で渡したモデルには、呼び出し元のid
を持っている必要があります。
今回の例で言うと、board_id
をmessages
が持っているため取得できます。
呼び出し元のモデルのid
カラムと呼び出し先の[呼び出し元のテーブル名 + ‘_id’]カラムがリレーションで使うカラムとして自動的に選択されます。
hasOneで、ひとつのデータを取得する
リレーションを作った先のモデルを取得する時は、親のモデルをひとつ取得し、そこからメソッドを呼びます。
下記のように書くことで、Board
からMessage
をひとつ取得します。
Board::find(1)->message
ddで確認すると、このように表示されます。
関連するmessages
テーブルのモデルが1件返ってきているのが確認できました。
App\Models\Message {#1010 ▼
#fillable: array:3 [▶]
#connection: "mysql"
#table: "messages"
#primaryKey: "id"
#keyType: "int"
----- 省略 -----
}
リレーション先のデータが存在しない場合は結果がnull
になります。
1対Nでリレーションする(hasManyを使用する)
モデルにhasMany
を書くことで、引数で渡したクラスのモデルを複数返してくれます。
class Board extends Model
{
// --- 省略 ---
public function messages()
{
return $this->hasMany(Message::class);
}
}
hasOne
と同じで、messagesがboard_id
を持っているため、このように書くことが可能です。
hasManyで、複数のデータを取得する
使用するときは、下記のように呼び出すと複数取得することができます。
Board::find(1)->messages
取得した結果を出力すると、下記のようにコレクションの中にモデルが複数入って返ってきていることが確認できます。
Illuminate\Database\Eloquent\Collection {#1010 ▼
#items: array:2 [▼
0 => App\Models\Message {#1011 ▶}
1 => App\Models\Message {#1220 ▶}
]
}
hasOne, hasManyでキーが違う場合はどうする?
Eloquentでは、呼び出し元のテーブル名に基づいて、キーが決定します。
今回の例で言うとBoard
モデルからMessage
を呼び出しているので、messages
テーブルにはboard_id
が必要ということです。
Eloquentはboard_id
と呼び出し元のboards
テーブルのid
を結合して取得してきます。
このデフォルトのキーがリレーションしたいキーではない場合は、モデルを呼び出す時に引数として渡すことができます。
phones
テーブルとusers
テーブルがあるとします。
Usersモデル(テーブル名:users)
項目名 | 型 |
---|---|
id | bigint(20) |
user_number | bigint(20) |
name | string |
string |
Phonesモデル(テーブル名:phones)
項目名 | 型 |
---|---|
id | bigint(20) |
user_number | bigint(20) |
phone_number | string |
phones
テーブルにはuser_id
の代わりに、user_number
があるとします。
Userモデルから呼び出す場合は、下記のようにリレーションするときのキーを指定することができます。
public function phone()
{
return $this->hasOne(Phone::class, 'user_number');
}
こうすると、呼び出し先のphones
テーブルのuser_number
と呼び出し元のusers
テーブルのid
でリレーションが作れます。
もし、users
テーブルのリレーションしたいキーがid
じゃない場合は、下記のように渡すことができます。
こうすると、呼び出し先のphones
テーブルのuser_numberと呼び出し元のusers
テーブルのuser_numberをリレーションすることになります。
public function phone()
{
return $this->hasOne(Phone::class, 'user_number', 'user_number');
}
ここではhasOne
を例にしていますが、hasMany
の場合も同じように渡すことができます。
つまりhasOne
の場合は下記のようになり…
$this->hasOne(Phone::class, '呼び出し先のキー', '呼び出し元のキー');
hasMany
の場合も同じですが、下記のようになります。
$this->hasMany(Phone::class, '呼び出し先のキー', '呼び出し元のキー');
おわりに
今回はEloquentのリレーションについて記載しました。
簡単にリレーションを作ることが可能なことがわかったかと思います。
気をつけるべきは、呼び出し先のテーブルに[呼び出し元のテーブル名+’_id’]で作っておかないといけませんでした。
ない場合は取得することができないので、作成するようにしてください。
また、リレーションしたいカラムが別のカラムの場合でも引数に指定することでリレーションが作れることもわかりました。
複雑な条件などがない場合はリレーションで取得して使うと良いかと思います。
コメント