はじめに

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

アクセサとミューテータ

アクセサの定義

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

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

  1. <?php
  2. namespace App\Models;
  3. use Illuminate\Database\Eloquent\Casts\Attribute;
  4. use Illuminate\Database\Eloquent\Model;
  5. class User extends Model
  6. {
  7. /**
  8. * Get the user's first name.
  9. */
  10. protected function firstName(): Attribute
  11. {
  12. return Attribute::make(
  13. get: fn (string $value) => ucfirst($value),
  14. );
  15. }
  16. }

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

ご覧のとおり、列の元の値がアクセサに渡され、値を操作して返すことができます。アクセサの値にアクセスするには、モデルインスタンスのfirst_name属性に単純にアクセスできます:

  1. use App\Models\User;
  2. $user = User::find(1);
  3. $firstName = $user->first_name;

計算されたこれらの値をモデルの配列/JSON表現に追加したい場合は、それらを追加する必要があります

複数属性からの値オブジェクトの構築

時には、アクセサが複数のモデル属性を単一の「値オブジェクト」に変換する必要があります。そのために、getクロージャは、$attributesの2番目の引数を受け入れることができ、これは自動的にクロージャに供給され、モデルの現在のすべての属性の配列を含みます:

  1. use App\Support\Address;
  2. use Illuminate\Database\Eloquent\Casts\Attribute;
  3. /**
  4. * Interact with the user's address.
  5. */
  6. protected function address(): Attribute
  7. {
  8. return Attribute::make(
  9. get: fn (mixed $value, array $attributes) => new Address(
  10. $attributes['address_line_one'],
  11. $attributes['address_line_two'],
  12. ),
  13. );
  14. }

アクセサキャッシング

アクセサから値オブジェクトを返すとき、値オブジェクトに加えられた変更は、モデルが保存される前に自動的にモデルに同期されます。これは、Eloquentがアクセサによって返されたインスタンスを保持するため、アクセサが呼び出されるたびに同じインスタンスを返すことができるからです:

  1. use App\Models\User;
  2. $user = User::find(1);
  3. $user->address->lineOne = 'Updated Address Line 1 Value';
  4. $user->address->lineTwo = 'Updated Address Line 2 Value';
  5. $user->save();

ただし、文字列やブール値などのプリミティブ値のキャッシングを有効にしたい場合があります。特に計算集約が多い場合はそうです。これを実現するには、アクセサを定義するときにshouldCacheメソッドを呼び出すことができます:

  1. protected function hash(): Attribute
  2. {
  3. return Attribute::make(
  4. get: fn (string $value) => bcrypt(gzuncompress($value)),
  5. )->shouldCache();
  6. }

属性のオブジェクトキャッシング動作を無効にしたい場合は、属性を定義するときにwithoutObjectCachingメソッドを呼び出すことができます:

  1. /**
  2. * Interact with the user's address.
  3. */
  4. protected function address(): Attribute
  5. {
  6. return Attribute::make(
  7. get: fn (mixed $value, array $attributes) => new Address(
  8. $attributes['address_line_one'],
  9. $attributes['address_line_two'],
  10. ),
  11. )->withoutObjectCaching();
  12. }

ミューテータの定義

ミューテータは、Eloquent属性値が設定されるときに変換されます。ミューテータを定義するには、属性を定義するときにset引数を提供できます。first_name属性のミューテータを定義しましょう。このミューテータは、モデルのfirst_name属性の値を設定しようとする際に自動的に呼び出されます:

  1. <?php
  2. namespace App\Models;
  3. use Illuminate\Database\Eloquent\Casts\Attribute;
  4. use Illuminate\Database\Eloquent\Model;
  5. class User extends Model
  6. {
  7. /**
  8. * Interact with the user's first name.
  9. */
  10. protected function firstName(): Attribute
  11. {
  12. return Attribute::make(
  13. get: fn (string $value) => ucfirst($value),
  14. set: fn (string $value) => strtolower($value),
  15. );
  16. }
  17. }

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

  1. use App\Models\User;
  2. $user = User::find(1);
  3. $user->first_name = 'Sally';

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

複数属性のミューテーション

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

  1. use App\Support\Address;
  2. use Illuminate\Database\Eloquent\Casts\Attribute;
  3. /**
  4. * Interact with the user's address.
  5. */
  6. protected function address(): Attribute
  7. {
  8. return Attribute::make(
  9. get: fn (mixed $value, array $attributes) => new Address(
  10. $attributes['address_line_one'],
  11. $attributes['address_line_two'],
  12. ),
  13. set: fn (Address $value) => [
  14. 'address_line_one' => $value->lineOne,
  15. 'address_line_two' => $value->lineTwo,
  16. ],
  17. );
  18. }

属性キャスティング

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

  1. - `````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

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

  1. <?php
  2. namespace App\Models;
  3. use Illuminate\Database\Eloquent\Model;
  4. class User extends Model
  5. {
  6. /**
  7. * Get the attributes that should be cast.
  8. *
  9. * @return array<string, string>
  10. */
  11. protected function casts(): array
  12. {
  13. return [
  14. 'is_admin' => 'boolean',
  15. ];
  16. }
  17. }

キャストを定義した後、is_admin属性は、たとえ基礎となる値がデータベースに整数として保存されていても、アクセスする際に常にブール値にキャストされます:

  1. $user = App\Models\User::find(1);
  2. if ($user->is_admin) {
  3. // ...
  4. }

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

  1. $user->mergeCasts([
  2. 'is_admin' => 'integer',
  3. 'options' => 'object',
  4. ]);
  1. <a name="stringable-casting"></a>
  2. #### ストリングキャスト
  3. モデル属性を[流暢な`````Illuminate\Support\Stringable`````オブジェクト](3b58d700a029d9f7.md#fluent-strings-method-list)にキャストするには、`````Illuminate\Database\Eloquent\Casts\AsStringable`````キャストクラスを使用できます:
  4. ``````php
  5. <?php
  6. namespace App\Models;
  7. use Illuminate\Database\Eloquent\Casts\AsStringable;
  8. use Illuminate\Database\Eloquent\Model;
  9. class User extends Model
  10. {
  11. /**
  12. * Get the attributes that should be cast.
  13. *
  14. * @return array<string, string>
  15. */
  16. protected function casts(): array
  17. {
  18. return [
  19. 'directory' => AsStringable::class,
  20. ];
  21. }
  22. }
  23. `

配列およびJSONキャスト

  1. ``````php
  2. <?php
  3. namespace App\Models;
  4. use Illuminate\Database\Eloquent\Model;
  5. class User extends Model
  6. {
  7. /**
  8. * Get the attributes that should be cast.
  9. *
  10. * @return array<string, string>
  11. */
  12. protected function casts(): array
  13. {
  14. return [
  15. 'options' => 'array',
  16. ];
  17. }
  18. }
  19. `

キャストが定義されると、options属性にアクセスすると、自動的にJSONからPHP配列にデシリアライズされます。options属性の値を設定すると、指定された配列は自動的にストレージ用にJSONにシリアライズされます:

  1. use App\Models\User;
  2. $user = User::find(1);
  3. $options = $user->options;
  4. $options['key'] = 'value';
  5. $user->options = $options;
  6. $user->save();

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

  1. $user = User::find(1);
  2. $user->update(['options->key' => 'value']);

配列オブジェクトおよびコレクションキャスト

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

  1. $user = User::find(1);
  2. $user->options['key'] = $value;

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

  1. use Illuminate\Database\Eloquent\Casts\AsArrayObject;
  2. /**
  3. * Get the attributes that should be cast.
  4. *
  5. * @return array<string, string>
  6. */
  7. protected function casts(): array
  8. {
  9. return [
  10. 'options' => AsArrayObject::class,
  11. ];
  12. }

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

  1. use Illuminate\Database\Eloquent\Casts\AsCollection;
  2. /**
  3. * Get the attributes that should be cast.
  4. *
  5. * @return array<string, string>
  6. */
  7. protected function casts(): array
  8. {
  9. return [
  10. 'options' => AsCollection::class,
  11. ];
  12. }
  1. ``````php
  2. use App\Collections\OptionCollection;
  3. use Illuminate\Database\Eloquent\Casts\AsCollection;
  4. /**
  5. * Get the attributes that should be cast.
  6. *
  7. * @return array<string, string>
  8. */
  9. protected function casts(): array
  10. {
  11. return [
  12. 'options' => AsCollection::using(OptionCollection::class),
  13. ];
  14. }
  15. `

日付キャスト

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

  1. ``````php
  2. /**
  3. * Get the attributes that should be cast.
  4. *
  5. * @return array<string, string>
  6. */
  7. protected function casts(): array
  8. {
  9. return [
  10. 'created_at' => 'datetime:Y-m-d',
  11. ];
  12. }
  13. `

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

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

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

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

  1. /**
  2. * The storage format of the model's date columns.
  3. *
  4. * @var string
  5. */
  6. protected $dateFormat = 'U';

日付キャスト、シリアル化、およびタイムゾーン

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

  1. <a name="enum-casting"></a>
  2. ### 列挙型キャスト
  3. Eloquentは、属性値をPHPの[列挙型](https://www.php.net/manual/en/language.enumerations.backed.php)にキャストすることも許可します。これを実現するには、モデルの`````casts`````メソッドでキャストしたい属性と列挙型を指定します:
  4. ``````php
  5. use App\Enums\ServerStatus;
  6. /**
  7. * Get the attributes that should be cast.
  8. *
  9. * @return array<string, string>
  10. */
  11. protected function casts(): array
  12. {
  13. return [
  14. 'status' => ServerStatus::class,
  15. ];
  16. }
  17. `

モデルでキャストを定義すると、指定された属性は、属性と対話する際に自動的に列挙型にキャストされます:

  1. if ($server->status == ServerStatus::Provisioned) {
  2. $server->status = ServerStatus::Ready;
  3. $server->save();
  4. }

列挙型の配列キャスト

時には、モデルが単一の列に列挙型の値の配列を保存する必要があります。これを実現するには、Laravelが提供するAsEnumArrayObjectまたはAsEnumCollectionキャストを利用できます:

  1. use App\Enums\ServerStatus;
  2. use Illuminate\Database\Eloquent\Casts\AsEnumCollection;
  3. /**
  4. * Get the attributes that should be cast.
  5. *
  6. * @return array<string, string>
  7. */
  8. protected function casts(): array
  9. {
  10. return [
  11. 'statuses' => AsEnumCollection::of(ServerStatus::class),
  12. ];
  13. }

暗号化キャスト

  1. 暗号化されたテキストの最終的な長さは予測できず、平文の対応物よりも長くなるため、関連するデータベース列は`````TEXT`````型以上であることを確認してください。さらに、値がデータベースに暗号化されているため、暗号化された属性値をクエリまたは検索することはできません。
  2. <a name="key-rotation"></a>
  3. #### キーのローテーション
  4. ご存知のように、Laravelはアプリケーションの`````app`````設定ファイルで指定された`````key`````設定値を使用して文字列を暗号化します。通常、この値は`````APP_KEY`````環境変数の値に対応します。アプリケーションの暗号化キーをローテーションする必要がある場合は、新しいキーを使用して暗号化された属性を手動で再暗号化する必要があります。
  5. <a name="query-time-casting"></a>
  6. ### クエリ時のキャスティング
  7. 時には、クエリを実行する際にキャストを適用する必要があります。たとえば、テーブルから生の値を選択する場合などです。次のクエリを考えてみましょう:
  8. ``````php
  9. use App\Models\Post;
  10. use App\Models\User;
  11. $users = User::select([
  12. 'users.*',
  13. 'last_posted_at' => Post::selectRaw('MAX(created_at)')
  14. ->whereColumn('user_id', 'users.id')
  15. ])->get();
  16. `

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

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

カスタムキャスト

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

  1. php artisan make:cast Json

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

  1. <?php
  2. namespace App\Casts;
  3. use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
  4. use Illuminate\Database\Eloquent\Model;
  5. class Json implements CastsAttributes
  6. {
  7. /**
  8. * Cast the given value.
  9. *
  10. * @param array<string, mixed> $attributes
  11. * @return array<string, mixed>
  12. */
  13. public function get(Model $model, string $key, mixed $value, array $attributes): array
  14. {
  15. return json_decode($value, true);
  16. }
  17. /**
  18. * Prepare the given value for storage.
  19. *
  20. * @param array<string, mixed> $attributes
  21. */
  22. public function set(Model $model, string $key, mixed $value, array $attributes): string
  23. {
  24. return json_encode($value);
  25. }
  26. }

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

  1. <?php
  2. namespace App\Models;
  3. use App\Casts\Json;
  4. use Illuminate\Database\Eloquent\Model;
  5. class User extends Model
  6. {
  7. /**
  8. * Get the attributes that should be cast.
  9. *
  10. * @return array<string, string>
  11. */
  12. protected function casts(): array
  13. {
  14. return [
  15. 'options' => Json::class,
  16. ];
  17. }
  18. }

値オブジェクトキャスト

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

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

  1. <?php
  2. namespace App\Casts;
  3. use App\ValueObjects\Address as AddressValueObject;
  4. use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
  5. use Illuminate\Database\Eloquent\Model;
  6. use InvalidArgumentException;
  7. class Address implements CastsAttributes
  8. {
  9. /**
  10. * Cast the given value.
  11. *
  12. * @param array<string, mixed> $attributes
  13. */
  14. public function get(Model $model, string $key, mixed $value, array $attributes): AddressValueObject
  15. {
  16. return new AddressValueObject(
  17. $attributes['address_line_one'],
  18. $attributes['address_line_two']
  19. );
  20. }
  21. /**
  22. * Prepare the given value for storage.
  23. *
  24. * @param array<string, mixed> $attributes
  25. * @return array<string, string>
  26. */
  27. public function set(Model $model, string $key, mixed $value, array $attributes): array
  28. {
  29. if (! $value instanceof AddressValueObject) {
  30. throw new InvalidArgumentException('The given value is not an Address instance.');
  31. }
  32. return [
  33. 'address_line_one' => $value->lineOne,
  34. 'address_line_two' => $value->lineTwo,
  35. ];
  36. }
  37. }

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

  1. use App\Models\User;
  2. $user = User::find(1);
  3. $user->address->lineOne = 'Updated Address Value';
  4. $user->save();

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

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

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

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

  1. class Address implements CastsAttributes
  2. {
  3. public bool $withoutObjectCaching = true;
  4. // ...
  5. }

配列/JSONシリアル化

EloquentモデルがtoArrayおよびtoJsonメソッドを使用して配列またはJSONに変換されると、カスタムキャスト値オブジェクトは通常、Illuminate\Contracts\Support\ArrayableおよびJsonSerializableインターフェースを実装している限り、シリアライズされます。ただし、サードパーティライブラリによって提供される値オブジェクトを使用する場合、これらのインターフェースをオブジェクトに追加する能力がない場合があります。

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

  1. /**
  2. * Get the serialized representation of the value.
  3. *
  4. * @param array<string, mixed> $attributes
  5. */
  6. public function serialize(Model $model, string $key, mixed $value, array $attributes): string
  7. {
  8. return (string) $value;
  9. }

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

時には、モデルに設定されている値のみを変換し、モデルから属性を取得する際には操作を行わないカスタムキャストクラスを書く必要があります。

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

  1. php artisan make:cast Hash --inbound

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

  1. <?php
  2. namespace App\Casts;
  3. use Illuminate\Contracts\Database\Eloquent\CastsInboundAttributes;
  4. use Illuminate\Database\Eloquent\Model;
  5. class Hash implements CastsInboundAttributes
  6. {
  7. /**
  8. * Create a new cast class instance.
  9. */
  10. public function __construct(
  11. protected string|null $algorithm = null,
  12. ) {}
  13. /**
  14. * Prepare the given value for storage.
  15. *
  16. * @param array<string, mixed> $attributes
  17. */
  18. public function set(Model $model, string $key, mixed $value, array $attributes): string
  19. {
  20. return is_null($this->algorithm)
  21. ? bcrypt($value)
  22. : hash($this->algorithm, $value);
  23. }
  24. }

キャストパラメータ

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

  1. /**
  2. * Get the attributes that should be cast.
  3. *
  4. * @return array<string, string>
  5. */
  6. protected function casts(): array
  7. {
  8. return [
  9. 'secret' => Hash::class.':sha256',
  10. ];
  11. }

キャスト可能なもの

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

  1. use App\ValueObjects\Address;
  2. protected function casts(): array
  3. {
  4. return [
  5. 'address' => Address::class,
  6. ];
  7. }
  1. ``````php
  2. <?php
  3. namespace App\ValueObjects;
  4. use Illuminate\Contracts\Database\Eloquent\Castable;
  5. use App\Casts\Address as AddressCast;
  6. class Address implements Castable
  7. {
  8. /**
  9. * Get the name of the caster class to use when casting from / to this cast target.
  10. *
  11. * @param array<string, mixed> $arguments
  12. */
  13. public static function castUsing(array $arguments): string
  14. {
  15. return AddressCast::class;
  16. }
  17. }
  18. `
  1. ``````php
  2. use App\ValueObjects\Address;
  3. protected function casts(): array
  4. {
  5. return [
  6. 'address' => Address::class.':argument',
  7. ];
  8. }
  9. `

キャスト可能なものと匿名キャストクラス

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

  1. <?php
  2. namespace App\ValueObjects;
  3. use Illuminate\Contracts\Database\Eloquent\Castable;
  4. use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
  5. class Address implements Castable
  6. {
  7. // ...
  8. /**
  9. * Get the caster class to use when casting from / to this cast target.
  10. *
  11. * @param array<string, mixed> $arguments
  12. */
  13. public static function castUsing(array $arguments): CastsAttributes
  14. {
  15. return new class implements CastsAttributes
  16. {
  17. public function get(Model $model, string $key, mixed $value, array $attributes): Address
  18. {
  19. return new Address(
  20. $attributes['address_line_one'],
  21. $attributes['address_line_two']
  22. );
  23. }
  24. public function set(Model $model, string $key, mixed $value, array $attributes): array
  25. {
  26. return [
  27. 'address_line_one' => $value->lineOne,
  28. 'address_line_two' => $value->lineTwo,
  29. ];
  30. }
  31. };
  32. }
  33. }