概要
本記事は、PHPフレームワークLaravel入門 第2版で学習している中の疑問・つまづきの備忘録です。
今回はhasOneメソッドで関連付けられるテーブルの項目名の決まり方について、疑問を調べたのでまとめました。
環境
- Docker
- Laravel Sail
- MySQL8.0
今回の疑問
なぜ以下のようにhasOneメソッドを使用することで、Personモデル(peopleテーブル)のidとBoardモデルクラス(boardsテーブル)のperson_idが結びつけられるのか疑問に思いました。
このメソッドにはidやperson_idという情報は渡していません。
public function board()
{
return $this->hasOne('App\Models\Board');
}
ちなみに、公式ドキュメントには以下のような記載があります。
idとxxx_idが関連付けられることは分かりますが、それがなぜかは不明なので調べてみました。
Eloquentは、親モデル名に基づきリレーションの外部キーを決定します。この場合、Phoneモデルは自動的にuser_id外部キーを持っているとみなします。
Laravel 8.x Eloquent:リレーション
テーブルの情報
peopleテーブル
mysql> SHOW CREATE TABLE people;
| Table | Create Table |
+--------+----------------------------------------------------+
| people | CREATE TABLE `people` (
`id` int unsigned NOT NULL AUTO_INCREMENT, ///////////////////ここと
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`mail` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`age` int NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=72824 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
boardsテーブル
mysql> SHOW CREATE TABLE boards;
| Table | Create Table |
+--------+----------------------------------------------------+
| boards | CREATE TABLE `boards` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`person_id` int NOT NULL, /////////////////////////////ここが関連付けられている
`title` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`message` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci |
hasOneメソッドの動きを追ってみた
Person.phpで使用しているhasOneメソッドの呼び出し先を確認していきます。
hasOneメソッドは、HasRelationships.phpで以下のように宣言されています。
///一部抜粋
public function hasOne($related, $foreignKey = null, $localKey = null)
{
$instance = $this->newRelatedInstance($related);
$foreignKey = $foreignKey ?: $this->getForeignKey();
$localKey = $localKey ?: $this->getKeyName();
return $this->newHasOne($instance->newQuery(), $this, $instance->getTable().'.'.$foreignKey, $localKey);
}
ここで注目するのは引数です。
-
$related
・・・・どのモデルと関連付けるかを指定。今回は'App\Models\Board'を渡している。 -
$foreignKey
・・・・$related
で指定したモデルのどのカラムと$localKey
を関連付けるかを指定。デフォルトではnull。 -
$localKey
・・・・$foreignKey
と関連付けられる、このモデルのカラムを指定。デフォルトではnull。
今回、hasOneメソッドには$related
しか引数を渡していないので、$this->getForeignKey()
の戻り値が$foreignKey
に格納されます。
getoForeignKeyメソッドの宣言は以下のようになっています。
///一部抜粋
public function getForeignKey()
{
return Str::snake(class_basename($this)).'_'.$this->getKeyName();
}
Str::snakeは、引数の値をスネークケースにして返します。
Str::snakeメソッドは文字列をスネークケース(snake_case)に変換します。
ここでの$this
はPersonのインスタンスなのでclass_basename関数はPersonという文字列を返します。
class_basename関数は、指定クラスの名前から名前空間を取り除いて返します。
Laravel 8.x ヘルパ
では、getKeyNameメソッドはどうでしょうか。
///一部抜粋
public function getKeyName()
{
return $this->primaryKey;
}
ここでも$this
はPersonのインスタンスなので、Personモデル(peopleテーブル)のプライマリキーであるidを返しています。
これらのことより、$foreignKey
の値は「person_id」となります。
次に$localKey
ですが、これはPersonモデル(peopleテーブル)のプライマリキーなので「id」となります。
したがって、Personモデルのidと、Boardモデルのperson_idが関連付けられます。
まとめ
hasOneメソッドで関連付けられるテーブルの項目名は、hasOneメソッドを遡った先にあるgetForeignKeyメソッドおよびgetKeyNameメソッドによって決まっている。
基本的には「id」と「モデル名_id」が関連付けられる。
参考文献
PHPフレームワークLaravel入門 第2版
Laravel 8.x Eloquent:リレーション
Laravel 8.x ヘルパ