【Laravel】中間テーブルの値をDateTime型で取得したい


目的

多対多のモデルがあり、中間テーブルにはDatetime型のフィールドがあるとします。
たとえば下記のように、ユーザーが複数のスクールに通っており、それぞれのスクールを開始した日時をもっているとき、

開始日時をDateTimeで取得し、format()などのメソッドをそのまま使いたいときのモデル定義はどうすればいいかについて、覚書を残します。

foreach($user->schools as $school){
 echo $school->pivot->start_at->format('Y年m月d日'); // Datetimeにキャストされた状態で値を取得したい
}

結論

カスタム中間テーブルモデルを定義し、そこに日付ミューテタを追加します。

手順

1. カスタム中間テーブルを作成する

中間テーブル自体のオリジナルモデルを定義して使用することができます。
Pivotを継承することを忘れないようにしましょう。

SchoolUser.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Relations\Pivot; 

class SchoolUser extends Pivot // Pivotを継承する
{
    //
}

2. 日付ミューテタの設定

Eloquentでは、$datesプロパティをセットすることにより、属性値をCarbon(DateTimeの拡張クラス)インスタンスとして取得することができます。
ちなみに、タイムスタンプ(created_atとupdated_at)は自動的にキャストされるようになっています。

<?php

namespace App;

use Illuminate\Database\Eloquent\Relations\Pivot;

class SchoolUser extends Pivot
{
    protected $dates = ['start_at']; // 日付ミューテタの設定
}

3. リレーションの設定

おなじみ、各モデルで多対多のリレーションをbelongsToManyで設定します。
このとき、usingメソッドを呼び出すことで、カスタム中間テーブルモデルを使用することができます。

User.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * 役目を所有するユーザー
     */
    public function school()
    {
        return $this->belongsToMany('App\School')
                        ->using('App\SchoolUser') // カスタム中間テーブルの使用
                        ->withPivot([
                            'start_at',
                        ]);
    }
}

以上。

参考

Laravel 7.x Eloquent:リレーション 
Laravel 7.x Eloquent:ミューテタ