Laravel モデルのリレーション:1対1

データベースのテーブルの多くは他のテーブルと関係性を持ちます。例えば posts テーブルで管理されているブログの投稿は comments テーブルで管理されている複数のコメントと関係しています。

テーブル同士の関係性をEloquent Modelを使えば簡単に定義することができます。今回はモデルを使った関係性の中でも1対1のリレーションについて定義と実際の利用方法をまとめます。

1対1を定義する

「人」と所有している「電話」を想定してみましょう。

1対1の関係の場合、どちらかのテーブルに、もう一方のテーブルの id がわかるように user_id のようなカラムを持ちます。

user_id のように他のテーブルのどのデータか判別するためのカラムを「外部キー」と呼びます

f:id:kouVernon:20191012234451p:plain

使用するモデルの作成

User モデルと Phone モデルを作成します。

$ php artisan make:model User
$ php artisan make:model Phone

コマンドを実行したら app ディレクトリ配下に User.php と Phone.php が作成されていればOKです👍

UserモデルにPhoneモデルとのリレーションを定義する

User モデルにはhasOne メソッドを利用して、 Phone モデルとのリレーションを表す phone メソッドを実装できます。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}

モデルは自動的に外部キーを判断してくれます。例えば上記の例だと、Phone モデルは user_id という外部キーを持っていると判断してくれます。

もしも Phone モデルが持っている外部キーが user_id では無い場合、例えば active_user_id という名前だった場合、以下のように hasOne メソッドの第二引数を修正します。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    public function phone()
    {
        return $this->hasOne('App\Phone', 'active_user_id');
    }
}

リレーションを利用する

Model同士のリレーションの定義ができたら、コントローラーとbladeでどのように利用するのかをみていきましょう。

Userモデルに紐づいたPhoneをコントローラーで扱う

今回はControllerの中で利用することを想定して、以下のような UsersController と testアクション を作成しました。

※ Userモデルを利用するためにファイル上部で use App\User; と書かれていることを確認してください。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\User;

class UsersController extends Controller
{
    public function test()
    {
        //
    }
}

1対1のリレーションなので、まずはUser モデルを使ってデータを1つ見つけます。以下の例では id = 1 のデータを取得します。

public function test()
{
    $user = User::find(1);
}

※ モデルをつかったデータ取得方法はこちらも記事を参考にしてください。
Laravel モデルの作成とデータ取得

1対1の関係の場合、User モデルが1つ見つかると紐づく Phone モデルが見つかります。先ほど User モデルで hasOne メソッドを使って定義した関数を利用することができます。

public function test()
{
    // id = 1のデータを取得
    $user  = User::find(1);

    // $userに紐づくPhoneモデルを取得
    $phone = $user->phone;
}

これでコントローラーでモデルのリレーションを使ったデータ取得ができます。

Userモデルに紐づいたPhoneをbladeで扱う

例えば UsersControllertestアクション が以下のような実装だったとします。

public function test()
{
    $user = User::find(1);
    return view('home', ['user' => $user]);
}

id = 1User モデルを取得して、 home.blade.php というviewファイルを返しています。

bladeファイルで $user に紐づいている Phone モデルを利用するにはどうすればいいでしょうか。コントローラーと同じく、 先ほど User モデルで hasOne メソッドを使って定義した関数を利用することができます。

以下の例では仮に User モデルは name属性Phone モデルは number属性 を持っているものとします。

{{-- $userのname属性を表示します --}}
<p>{{ $user->name }}</p>

{{-- $userに紐づくPhoneモデルを取得し、かつnumber属性を表示します --}}
<p>{{ $user->phone->number }}</p>

これでbladeでモデルのリレーションを使ったデータ取得、表示ができます。

逆のリレーションを定義する

今まで User モデルから紐づいている Phone モデルを取得する方法をみてきましたが、逆に Phone モデルから紐づいている User モデルを取得する方法をみていきます。

hasOne メソッドを利用したリレーションの逆を表現する時には belongsTo メソッドを利用します。Phone モデルに以下のように user メソッドを実装してください。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Phone extends Model
{
    public function user()
    {
        return $this->belongsTo('App\User');
    }
}

上記の例では、 Phone モデルが user_id という外部キーを持っているとLaravel側が自動的に判断してくれます。

もしも Phone モデルが持っている外部キーが user_id では無い場合、例えば active_user_id という名前だった場合、以下のように belongsTo メソッドの第二引数を修正します。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Phone extends Model
{
    public function user()
    {
        return $this->belongsTo('App\User', 'active_user_id');
    }
}

ここまで来るとあとは今までと同じです。コントローラーでもbladeでも Phone モデルに紐づいた User モデルを利用することができます。

※ Phoneモデルを利用するためにファイル上部で use App\Phone; と書かれていることを確認してください。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\User;

class PhonesController extends Controller
{
    public function test()
    {
        // id = 1のデータを取得
        $phone = Phone::find(1);

        // $phoneに紐づくUserモデルを取得
        $user = $phone->user;

        return view('home', ['user' => $user]);
    }
}
{{-- $phoneのnumber属性を表示します --}}
<p>{{ $phone->number }}</p>

{{-- $phoneに紐づくUserモデルを取得し、かつname属性を表示します --}}
<p>{{ $phone->user->name }}</p>

まとめ

データベースのテーブルの多くは他のテーブルと関係性を持ちます。テーブル同士の関係性をEloquent Modelを使えば簡単に定義することができます。

今回はモデルを使った関係性の中でも1対1のリレーションについて定義と実際の利用方法をみてきました。

1対1の関係の場合、どちらかのテーブルに、もう一方のテーブルの id がわかるように user_id のようなカラムを持ちます。(このカラムを外部キーと言います)

リレーション(関係性)を定義する時には各モデルに hasOne メソッド、 belongsTo メソッドを利用して実装します。

コントローラーとbladeで利用する時にはモデルに実装した関数を使ってデータ取得をします。