メインコンテンツまでスキップ

エロクエント: ミューテータとキャスティング

はじめに

アクセサ、ミューテータ、属性のキャスティングを使用すると、モデルインスタンスで属性値を取得または設定する際に値を変換できます。たとえば、データベースに値を保存するときにLaravelの暗号化機能を使用して値を暗号化し、Eloquentモデルで属性にアクセスするときに自動的に属性を復号化したい場合があります。また、データベースに保存されているJSON文字列をEloquentモデルを介してアクセスするときに配列に変換したい場合もあります。

アクセサとミューテータ

アクセサの定義

アクセサは、属性にアクセスするときにEloquent属性値を変換します。アクセサを定義するには、モデルに保護されたメソッドを作成してアクセス可能な属性を表現します。このメソッド名は、適用可能な場合には真の基礎となるモデル属性/データベース列の「キャメルケース」表現に対応している必要があります。

この例では、first_name属性のためのアクセサを定義します。アクセサは、first_name属性の値を取得しようとするときにEloquentによって自動的に呼び出されます。すべての属性アクセサ/ミューテータメソッドは、Illuminate\Database\Eloquent\Casts\Attributeの戻り値の型ヒントを宣言する必要があります:

    <?php

namespace App\Models;

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

class User extends Model
{
/**
* Get the user's first name.
*/
protected function firstName(): Attribute
{
return Attribute::make(
get: fn (string $value) => ucfirst($value),
);
}
}

すべてのアクセサメソッドは、属性がどのようにアクセスされ、オプションで変異するかを定義するAttributeインスタンスを返します。この例では、属性がどのようにアクセスされるかだけを定義しています。そのため、Attributeクラスのコンストラクタにget引数を提供します。

如您所见,列的原始值被传递给访问器,允许您操纵并返回该值。要访问访问器的值,您可以简单地访问模型实例上的 first_name 属性:

    use App\Models\User;

$user = User::find(1);

$firstName = $user->first_name;

注記

如果您希望这些计算值添加到模型的数组/JSON表示中,您需要追加它们

从多个属性构建值对象

有时,您的访问器可能需要将多个模型属性转换为单个“值对象”。为此,您的 get 闭包可以接受第二个参数 $attributes,该参数将自动提供给闭包,并将包含模型当前所有属性的数组:

use App\Support\Address;
use Illuminate\Database\Eloquent\Casts\Attribute;

/**
* Interact with the user's address.
*/
protected function address(): Attribute
{
return Attribute::make(
get: fn (mixed $value, array $attributes) => new Address(
$attributes['address_line_one'],
$attributes['address_line_two'],
),
);
}

访问器缓存

当从访问器返回值对象时,对值对象所做的任何更改将在模型保存之前自动同步回模型。这是可能的,因为 Eloquent 保留由访问器返回的实例,以便每次调用访问器时都可以返回相同的实例:

    use App\Models\User;

$user = User::find(1);

$user->address->lineOne = 'Updated Address Line 1 Value';
$user->address->lineTwo = 'Updated Address Line 2 Value';

$user->save();

但是,有时您可能希望为诸如字符串和布尔值之类的原始值启用缓存,特别是如果它们具有计算密集型。为此,您可以在定义访问器时调用 shouldCache 方法:

protected function hash(): Attribute
{
return Attribute::make(
get: fn (string $value) => bcrypt(gzuncompress($value)),
)->shouldCache();
}

如果您希望禁用属性的对象缓存行为,您可以在定义属性时调用 withoutObjectCaching 方法:

/**
* Interact with the user's address.
*/
protected function address(): Attribute
{
return Attribute::make(
get: fn (mixed $value, array $attributes) => new Address(
$attributes['address_line_one'],
$attributes['address_line_two'],
),
)->withoutObjectCaching();
}

定义一个修改器

修改器在设置时转换 Eloquent 属性值。要定义修改器,您可以在定义属性时提供 set 参数。让我们为 first_name 属性定义一个修改器。当我们尝试设置模型上的 first_name 属性的值时,此修改器将自动调用:

    <?php

namespace App\Models;

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

class User extends Model
{
/**
* Interact with the user's first name.
*/
protected function firstName(): Attribute
{
return Attribute::make(
get: fn (string $value) => ucfirst($value),
set: fn (string $value) => strtolower($value),
);
}
}

ミューテータークロージャは、属性に設定されている値を受け取り、その値を操作して変更した値を返すことができます。ミューテーターを使用するには、Eloquentモデルのfirst_name属性を設定するだけです:

    use App\Models\User;

$user = User::find(1);

$user->first_name = 'Sally';

この例では、setコールバックが値Sallyとともに呼び出されます。その後、ミューテーターは名前にstrtolower関数を適用し、その結果の値をモデルの内部$attributes配列に設定します。

複数の属性の変更

時には、ミューテーターが基礎となるモデルの複数の属性を設定する必要があるかもしれません。その場合、setクロージャから配列を返すことができます。配列内の各キーは、モデルに関連付けられた基礎属性/データベース列に対応する必要があります:

use App\Support\Address;
use Illuminate\Database\Eloquent\Casts\Attribute;

/**
* Interact with the user's address.
*/
protected function address(): Attribute
{
return Attribute::make(
get: fn (mixed $value, array $attributes) => new Address(
$attributes['address_line_one'],
$attributes['address_line_two'],
),
set: fn (Address $value) => [
'address_line_one' => $value->lineOne,
'address_line_two' => $value->lineTwo,
],
);
}

属性のキャスティング

属性のキャスティングは、アクセサやミューテーターと同様の機能を提供しますが、モデルに追加のメソッドを定義する必要はありません。代わりに、モデルのcastsメソッドは、属性を一般的なデータ型に変換する便利な方法を提供します。

castsメソッドは、キーがキャストされる属性の名前であり、値が列をキャストする型である配列を返す必要があります。サポートされているキャストタイプは次のとおりです:

  • array
  • AsStringable::class
  • boolean
  • collection
  • date
  • datetime
  • immutable_date
  • immutable_datetime
  • decimal:<precision>
  • double
  • encrypted
  • encrypted:array
  • encrypted:collection
  • encrypted:object
  • float
  • hashed
  • integer
  • object
  • real
  • string
  • timestamp

属性のキャスティングを示すために、データベースに整数(0または1)として格納されているis_admin属性をブール値にキャストしてみましょう:

    <?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'is_admin' => 'boolean',
];
}
}

キャストを定義した後、is_admin属性は常にブール値にキャストされます。たとえデータベースに整数として格納されていても、アクセスするときには常にブール値になります。

    $user = App\Models\User::find(1);

if ($user->is_admin) {
// ...
}

新しい一時的なキャストを実行時に追加する必要がある場合は、mergeCasts メソッドを使用できます。これらのキャスト定義は、モデルで既に定義されているキャストに追加されます:

    $user->mergeCasts([
'is_admin' => 'integer',
'options' => 'object',
]);

警告

null である属性はキャストされません。さらに、関係性と同じ名前のキャスト(または属性)を定義したり、モデルの主キーにキャストを割り当てるべきではありません。

Stringable キャスト

モデル属性を 流暢な Illuminate\Support\Stringable オブジェクト にキャストするには、Illuminate\Database\Eloquent\Casts\AsStringable キャストクラスを使用できます:

    <?php

namespace App\Models;

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

class User extends Model
{
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'directory' => AsStringable::class,
];
}
}

配列と JSON キャスト

array キャストは、シリアライズされた JSON として保存されている列を扱う際に特に便利です。たとえば、データベースにシリアライズされた JSON を含む JSON または TEXT フィールドタイプがある場合、その属性に array キャストを追加すると、Eloquent モデルでアクセスするときにその属性が自動的に PHP 配列に逆シリアル化されます:

    <?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'options' => 'array',
];
}
}

キャストが定義されると、options 属性にアクセスでき、JSON が自動的に PHP 配列に逆シリアル化されます。options 属性の値を設定すると、指定された配列が自動的に JSON に戻されて保存されます:

    use App\Models\User;

$user = User::find(1);

$options = $user->options;

$options['key'] = 'value';

$user->options = $options;

$user->save();

より簡潔な構文で JSON 属性の単一のフィールドを更新するには、属性を一括代入可能に し、update メソッドを呼び出す際に -> 演算子を使用できます:

    $user = User::find(1);

$user->update(['options->key' => 'value']);

配列オブジェクトとコレクションのキャスト

標準の array キャストは多くのアプリケーションには十分ですが、いくつかの欠点があります。array キャストはプリミティブ型を返すため、配列のオフセットを直接変更することはできません。たとえば、次のコードは PHP エラーを引き起こします:

    $user = User::find(1);

$user->options['key'] = $value;

これを解決するために、LaravelはJSON属性をArrayObjectクラスにキャストするAsArrayObjectキャストを提供しています。この機能は、Laravelのカスタムキャスト実装を使用して実装されており、Laravelが変異したオブジェクトを賢くキャッシュして変換し、個々のオフセットをPHPエラーを引き起こさずに変更できるようにします。AsArrayObjectキャストを使用するには、単純に属性に割り当てます:

    use Illuminate\Database\Eloquent\Casts\AsArrayObject;

/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'options' => AsArrayObject::class,
];
}

同様に、LaravelはJSON属性をLaravelのCollectionインスタンスにキャストするAsCollectionキャストも提供しています:

    use Illuminate\Database\Eloquent\Casts\AsCollection;

/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'options' => AsCollection::class,
];
}

AsCollectionキャストがLaravelの基本コレクションクラスではなく、カスタムコレクションクラスをインスタンス化するようにしたい場合は、キャスト引数としてコレクションクラス名を指定できます:

    use App\Collections\OptionCollection;
use Illuminate\Database\Eloquent\Casts\AsCollection;

/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'options' => AsCollection::using(OptionCollection::class),
];
}

日付キャスティング

デフォルトでは、Eloquentはcreated_atおよびupdated_atカラムをCarbonのインスタンスにキャストします。これはPHPのDateTimeクラスを拡張し、さまざまな便利なメソッドを提供します。モデルのcastsメソッド内で追加の日付キャストを定義することで、追加の日付属性をキャストできます。通常、日付はdatetimeまたはimmutable_datetimeキャストタイプを使用してキャストする必要があります。

dateまたはdatetimeキャストを定義する際に、日付のフォーマットを指定することもできます。このフォーマットは、モデルが配列またはJSONにシリアル化されるときに使用されます:

    /**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'created_at' => 'datetime:Y-m-d',
];
}

カラムが日付としてキャストされている場合、対応するモデル属性値をUNIXタイムスタンプ、日付文字列(Y-m-d)、日付時刻文字列、またはDateTime / Carbonインスタンスに設定できます。日付の値は正しく変換されてデータベースに保存されます。

すべてのモデルの日付のデフォルトシリアル化形式をカスタマイズするには、モデルでserializeDateメソッドを定義します。このメソッドは、データベースに保存される日付のフォーマットに影響しません:

    /**
* Prepare a date for array / JSON serialization.
*/
protected function serializeDate(DateTimeInterface $date): string
{
return $date->format('Y-m-d');
}

モデルの日付を実際にデータベースに保存する際に使用する形式を指定するには、モデルで$dateFormatプロパティを定義する必要があります:

    /**
* The storage format of the model's date columns.
*
* @var string
*/
protected $dateFormat = 'U';

日付のキャスティング、シリアライズ、およびタイムゾーン

デフォルトでは、dateおよびdatetimeのキャストは、日付をUTCのISO-8601形式の日付文字列(YYYY-MM-DDTHH:MM:SS.uuuuuuZ)にシリアライズします。アプリケーションのtimezone構成オプションで指定されたタイムゾーンに関係なく、このシリアライゼーション形式を常に使用し、アプリケーションの日付をデフォルトのUTC値から変更せずにUTCタイムゾーンで保存することを強くお勧めします。アプリケーション全体で常にUTCタイムゾーンを使用することで、PHPおよびJavaScriptで記述された他の日付操作ライブラリとの最大レベルの相互運用性が提供されます。

dateまたはdatetimeキャストにカスタム形式が適用された場合(たとえば、datetime:Y-m-d H:i:s)、日付のシリアライゼーション中にCarbonインスタンスの内部タイムゾーンが使用されます。通常、これはアプリケーションのtimezone構成オプションで指定されたタイムゾーンになります。

Enumキャスティング

Eloquentでは、属性値をPHPのEnumsにキャストすることもできます。これを実現するために、モデルのcastsメソッドでキャストする属性とEnumを指定することができます:

    use App\Enums\ServerStatus;

/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'status' => ServerStatus::class,
];
}

モデルでキャストを定義した後、指定した属性は、その属性とやり取りする際に自動的にEnumにキャストおよびEnumからキャストされます:

    if ($server->status == ServerStatus::Provisioned) {
$server->status = ServerStatus::Ready;

$server->save();
}

Enumの配列のキャスティング

時々、モデルが1つの列内にEnum値の配列を保存する必要がある場合があります。これを実現するために、Laravelが提供するAsEnumArrayObjectまたはAsEnumCollectionキャストを利用することができます:

    use App\Enums\ServerStatus;
use Illuminate\Database\Eloquent\Casts\AsEnumCollection;

/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'statuses' => AsEnumCollection::of(ServerStatus::class),
];
}

暗号化キャスティング

encrypted キャストは、Laravel の組み込み暗号化機能を使用してモデルの属性値を暗号化します。さらに、encrypted:arrayencrypted:collectionencrypted:objectAsEncryptedArrayObjectAsEncryptedCollection キャストは、非暗号化の対応物と同様に機能しますが、データベースに保存される際に基になる値が暗号化される点が異なります。

暗号化されたテキストの最終的な長さは予測できず、プレーンテキストの対応物よりも長くなるため、関連するデータベースのカラムが TEXT 型またはそれ以上であることを確認してください。また、値がデータベースで暗号化されているため、暗号化された属性値をクエリや検索することはできません。

キーのローテーション

Laravel は、アプリケーションの app 構成ファイルで指定された key 構成値を使用して文字列を暗号化します。通常、この値は APP_KEY 環境変数の値に対応します。アプリケーションの暗号化キーをローテーションする必要がある場合は、新しいキーを使用して暗号化された属性を手動で再暗号化する必要があります。

クエリ時のキャスト

クエリを実行する際にキャストを適用する必要がある場合があります。たとえば、テーブルから生の値を選択する場合などです。次のクエリを考えてみてください:

    use App\Models\Post;
use App\Models\User;

$users = User::select([
'users.*',
'last_posted_at' => Post::selectRaw('MAX(created_at)')
->whereColumn('user_id', 'users.id')
])->get();

このクエリの結果の last_posted_at 属性は単純な文字列になります。この属性にクエリを実行する際に datetime キャストを適用できれば素晴らしいです。幸い、withCasts メソッドを使用してこの目的を達成することができます:

    $users = User::select([
'users.*',
'last_posted_at' => Post::selectRaw('MAX(created_at)')
->whereColumn('user_id', 'users.id')
])->withCasts([
'last_posted_at' => 'datetime'
])->get();

カスタムキャスト

Laravel にはさまざまな組み込みの便利なキャストタイプがありますが、時折独自のキャストタイプを定義する必要があるかもしれません。キャストを作成するには、make:cast Artisan コマンドを実行します。新しいキャストクラスは app/Casts ディレクトリに配置されます:

php artisan make:cast Json

すべてのカスタムキャストクラスは CastsAttributes インターフェースを実装しています。このインターフェースを実装するクラスは、get メソッドと set メソッドを定義する必要があります。get メソッドは、データベースからの生の値をキャスト値に変換する責任があり、set メソッドは、データベースに保存できる生の値にキャスト値を変換する必要があります。例として、組み込みの json キャストタイプをカスタムキャストタイプとして再実装します:

    <?php

namespace App\Casts;

use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Database\Eloquent\Model;

class Json implements CastsAttributes
{
/**
* Cast the given value.
*
* @param array<string, mixed> $attributes
* @return array<string, mixed>
*/
public function get(Model $model, string $key, mixed $value, array $attributes): array
{
return json_decode($value, true);
}

/**
* Prepare the given value for storage.
*
* @param array<string, mixed> $attributes
*/
public function set(Model $model, string $key, mixed $value, array $attributes): string
{
return json_encode($value);
}
}

カスタムキャストタイプを定義したら、そのクラス名を使用してモデル属性にアタッチすることができます:

    <?php

namespace App\Models;

use App\Casts\Json;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'options' => Json::class,
];
}
}

値オブジェクトのキャスティング

値をプリミティブ型にキャストすることに限定されません。値をオブジェクトにキャストすることもできます。値をオブジェクトにキャストするカスタムキャストを定義することは、プリミティブ型にキャストすることと非常に似ています。ただし、set メソッドは、モデルに格納可能な生の値を設定するために使用されるキー/値のペアの配列を返す必要があります。

例として、複数のモデル値を単一の Address 値オブジェクトにキャストするカスタムキャストクラスを定義します。Address 値には lineOnelineTwo の2つのパブリックプロパティがあると仮定します:

    <?php

namespace App\Casts;

use App\ValueObjects\Address as AddressValueObject;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Database\Eloquent\Model;
use InvalidArgumentException;

class Address implements CastsAttributes
{
/**
* Cast the given value.
*
* @param array<string, mixed> $attributes
*/
public function get(Model $model, string $key, mixed $value, array $attributes): AddressValueObject
{
return new AddressValueObject(
$attributes['address_line_one'],
$attributes['address_line_two']
);
}

/**
* Prepare the given value for storage.
*
* @param array<string, mixed> $attributes
* @return array<string, string>
*/
public function set(Model $model, string $key, mixed $value, array $attributes): array
{
if (! $value instanceof AddressValueObject) {
throw new InvalidArgumentException('The given value is not an Address instance.');
}

return [
'address_line_one' => $value->lineOne,
'address_line_two' => $value->lineTwo,
];
}
}

値オブジェクトにキャストする際、値オブジェクトに加えられた変更は、モデルが保存される前に自動的にモデルに同期されます:

    use App\Models\User;

$user = User::find(1);

$user->address->lineOne = 'Updated Address Value';

$user->save();

注記

Eloquent モデルに値オブジェクトを含むシリアライズを JSON や配列にする予定がある場合は、値オブジェクトに Illuminate\Contracts\Support\Arrayable および JsonSerializable インターフェースを実装する必要があります。

値オブジェクトのキャッシング

値オブジェクトにキャストされた属性が解決されると、Eloquent によってキャッシュされます。そのため、属性が再度アクセスされた場合には同じオブジェクトインスタンスが返されます。

カスタムキャストクラスのオブジェクトキャッシング動作を無効にしたい場合は、カスタムキャストクラスに公開の withoutObjectCaching プロパティを宣言することができます:

class Address implements CastsAttributes
{
public bool $withoutObjectCaching = true;

// ...
}

配列 / JSON シリアル化

Eloquent モデルを toArray メソッドや toJson メソッドを使用して配列や JSON に変換すると、カスタムキャスト値オブジェクトも通常シリアル化されます。ただし、サードパーティライブラリが提供する値オブジェクトを使用する場合、これらのインターフェースをオブジェクトに追加する機能がないかもしれません。

したがって、カスタムキャストクラスが値オブジェクトのシリアライズを担当するように指定することができます。そのためには、カスタムキャストクラスは Illuminate\Contracts\Database\Eloquent\SerializesCastableAttributes インターフェースを実装する必要があります。このインターフェースでは、クラスに serialize メソッドを含める必要があり、そのメソッドは値オブジェクトのシリアライズ形式を返す必要があります:

    /**
* Get the serialized representation of the value.
*
* @param array<string, mixed> $attributes
*/
public function serialize(Model $model, string $key, mixed $value, array $attributes): string
{
return (string) $value;
}

インバウンドキャスティング

時折、モデルに設定される値を変換するだけであり、モデルから取得される属性に対しては操作を行わないカスタムキャストクラスを作成する必要があるかもしれません。

インバウンド専用のカスタムキャストは CastsInboundAttributes インターフェースを実装する必要があり、set メソッドを定義するだけで済みます。インバウンド専用のキャストクラスを生成するには、make:cast Artisan コマンドを --inbound オプションと共に呼び出すことができます:

php artisan make:cast Hash --inbound

インバウンド専用のキャストの典型的な例は「ハッシング」キャストです。たとえば、指定されたアルゴリズムを使用してインバウンド値をハッシュ化するキャストを定義することができます:

    <?php

namespace App\Casts;

use Illuminate\Contracts\Database\Eloquent\CastsInboundAttributes;
use Illuminate\Database\Eloquent\Model;

class Hash implements CastsInboundAttributes
{
/**
* Create a new cast class instance.
*/
public function __construct(
protected string|null $algorithm = null,
) {}

/**
* Prepare the given value for storage.
*
* @param array<string, mixed> $attributes
*/
public function set(Model $model, string $key, mixed $value, array $attributes): string
{
return is_null($this->algorithm)
? bcrypt($value)
: hash($this->algorithm, $value);
}
}

キャストパラメータ

モデルにカスタムキャストをアタッチする際には、クラス名と : 文字を使用してパラメータを指定し、複数のパラメータをコンマで区切って指定することができます。これらのパラメータは、キャストクラスのコンストラクタに渡されます:

    /**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'secret' => Hash::class.':sha256',
];
}

キャスタブル

アプリケーションの値オブジェクトが独自のカスタムキャストクラスを定義することを許可したい場合、モデルにカスタムキャストクラスをアタッチする代わりに、Illuminate\Contracts\Database\Eloquent\Castable インターフェースを実装する値オブジェクトクラスをアタッチすることもできます:

    use App\ValueObjects\Address;

protected function casts(): array
{
return [
'address' => Address::class,
];
}

Castable インターフェースを実装するオブジェクトは、Castable クラスへのキャストを担当するカスタムキャスタークラスのクラス名を返す castUsing メソッドを定義する必要があります。

    <?php

namespace App\ValueObjects;

use Illuminate\Contracts\Database\Eloquent\Castable;
use App\Casts\Address as AddressCast;

class Address implements Castable
{
/**
* Get the name of the caster class to use when casting from / to this cast target.
*
* @param array<string, mixed> $arguments
*/
public static function castUsing(array $arguments): string
{
return AddressCast::class;
}
}

Castable クラスを使用する際には、casts メソッドの定義で引数を指定することができます。これらの引数は castUsing メソッドに渡されます:

    use App\ValueObjects\Address;

protected function casts(): array
{
return [
'address' => Address::class.':argument',
];
}

キャスタブル & 匿名キャストクラス

PHP の 匿名クラス と組み合わせることで、「キャスタブル」を使用して、値オブジェクトとそのキャストロジックを単一のキャスタブルオブジェクトとして定義することができます。これを実現するために、値オブジェクトの castUsing メソッドから匿名クラスを返します。匿名クラスは CastsAttributes インターフェースを実装する必要があります:

    <?php

namespace App\ValueObjects;

use Illuminate\Contracts\Database\Eloquent\Castable;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;

class Address implements Castable
{
// ...

/**
* このキャスト対象からのキャスト / へのキャストに使用するキャスタクラスを取得します。
*
* @param array<string, mixed> $arguments
*/
public static function castUsing(array $arguments): CastsAttributes
{
return new class implements CastsAttributes
{
public function get(Model $model, string $key, mixed $value, array $attributes): Address
{
return new Address(
$attributes['address_line_one'],
$attributes['address_line_two']
);
}

public function set(Model $model, string $key, mixed $value, array $attributes): array
{
return [
'address_line_one' => $value->lineOne,
'address_line_two' => $value->lineTwo,
];
}
};
}
}