1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Laravel,MySQL】 hasOneメソッドで関連付けられるテーブルの項目名はどのように決まっているのか

Last updated at Posted at 2022-01-18

概要

本記事は、PHPフレームワークLaravel入門 第2版で学習している中の疑問・つまづきの備忘録です。
今回はhasOneメソッドで関連付けられるテーブルの項目名の決まり方について、疑問を調べたのでまとめました。

環境

  • Docker
  • Laravel Sail
  • MySQL8.0

今回の疑問

なぜ以下のようにhasOneメソッドを使用することで、Personモデル(peopleテーブル)のidとBoardモデルクラス(boardsテーブル)のperson_idが結びつけられるのか疑問に思いました。
このメソッドにはidやperson_idという情報は渡していません。

Person.php
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で以下のように宣言されています。

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メソッドの宣言は以下のようになっています。

Model.php
    ///一部抜粋
    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メソッドはどうでしょうか。

Model.php
    ///一部抜粋
    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 ヘルパ

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?