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 に追加します。こうすると自動でアクセサをシリアライズに含められます。