はじめに
以前に書いた記事がいくつかLGMTいただいていたので、
こちらに現在自分の知識での最善のリレーションを記述しておきます。
親子が1対1の関係
テーブル構成
[親] users
テーブル
色々な子テーブルを持っています。
もちろん、次に登場する user_ages
テーブルもです。
id | name |
---|---|
1 | 田中太郎 |
2 | 山田花子 |
3 | 佐藤一郎 |
[子] user_ages
テーブル
ユーザーの年齢を管理するテーブル。
users
テーブルとのレコードは1対1の関係。
id | user_id | age |
---|---|---|
1 | 1 | 23 |
2 | 2 | 34 |
3 | 3 | 55 |
Model側の実装
親(idを持つ)から子(user_idを持つ)を参照するには、 hasOne
を使います。
use App\Models\UserAge;
public function age() {
return $this->hasOne(UserAge::class);
}
子(user_idを持つ)から親(idを持つ)を参照するには、 belongsTo
を使います。
use App\Models\User;
public function user() {
return $this->belongsTo(User::class);
}
準備しておけば下記のように記述できます。
use App\Models\{ User, UserAge };
$user = User::find(1);
echo $user->age->age; // 23
$age = UserAge::find(3);
echo $age->user->name; // 佐藤一郎
親子が1対多の関係
テーブル構成
[親] users
テーブル
再登場した users
テーブル。
次は1ユーザーが複数の 本
を持つことができる、 user_books
テーブルを参照します。
id | name |
---|---|
1 | 田中太郎 |
2 | 山田花子 |
3 | 佐藤一郎 |
[子] user_books
テーブル
ユーザーの持っている本のタイトルを管理するテーブルです。
エルマーのぼうけん シリーズ
が人気のようです。
同じ user_id
のレコードが複数行できる可能性があります。
id | user_id | name |
---|---|---|
1 | 1 | エルマーのぼうけん |
2 | 1 | 週刊少年ジャンプ+ |
3 | 3 | エルマーのぼうけん |
4 | 3 | エルマーとりゅう |
5 | 3 | エルマーと16ぴきのりゅう |
Model側の実装
親(idを持つ)から複数の子(user_idを持つ)を参照するには、 hasMany
を使います。
use App\Models\UserBook;
public function books() {
return $this->hasMany(UserBook::class);
}
子(user_idを持つ)から親(idを持つ)を参照するには、先ほどと同じく belongsTo
を使います。
use App\Models\User;
public function user() {
return $this->belongsTo(User::class);
}
準備しておけば下記のように記述できます。
use App\Models\{ User, UserBook };
// 田中太郎(ID:1)さんの持つ本の一覧を表示してみましょう。
$user = User::find(1);
foreach ($user->books as $book) {
echo $book->name . PHP_EOL;
}
// エルマーのぼうけん
// 週刊少年ジャンプ+
// エルマーとりゅう(ID:4)は誰の持ち物か表示してみましょう。
$book = UserBook::find(4);
echo $book->user->name; // 佐藤一郎
多対多の関係
テーブル構成
users
テーブル
先程は「親子」と言っていましたが、多対多の関係では親子の縁は切れました。
なぜなら、どちらも親になる可能性があるからです。
id | name |
---|---|
1 | 田中太郎 |
2 | 山田花子 |
3 | 佐藤一郎 |
books
テーブル
本のタイトルをそのまま持つと、本のタイトルが変わったときに一気にレコードを更新しないといけません。
毎回、複数のレコードを更新するのはめんどくさいですよね?
なら、本
は books
テーブルで管理しましょう。
id | name |
---|---|
1 | 週刊少年ジャンプ+ |
2 | おそ松さん |
3 | エルマーのぼうけん |
4 | エルマーとりゅう |
5 | エルマーと16ぴきのりゅう |
book_user
テーブル
ユーザー
と 本
を結びつける中間テーブルです。
なぜ book_user[s]
じゃないのかって?
Laravelでは中間テーブルの名前は[複数形にしないルール](### 基本的なLaravelにおけるテーブルの命名規則)になっています。
ちなみに、 users
テーブルと books
テーブルの中間テーブル名は、
アルファベットの早い方が先頭になります。
したがって、 book_user
テーブルとなります。
id | user_id | book_id |
---|---|---|
1 | 1 | 3 |
2 | 1 | 1 |
3 | 3 | 3 |
4 | 3 | 4 |
5 | 3 | 5 |
Model側の実装
users
テーブルから book_user
という中間テーブルを経由して books
データを取得する場合は、 belongsToMany
を使用します。
use App\Models\Book;
public function books() {
return $this->belongsToMany(Book::class);
}
books
テーブルから book_user
という中間テーブルを経由して users
データを取得する場合も、 belongsToMany
を使用します。
use App\Models\User;
public function users() {
return $this->belongsToMany(User::class);
}
準備しておけば下記のように記述できます。
use App\Models\{ User, Book };
// 佐藤一郎(3)さんの持つ本の一覧を表示してみましょう。
$user = User::find(3);
foreach ($user->books as $book) {
echo $book->name . PHP_EOL;
}
// エルマーのぼうけん
// エルマーとりゅう
// エルマーと16ぴきのりゅう
// エルマーのぼうけん(3)を持っている人一覧を表示してみましょう。
$book = Book::find(3);
foreach ($book->users as $user) {
echo $user->name . PHP_EOL;
}
// 田中太郎
// 佐藤一郎
また、 山田花子
さんに おそ松さん
を持たせたい場合は、
下記のように attach
メソッドを使えば追加できます。
$user = User::find(2); // 山田花子
$user->books()->attach(2); // おそ松さん(2)を追加します。
その他、覚えておくと良いこと
基本的なLaravelにおけるテーブルの命名規則
LaravelでDBを使用する場合のテーブル名は、マスタ・データ問わず基本的に 複数形
になります。
また、中間テーブルのみ 単数形
となります。
$user->age
と $user->age()
の違い
$user->age
はSQLを実行して、その結果を App\Models\UserAge
で返します。
$user->age()
はSQLが実行されず、Illuminate\Database\Eloquent\Relations\HasOne
のようなリレーションオブジェクトを返します。
下記のように、続けて HasOne
オブジェクトのメソッドが利用できます。
if ($user->age()->exists()) {
// \App\Models\UserAge モデルが存在する
} else {
// \App\Models\UserAge モデルが存在しない
}
$user->books()
$user->books()
は、
1対多の関係の場合は Illuminate\Database\Eloquent\Relations\HasMany
多対多の関係の場合は Illuminate\Database\Eloquent\Relations\BelongsToMany
を返します。
Illuminate\Database\Eloquent\Relations\HasMany
新しくレコードを追加したい場合は、下記のように実装します。
$user->books()->create(['name' => '週刊少年ジャンプ+']);
Illuminate\Database\Eloquent\Relations\BelongsToMany
新しく本を紐付けしたい場合は下記のように実装します。
$user->books()->attach([1, 2, 3]); // books テーブルのID
// 新しく books.id が 1, 2, 3 のものが追加されます。
また、本の紐付けを同期したい場合は下記のように実装します。
$user->books()->sync([1, 2, 3]); // books テーブルのID
// books.id が 1, 2, 3 のものが追加され、それ以外のidは削除されます。
最後に
社内用です。
ソースを書きながら記事を書いたわけではないので、
ところどころ動かしてみると間違ってる可能性があるので、
その場合は都度修正します…。