【Laravel】Laravel11でアクセサを完全に自動でシリアライズやtoArrayに含める方法

 Laravelにはアクセサという仕組みがあります。これを使うとモデルに定義した計算による値の取得をLaravelに即した形でできます。これは次のようにできます。

protected function addressFull(): Attribute
{
    return Attribute::make(
        get: fn (mixed $value, array $attributes) => $attributes['address_01'] . $attributes['address_02'],
    );
}

// 定義はキャメルケース。呼び出す時はスネークケース
echo $user->address_full;

11.x Eloquent:ミューテタ/キャスト Laravel

 便利ですが、そのままでは toArray 等でモデルから別の値に変換した際にその値が引き継がれません。自動で引き継ぐためには appends というプロパティに引き継ぎたい名前のメソッドを明記する必要があります。これは次のようにできます。
11.x Eloquent: シリアライズ Laravel#appending-values-to-json

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    protected $appends = [
        'address_full'  // 呼び出す時の名前を明記
    ];

    protected function addressFull(): Attribute
    {
        return Attribute::make(
            get: fn (mixed $value, array $attributes) => $attributes['address_01'] . $attributes['address_02'],
        );
    }
}

 実際これが速度面でも安全面でおすすめな方法なのですが、常にアクセサに重い処理を書くことがなく、常にアクセサ全てが必要で、開発体験こそが最重要な場合もあります(自分だけが使う自作プログラム等)。そういった時はアクセサを書くだけで自動でシリアライズや toArray の結果に含まれるようにしたいです。そういった場合は次のようにできます。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    public function __construct(array $attributes = [])
    {
        parent::__construct($attributes);
        // appends が手動設定済みならばこの後の自動ロードをしない
        if ($this->appends !== []) {
            return;
        }
        // appends の中身をメソッドの返り値の型を元に構築する
        // リフレクションで全てのメソッドを取得する
        // ここで400弱のメソッドを見るので速度面を気にする場合、これはやらない方がいいです。
        $methods = (new \ReflectionClass($this))->getMethods();
        foreach ($methods as $method) {
            // 返り値がAttributeであるメソッドのみを$appendsに追加
            $returnType = $method->getReturnType();
            if ($returnType && $returnType->getName() === Attribute::class) {
                // 呼び出し時の名前になるようにスネークケースに変換
                $this->appends[] = \Str::snake($method->getName());
            }
        }
    }

    protected function addressFull(): Attribute
    {
        return Attribute::make(
            get: fn (mixed $value, array $attributes) => $attributes['address_01'] . $attributes['address_02'],
        );
    }
}

 コンストラクタの中で appends を構築します。リフレクションを使うことによってメソッドを見て回り、アクセサメソッドを見つけた場合にそれを appends に追加します。こうすると自動でアクセサをシリアライズに含められます。

>株式会社シーポイントラボ

株式会社シーポイントラボ

TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:〒432-8003
   静岡県浜松市中央区和地山3-1-7
   浜松イノベーションキューブ 315
※ご来社の際はインターホンで「316」をお呼びください

CTR IMG