はじめに
Laravelで開発中に、リレーションについて、曖昧な箇所や、なんとなく実装していた箇所ががあったため、調べ直してみました。1対1、1対多編!
開発状況(Version)
macOS Big Sur
Laravel 6系
PHP 7系
リレーションとは
Laravel ではモデルにリレーション=「関連」の設定ができるようになっています。
モデルにリレーションの設定をしておくと、簡単にリレーション先へアクセスができるようになります。
1対1の関係
1対1リレーションは、分割しなくてもよいテーブルが分割されている状態です。
Eloquentで記述する場合、どちらかを主テーブル、もう一方を従テーブルになります。
主テーブル:主キー(id)をもつテーブル
従テーブル:外部キー(〇〇_id)をもつテーブル
例えば
主テーブル(主キー):Usersテーブル
従テーブル(従キー):Videosテーブル
主テーブルから従テーブルのデータを引っ張ってくる方法
リレーションの定義
class User extends Authenticatable
{
---------抜粋-----------
//UserモデルがVideoモデルを所有している
//1対1の場合、メソッドは単数になる
public function video()
{
return $this->hasOne(Video::class);
}
---------抜粋-----------
}
※主テーブルが従テーブルをデータを引っ張ってくることができます。
hasOneとすると、オブジェクトが1個返ります。
動作確認
Tinkerを使用して、主テーブルが従テーブルを引っ張ってこれるか確認してみます。
[root@fcd514507bc6 html]# php artisan tinker
Psy Shell v0.9.12 (PHP 7.2.34 — cli) by Justin Hileman
User id:1のデータを表示
>>> App\User::find(1);
=> App\User {#3548
id: 1,
nickname: "信長のパパ",
email: "oda@oda.com",
delete_flag: "1",
created_at: null,
updated_at: null,
}
UserテーブルからVideoテーブルの情報を取得表示
※User id:1のVideoテーブルでのデータが引っ張り出せている
>>> App\User::find(1)->video;
=> Illuminate\Database\Eloquent\Collection {#3229
all: [
App\Video {#3230
id: 1,
user_id: 1,
url: "PkDfrVdCwCs",
target_id: 1,
created_at: "2022-04-03 12:38:03",
updated_at: "2022-04-03 12:38:03",
},
App\Video {#4012
id: 9,
user_id: 1,
url: "lZRNUvDOzmY",
target_id: 1,
created_at: "2022-04-03 12:38:03",
updated_at: "2022-04-03 12:38:03",
},
App\Video {#4166
id: 17,
このように、Videoメソッドをチェーンするだけで、従テーブルのデータを引っ張ってくることができます。
従テーブルから主テーブルのデータを引っ張ってくる方法
リレーションの定義
class Video extends Model
{
---------抜粋-----------
// Videoモデルが、Userモデルに所属している
//1対1のメソッドは単数になる
public function user()
{
return $this->belongsTo(User::class);
}
---------抜粋-----------
}
※従テーブルが主テーブルをデータを引っ張ってくることができます。
親モデルを呼び出すときは、「belongsTo」で定義します。
動作確認
Tinkerを使用して、従テーブルが主テーブルを引っ張ってこれるか確認してみます。
Video id:1のデータを表示
>>> App\Video::find(1);
=> App\Video {#4158
id: 1,
user_id: 1,
url: "PkDfrVdCwCs",
target_id: 1,
created_at: "2022-04-03 12:38:03",
Videoテーブルから、Video id:1のデータに所持しているUserの情報を、Userテーブルから取得表示
>>> App\Video::find(1)->user;
=> App\User {#4012
id: 1,
nickname: "信長のパパ",
email: "oda@oda.com",
delete_flag: "1",
created_at: null,
updated_at: null,
}
このように、Userメソッドをチェーンするだけで、主テーブルのデータを引っ張ってくることができます。
1対多の関係
Aテーブルのレコードは、Bテーブルの複数のレコードと関連する。
Bテーブルのレコードは、Aテーブルのレコードと最大1件のみ関連する。
1対多のリレーションは、親テーブル(1)に主キーを設けて、
それを参照する外部キーを子テーブル(多)に設ける
例えば
主テーブル(主キー):Userテーブル
従テーブル(外部キー):Videosテーブル
主テーブルから従テーブルのデータを引っ張ってくる方法
リレーションの定義
class User extends Authenticatable
{
---------抜粋-----------
//UserモデルがVideoモデルを所有している
//1対多の場合、メソッドは複数形になる
public function videos()
{
return $this->hasMany(Video::class);
}
---------抜粋-----------
}
※主テーブルが従テーブルをデータを引っ張ってくることができます。
hasManyとすると、コレクションで複数返ります。
動作確認
Tinkerを使用して、主テーブルが従テーブルを引っ張ってこれるか確認してみます。
User id:2のデータを表示
>>> App\User::find(2);
=> App\User {#4101
id: 2,
nickname: "秀吉のママ",
email: "toyo@otoyo.com",
delete_flag: "1",
created_at: null,
updated_at: null,
}
Userテーブルから、User id:2に所持しているVideoのデータを、Videosテーブルから取得表示
>>> App\User::find(2)->videos;
=> Illuminate\Database\Eloquent\Collection {#3232
all: [
App\Video {#4167
id: 2,
user_id: 2,
url: "ZSHhBm5OgrA",
target_id: 3,
created_at: "2022-04-03 12:38:03",
updated_at: "2022-04-03 12:38:03",
},
App\Video {#3548
id: 10,
user_id: 2,
url: "jZk_rwLgsC4",
target_id: 3,
created_at: "2022-04-03 12:38:03",
updated_at: "2022-04-03 12:38:03",
},
App\Video {#4168
id: 18,
user_id: 2,
url: "VvY9TEDtets",
target_id: 3,
created_at: "2022-04-03 12:38:03",
updated_at: "2022-04-03 12:38:03",
},
],
}
クエリーに条件を付け加える
クエリに条件を付け加えて、チェーンで繋ぐこともできます。
User id :2が所持している、Videoのデータのうち、Videoテーブルのid:18のデータを取得表示
>>> App\User::find(2)->videos()->where('id', '18')->first();
=> App\Video {#4174
id: 18,
user_id: 2,
url: "VvY9TEDtets",
target_id: 3,
created_at: "2022-04-03 12:38:03",
updated_at: "2022-04-03 12:38:03",
※クエリビルダとしていろんな制約をするときは、最後にレコードを取得するメソッド(get()、first())が必要になります。
従テーブルから主テーブルのデータを引っ張ってくる方法
リレーションの定義
class Video extends Model
{
---------抜粋-----------
// Videoモデルが、Userモデルに所属している
//1対多の1側のメソッドなので、単数になる
public function user()
{
return $this->belongsTo(User::class);
}
---------抜粋-----------
}
※従テーブルが主テーブルのデータを引っ張ってくることができます。
こちらも「1対1」同様、親モデルを呼び出すときは、「belongsTo」で定義します。
動作確認
Tinkerを使用して、従テーブルが主テーブルを引っ張ってこれるか確認してみます。
Videosテーブルに入っているデータで、Video id:2を所持しているUserデータを取得表示
>>> App\Video::find(2)->user;
=> App\User {#4174
id: 2,
nickname: "秀吉のママ",
email: "toyo@otoyo.com",
delete_flag: "1",
created_at: null,
updated_at: null,
}
Videosテーブルに入っているデータで、Video id:2を所持しているUserデータのnicknameだけを取得表示
>>> App\Video::find(2)->user->nickname;
=> "秀吉のママ"
最後に
業務でリレーションを修正する実装があったので、復習を込めて、記事にしてみました。しかし、相変わらず、TinkerでDBを確認する際のコマンドがうる覚えでした。。。次は、多対多をまとめてみようかな。
コメント