Laravel8 1対1 DBのリレーションを定義しよう

# 目的

- LaravelにおけるDBの1対1のリレーション定義方法をまとめる

# 実施環境

- ハードウェア環境

| 項目 | 情報 |
| --- | --- |
| OS | macOS Catalina(10.15.5) |
| ハードウェア | MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports) |
| プロセッサ | 2 GHz クアッドコアIntel Core i5 |
| メモリ | 32 GB 3733 MHz LPDDR4 |
| グラフィックス | Intel Iris Plus Graphics 1536 MB |

- ソフトウェア環境

| 項目 | 情報 | 備考 |
| --- | --- | --- |
| PHP バージョン | 7.4.8 | Homebrewを用いてこちらの方法で導入→[Mac HomebrewでPHPをインストールする](https://qiita.com/miriwo/items/cd54077aad7e139cf518) |
| Laravel バージョン | 8.6.0 | commposerを用いてこちらの方法で導入→[Mac Laravelの環境構築を行う](https://qiita.com/miriwo/items/adaaaeecae69d6392e08) |
| MySQLバージョン | 8.0.19 for osx10.13 on x86_64 | Homwbrewを用いてこちらの方法で導入→[Mac HomebrewでMySQLをインストールする](https://qiita.com/miriwo/items/ef6a064bc545fbea29d9) |

# 前提条件

- 実施環境に記載されている環境と近い環境が構築されていること。

# 前提情報

- 下記コマンドを実行してrelationアプリを作成した。

    ```terminal
    $ laravel new relation --auth
    ```
- Auth認証で使用されるusersテーブルのIDとリンクするuser_idカラムを有するphone_numbersテーブルがあるとする。両テーブルのカラム情報を下記に記載する。
    - usersテーブル

        | Field             | Type            | Null | Key | Default | Extra          |
        | --- | --- | --- | --- | --- | --- |
        | id                | bigint unsigned | NO   | PRI | NULL    | auto_increment |
        | name              | varchar(255)    | NO   |     | NULL    |                |
        | email             | varchar(255)    | NO   | UNI | NULL    |                |
        | email_verified_at | timestamp       | YES  |     | NULL    |                |
        | password          | varchar(255)    | NO   |     | NULL    |                |
        | remember_token    | varchar(100)    | YES  |     | NULL    |                |
        | created_at        | timestamp       | YES  |     | NULL    |                |
        | updated_at        | timestamp       | YES  |     | NULL    |                |

    - phonesテーブル

        | Field        | Type            | Null | Key | Default | Extra          |
        | --- | --- | --- | --- | --- | --- |
        | id           | bigint unsigned | NO   | PRI | NULL    | auto_increment |
        | user_id      | bigint unsigned | NO   |     | NULL    |                |
        | number | varchar(255)    | NO   |     | NULL    |                |
        | created_at   | timestamp       | YES  |     | NULL    |                |
        | updated_at   | timestamp       | YES  |     | NULL    |                |
- 両テーブルのカラムに注目するとわかるようにusersテーブルとphone_numbersテーブルは1対1の関係になっている。（usersテーブルのidとphone_numbersテーブルのuser_id）
- 前述した1対1のリレーションを定義する。

# 概要

1. usersテーブルからphonesテーブルに対するモデルファイルへの定義記載
1. phonesテーブルからusersテーブルに対するモデルファイルへの定義記載

# 詳細

1. usersテーブルからphonesテーブルに対するモデルファイルへの定義記載
    1. アプリ名ディレクトリで下記コマンドを実行してUserモデルファイルを開く。

        ```terminal
        $ vi app/Models/User.php
        ```
    1. 下記のようにリレーションを定義する。

        ```アプリ名ディレクトリ/app/Models/User.php
        <?php
        
        namespace App\Models;
        
        use Illuminate\Contracts\Auth\MustVerifyEmail;
        use Illuminate\Database\Eloquent\Factories\HasFactory;
        use Illuminate\Foundation\Auth\User as Authenticatable;
        use Illuminate\Notifications\Notifiable;
        
        class User extends Authenticatable
        {
            use HasFactory, Notifiable;
        
            /**
             * The attributes that are mass assignable.
             *
             * @var array
             */
            protected $fillable = [
                'name',
                'email',
                'password',
            ];
        
            /**
             * The attributes that should be hidden for arrays.
             *
             * @var array
             */
            protected $hidden = [
                'password',
                'remember_token',
            ];
        
            /**
             * The attributes that should be cast to native types.
             *
             * @var array
             */
            protected $casts = [
                'email_verified_at' => 'datetime',
            ];
        
            // 下記を追記
            /**
             * ユーザの電話番号を取得
             *
             * @return void
             */
            public function phone()
            {
                return $this->hasOne('App\Models\Phone');
            }
            // 上記までを追記
        }
        
        ```
    1. アプリ名ディレクトリで下記コマンドを実行してtinkerを起動する。

        ```terminal
        $ php artisan tinker
        ```
    1. tinkerで下記を実行してnull以外が帰ってくることを確認する。（usersテーブルとphonesテーブルにそれぞれデータが格納されているものとする。スペルミスがないのにnullが帰ってきてしまうときはtinkerを再起動する。）

        ```php
        use App\Models\User;
        User::find(1)->phone;
        ```
1. phonesテーブルからusersテーブルに対するモデルファイルへの定義記載
    1. アプリ名ディレクトリで下記コマンドを実行してUserモデルファイルを開く。

        ```terminal
        $ vi app/Models/Phone.php
        ```
    1. 下記のようにリレーションを定義する。

        ```アプリ名ディレクトリ/app/Models/Phone.php
        <?php
        
        namespace App\Models;
        
        use Illuminate\Database\Eloquent\Factories\HasFactory;
        use Illuminate\Database\Eloquent\Model;
        
        class Phone extends Model
        {
            use HasFactory;
        
            // 下記を追記
            public function user()
            {
                return $this->belongsTo('App\Models\user');
            }
            // 上記までを追記
        }
        ```
    1. アプリ名ディレクトリで下記コマンドを実行してtinkerを起動する。

        ```terminal
        $ php artisan tinker
        ```
    1. tinkerで下記を実行してnull以外が帰ってくることを確認する。（usersテーブルとphonesテーブルにそれぞれデータが格納されているものとする。スペルミスがないのにnullが帰ってきてしまうときはtinkerを再起動する。）

        ```php
        use App\Models\Phone;
        User::find(1)->user;
        ```

# 超簡単なまとめ

- 1対1のリレーションはメインテーブル→サブテーブルのときはhasOne(サブテーブルに紐づくモデル名)を使用し、サブテーブル→メインテーブルのときはbelongsTo(メインテーブルに紐づくモデル名)と記載する。

# 参考文献

- [Laravel 8.x Eloquent：リレーション](https://readouble.com/laravel/8.x/ja/eloquent-relationships.html)