Lang x Lang

Eloquent: Mutators & Casting

Table of Contents

Introduction

Accessors, mutators, そして attribute キャスティングは、model インスタンス上でそれらを取得または設定するときに Eloquent attribute values を transform することを可能にします。例えば、Laravel エンクリプタを使用して database 内に保存されている value を暗号化し、その attribute を Eloquent model 上でアクセスするときに自動的に復号化することができます。また、database に保存されている JSON string を Eloquent model 経由でアクセスされたときに array に変換するという場合もあります。

Accessors and Mutators

アクセサの定義

アクセサーは、アクセスされた際に Eloquent attribute value を変換します。アクセサーを定義するには、 model 上にアクセス可能な attribute を表す protected method を作成します。この method の名前は、該当する場合は、camel case 表現の true の基本的な model attribute / database column に対応しているべきです。

この例では、 first_name 属性のアクセサを定義します。 このアクセサは、 first_name 属性の value を取得しようとするときに、自動的に Eloquent によって呼び出されます。 すべての属性アクセサ/ミューテータ methods は、返り値の types ヒントを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),
        );
    }
}

すべてのアクセッサ methods は、属性がどのようにアクセスされ、option で変異するかを定義するAttributeインスタンスを返します。この例では、属性がどのようにアクセスされるかだけを定義しています。これを行うために、get引数をAttributeclass のコンストラクターに供給します。

ご覧の通り、元の value は column からアクセサに渡され、あなたがその value を操作し、返すことを可能にします。アクセサの value にアクセスするには、単にfirst_name attribute を model インスタンスでアクセスするだけです。

use App\Models\User;

$user = User::find(1);

$firstName = $user->first_name;

NOTE

これらの計算された values をあなたの model の array / JSON 表現に追加したい場合は、それらを append する必要があります

複数の Attributes から Value オブジェクトを作成する

時には、あなたのアクセサが複数の model attributes を一つの"value object"に変換する必要があるかもしれません。それを行うために、あなたのgetクロージャは第二引数として$attributesを受け入れることができます。これは自動的にクロージャに供給され、model の現在のすべての attributes の array を含んでいるでしょう。

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'],
        ),
    );
}

アクセサキャッシング

アクセサから value オブジェクトを返すとき、 value object への変更は自動的に model に同期され、その後で model が保存されます。これは 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();

しかし、時には文字列やブール型のようなプリミティブな values に対するキャッシュを有効にしたいこともあるでしょう。特にそれらが計算処理を多く必要とする場合には特にそうです。これを実現するためには、アクセサを定義する時にshouldCache method を呼び出すことができます。

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

もし attributes の object キャッシングの振る舞いを無効にしたいなら、 attribute を定義するときにwithoutObjectCaching method を呼び出すことができます:

/**
 * 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 attribute value を変換します。ミューテータを定義するには、 attribute を定義する際にset引数を提供できます。first_name attribute のミューテータを定義しましょう。このミューテータは、first_nameの attribute の value を model に設定しようと attempt すると自動的に呼び出されます:

<?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),
        );
    }
}

ミューテータクロージャーは、 attribute の設定中に value を受け取り、その value を操作して操作した value を返すことができます。ミューテータを使用するためには、 Eloquent model のfirst_name attribute を設定するだけです。

use App\Models\User;

$user = User::find(1);

$user->first_name = 'Sally';

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

複数の Attributes を変化させる

時々、あなたのミューテータは、基になる model に複数の attributes を設定する必要があるかもしれません。そのためには、setクロージャから array を返すことができます。 array の各キーは、 model に関連付けられた attribute / database column に対応するべきです:

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,
        ],
    );
}

Attribute Casting

Attribute キャスティングは、追加のメソッドを attributes に定義する必要なく、アクセサやミューテータと同様の機能を提供します。代わりに、 model のcasts method は、属性を一般的な data types に変換する便利な方法を提供します。

casts method は、キャストされる attribute の名前が key で、value はキャストしたい type、column へのキャストを希望する型が値である array を返す必要があります。サポートされているキャストの type は以下の通りです:

  • 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

attribute キャスティングを示すために、私たちの database に integer (0または1)として保存されているis_admin attribute を boolean value にキャストしてみましょう。

<?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 属性は、それが database に整数として保存されている場合であっても、それにアクセスするときは常にブールにキャストされます。

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

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

もし新しく、一時的なキャストを runtime で追加する必要がある場合、mergeCasts method を使うことができます。これらのキャスト定義は既に model 上で定義されているキャストのいずれかに追加されます。

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

WARNING

nullの属性はキャストされません。さらに、関係性と同じ名前のキャスト(または属性)を定義したり、model の primarykey にキャストを割り当てることは決してありません。

Stringable キャスティング

Illuminate\Database\Eloquent\Casts\AsStringableキャスト class を使用して、 model attribute をフルエントな Illuminate\Support\Stringable objectにキャストすることができます。

<?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,
        ];
    }
}

Array と JSON のキャスティング

arrayキャストは、シリアル化された JSON として保存されている columns を操作する際に特に便利です。例えば、あなたの database にJSONTEXTフィールドの type があり、それがシリアル化された JSON を含んでいる場合、その属性にarrayキャストを追加すると、その属性にアクセスする際に PHP の array へ自動的にデシリアライズします。Eloquent model 上でそれをアクセスするときに:

<?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の attribute にアクセスでき、自動的に JSON から PHP の array にデシリアライズされます。optionsの attribute の value を設定すると、指定された array は自動的に JSON にシリアライズされて storage に戻ります。

use App\Models\User;

$user = User::find(1);

$options = $user->options;

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

$user->options = $options;

$user->save();

より簡潔な syntax で JSON attribute の single フィールドを update するためには、attribute を一括割り当て可能にすることができ、update method を呼び出す際に->オペレータを使用します:

$user = User::find(1);

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

Array Object と Collection のキャスティング

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

$user = User::find(1);

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

これを解決するために、Laravel は、AsArrayObjectキャストを提供しており、これにより JSON 属性をArrayobject class に変換します。この機能は、Laravel のcustom キャスト実装を使用して実装されており、Laravel は、個々のオフセットが PHP error をトリガーすることなく変更できるように、変更された object をインテリジェントに cache および変換します。 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 attribute を 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 の基本の collection class の代わりに custom collection class をインスタンス化することを希望する場合、キャストの引数として collection class の名前を提供できます:

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),
    ];
}

日付のキャスティング

default では、 Eloquent は created_at および updated_at の columns を、PHP のDateTime class を拡張し、さまざまな便利な attributes を提供するCarbon のインスタンスにキャストします。model の casts method 内で追加の日付キャストを定義することで、追加の日付 属性をキャストすることができます。通常、日付は datetime または immutable_datetime キャスト types を使用してキャストする必要があります。

datedatetimeのキャストを定義するときに、日付の形式を指定することもできます。この形式は、model が array または JSON にシリアライズされるときに使用されます。

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

column が日付としてキャストされた場合、対応する model attribute value を UNIX の timestamp 、日付 string (Y-m-d)、日時 string 、もしくはDateTime / Carbonインスタンスに設定することができます。日付の value は正しく変換され、あなたの database に格納されます。

ご自身の model の全ての日付の default シリアライズ形式をカスタマイズすることが可能です。そのためには、model 上にserializeDate method を定義してください。この method は、database 内での storage のために日付がどのように整形されるかには影響を与えません:

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

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

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

日付のキャスト、直列化、およびタイムゾーン

default では、datedatetimeのキャストは、アプリケーションのtimezone設定オプションで指定された timezone に関係なく、日付を UTC ISO-8601 日付 string(YYYY-MM-DDTHH:MM:SS.uuuuuuZ)にシリアライズします。このシリアライズ形式を常に使用すること、およびアプリケーションの日付を default のUTC value から変更せずに UTC timezone で保存することが強く推奨されます。UTC timezone を application 全体で一貫して使用することで、PHP および JavaScript で書かれた他の日付操作ライブラリとの最大限の互換性が得られます。

datedatetimeキャストに custom フォーマットが適用される場合、例えばdatetime:Y-m-d H:i:sのような場合、 Carbon インスタンスの内部 timezone が日付のシリアル化の際に使用されます。通常、これはアプリケーションのtimezone設定オプションで指定した timezone になります。

Enum キャスティング

Eloquent はまた、あなたの attribute values を PHP enums にキャストすることもできます。これを達成するために、model の casts method でキャストしたい attribute と enum を指定することができます:

use App\Enums\ServerStatus;

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

model にキャストを定義すると、指定した attribute は、attribute とやり取りするときに自動的に enum にキャストされ、enum からキャストされます。

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

    $server->save();
}

Enum の配列のキャスト

時折、あなたの model が single column 内に enum values の array を格納する必要があるかもしれません。これを実現するためには、 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 の組み込みのencryption 機能を使用して、model の属性値を暗号化します。さらに、encrypted:arrayencrypted:collectionencrypted:objectAsEncryptedArrayObject、およびAsEncryptedCollectionキャストは、暗号化されていない対応するキャストと同じように動作します。しかし、おそらく思いもよらないでしょうが、基礎となる value は、database に格納されるときに暗号化されます。

暗号化されたテキストの最終的な length は予測できず、その平文の対応物よりも長いため、関連する database column がTEXTの type またはそれ以上の大きさであることを確認してください。さらに、 values は database で暗号化されているため、暗号化された attribute values を query または search することはできません。

キーのローテーション

ご存知の通り、 Laravel は、アプリケーションのapp設定ファイルで指定されたkey設定の value を使用して文字列を暗号化します。通常、この value はAPP_KEYの environment 変数の value に対応します。アプリケーションの encryption キーをローテートする必要がある場合は、新しいキーを使用して暗号化された attributes を手動で再暗号化する必要があります。

Query タイムキャスティング

時折、テーブルからの生の value を選択する場合など、 query を実行する際にキャストを適用する必要があるかもしれません。例えば、次の query を考えてみてください:

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();

この query の結果にあるlast_posted_at 属性はシンプルな string になるでしょう。この属性にdatetimeキャストを適用できたら素晴らしくなります。ありがたいことに、これはwithCasts method を使用して達成できます。

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

Custom Casts

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

php artisan make:cast Json

すべての custom キャストクラスは、CastsAttributesインターフェースを実装しています。 このインターフェースを実装するクラスは、getsetの method を定義する必要があります。 get の method は、 database からの生の value をキャストした value に変換する役割を担い、一方、setの method はキャストされた value を database に格納できる生の value に transform するべきです。例として、組み込みのjsonキャストの type を、 custom キャストの type として再実装します:

<?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);
    }
}

あなたが custom キャスト type を定義したら、その class 名を使用してそれを model attribute に attach することができます。

<?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,
        ];
    }
}

Value Object キャスティング

あなたは、values をプリミティブ types にキャストすることに限定されません。values を objects にキャストすることもできます。values を objects にキャストする custom キャストの定義は、プリミティブ types にキャストするのと非常に似ていますが、setmethod は、model 上で生の、保存可能な values を設定するために使用される key/value のペアの array を返すべきです。

例として、複数の model values を single のAddress value object にキャストする custom キャスト class を定義します。Address value には二つの public プロパティ:lineOnelineTwoがあると仮定します:

<?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,
        ];
    }
}

value オブジェクトにキャストする際、 value object に対して行ったすべての変更は、 model が保存される前に自動的に model に同期されます:

use App\Models\User;

$user = User::find(1);

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

$user->save();

NOTE

あなたが Eloquent models に含まれる value オブジェクトを JSON や配列にシリアライズする予定の場合、 value object にIlluminate\Contracts\Support\ArrayableJsonSerializableインタフェースを実装するべきです。

Value Object キャッシング

属性が valueobject にキャストされ解決されるとき、それらは Eloquent によって cache されます。したがって、属性が再びアクセスされた場合、同じ object インスタンスが返されます。

custom キャストクラスの object キャッシング動作を無効にしたい場合は、 custom キャスト class 上で public withoutObjectCaching プロパティを宣言することができます:

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

    // ...
}

Array / JSON シリアライゼーション

Eloquent model が toArraytoJson メソッドを使って array や JSON に変換されるとき、通常、 custom キャストの value オブジェクトもシリアライズされます。これらのオブジェクトは、Illuminate\Contracts\Support\Arrayable および JsonSerializable インターフェースを実装している限りです。しかし、サードパーティのライブラリから提供される value オブジェクトを使用していると、これらのインターフェースを object に追加する能力がないかもしれません。

したがって、あなたの custom キャスト class が value object のシリアライズを担当するように指定することができます。そのためには、あなたの custom キャスト class はIlluminate\Contracts\Database\Eloquent\SerializesCastableAttributesインターフェースを実装するべきです。このインターフェースは、あなたの class はserialize method を含むべきであり、これはあなたの value object のシリアライズされた形式を返すべきであると述べています:

/**
 * 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;
}

たまに、 model に設定されている values だけを変換し、 model から attributes を retrieved するときには何も操作を行わない、 custom なキャスト class を書く必要があるかもしれません。

インバウンド専用の custom casts は、set method のみを定義することを求めるCastsInboundAttributesインターフェースを実装する必要があります。 make:cast Artisan command は、インバウンド専用の cast class を生成するために、--inboundオプションを付けて呼び出すことができます:

php artisan make:cast Hash --inbound

受信専用キャストの古典的な例はハッシングキャストです。例えば、与えられた algorithm を通じて受信 values をハッシュするキャストを定義するかもしれません。

<?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);
    }
}

キャストパラメータ

model に custom キャストをアタッチするとき、キャストパラメータは、 class 名から:文字を使用して区切り、複数のパラメータをコンマで区切ることにより指定することができます。これらのパラメータはキャスト class のコンストラクタに渡されます:

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

Castables

あなたは、アプリケーションの value オブジェクトが自分自身の custom キャストクラスを定義することを許可したいかもしれません。 custom キャスト class をあなたの model に添付する代わりに、あなたは代わりにIlluminate\Contracts\Database\Eloquent\Castable インターフェースを実装する value object class を attach するかもしれません。

use App\ValueObjects\Address;

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

Castableインターフェースを実装する Objects は、Castable class へのキャストとその逆のキャストを担当する custom キャスターの class 名を返すcastUsing method を定義する必要があります。

<?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;
    }
}

Castableclass を使用する際でも、casts method の定義に引数を提供することができます。引数はcastUsing method に渡されます:

use App\ValueObjects\Address;

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

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

castables"を PHP の匿名クラス と組み合わせることで、" value object "とそのキャストロジックを" single "キャスト可能な" object "として定義することができます。これを達成するために、" value "オブジェクトのcastUsing " method "から匿名" class "を返します。匿名" class "は、CastsAttributesインターフェースを実装する必要があります:

<?php

namespace App\ValueObjects;

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

class Address implements Castable
{
    // ...

    /**
     * Get the caster class to use when casting from / to this cast target.
     *
     * @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,
                ];
            }
        };
    }
}

当社サイトでは、Cookie を使用しています。各規約をご確認の上ご利用ください:
Cookie Policy, Privacy Policy および Terms of Use