Eloquent:Mutators & Casting
簡介
訪問器、修改器和屬性 Cast 讓您可以在檢索或設定模型實例時轉換 Eloquent 屬性值。例如,您可能想使用 Laravel 加密器 來加密儲存在資料庫中的值,然後在您於 Eloquent 模型上訪問該屬性時自動解密。或者,您可能想要將儲存在資料庫中的 JSON 字串轉換為 PHP 陣列,以便透過您的 Eloquent 模型訪問。
訪問器與修改器
定義訪問器
訪問器會在屬性值被訪問時轉換它。要定義訪問器,請在您的模型上建立一個 protected 方法來表示可訪問的屬性。當適用時,此方法名稱應對應於真實底層模型屬性 / 資料庫欄位的「駝峰式命名」表示法。
在此範例中,我們將為 first_name
屬性定義一個訪問器。當嘗試檢索 first_name
屬性的值時,Eloquent 將自動呼叫此訪問器。所有屬性訪問器 / 修改器方法都必須宣告 Illuminate\Database\Eloquent\Casts\Attribute
的返回類型提示。
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Casts\Attribute; 6use Illuminate\Database\Eloquent\Model; 7 8class User extends Model 9{10 /**11 * Get the user's first name.12 */13 protected function firstName(): Attribute14 {15 return Attribute::make(16 get: fn (string $value) => ucfirst($value),17 );18 }19}
所有訪問器方法都會返回一個 Attribute
實例,該實例定義了屬性將如何被訪問,以及(可選地)如何被修改。在此範例中,我們僅定義屬性將如何被訪問。為此,我們將 get
參數提供給 Attribute
類別建構子。
如您所見,欄位的原始值會傳遞給訪問器,讓您可以操作並傳回該值。要訪問訪問器的值,您只需訪問模型實例上的 first_name
屬性即可。
1use App\Models\User;2 3$user = User::find(1);4 5$firstName = $user->first_name;
如果您希望將這些計算值添加到模型的陣列 / JSON 表示形式中,您將需要附加它們。
從多個屬性建構 Value Objects
有時您的訪問器可能需要將多個模型屬性轉換為單個「value object」。為此,您的 get
閉包可以接受第二個參數 $attributes
,它將自動提供給閉包,並將包含模型所有目前屬性的陣列。
1use App\Support\Address; 2use Illuminate\Database\Eloquent\Casts\Attribute; 3 4/** 5 * Interact with the user's address. 6 */ 7protected function address(): Attribute 8{ 9 return Attribute::make(10 get: fn (mixed $value, array $attributes) => new Address(11 $attributes['address_line_one'],12 $attributes['address_line_two'],13 ),14 );15}
訪問器快取
當從訪問器傳回 value objects 時,對 value object 所做的任何變更都將在模型儲存之前自動同步回模型。這是可能的,因為 Eloquent 保留了訪問器傳回的實例,因此每次調用訪問器時都可以傳回相同的實例。
1use App\Models\User;2 3$user = User::find(1);4 5$user->address->lineOne = 'Updated Address Line 1 Value';6$user->address->lineTwo = 'Updated Address Line 2 Value';7 8$user->save();
但是,您有時可能希望為諸如字串和布林值之類的原始值啟用快取,尤其是在它們計算量很大時。為了實現這一點,您可以在定義訪問器時調用 shouldCache
方法。
1protected function hash(): Attribute2{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 */ 4protected 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 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Casts\Attribute; 6use Illuminate\Database\Eloquent\Model; 7 8class User extends Model 9{10 /**11 * Interact with the user's first name.12 */13 protected function firstName(): Attribute14 {15 return Attribute::make(16 get: fn (string $value) => ucfirst($value),17 set: fn (string $value) => strtolower($value),18 );19 }20}
修改器閉包將接收正在設定在屬性上的值,讓您可以操作該值並傳回操作後的結果值。要使用我們的修改器,我們只需要在 Eloquent 模型上設定 first_name
屬性即可。
1use App\Models\User;2 3$user = User::find(1);4 5$user->first_name = 'Sally';
在此範例中,將使用值 Sally
呼叫 set
回呼。然後,修改器將把 strtolower
函式應用於名稱,並將其結果值設定在模型的內部 $attributes
陣列中。
修改多個屬性
有時您的修改器可能需要在底層模型上設定多個屬性。為此,您可以從 set
閉包傳回一個陣列。陣列中的每個鍵都應對應於與模型關聯的底層屬性 / 資料庫欄位。
1use App\Support\Address; 2use Illuminate\Database\Eloquent\Casts\Attribute; 3 4/** 5 * Interact with the user's address. 6 */ 7protected function address(): Attribute 8{ 9 return Attribute::make(10 get: fn (mixed $value, array $attributes) => new Address(11 $attributes['address_line_one'],12 $attributes['address_line_two'],13 ),14 set: fn (Address $value) => [15 'address_line_one' => $value->lineOne,16 'address_line_two' => $value->lineTwo,17 ],18 );19}
屬性 Cast
屬性 Cast 提供了與訪問器和修改器類似的功能,而無需您在模型上定義任何額外的方法。相反,您模型的 casts
方法提供了一種方便的方式,可將屬性轉換為常見的資料類型。
casts
方法應傳回一個陣列,其中鍵是要 Cast 的屬性名稱,而值是您希望將欄位 Cast 為的類型。支援的 Cast 類型為:
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
為了示範屬性 Cast,讓我們將儲存在資料庫中為整數 (0
或 1
) 的 is_admin
屬性 Cast 為布林值。
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Model; 6 7class User extends Model 8{ 9 /**10 * Get the attributes that should be cast.11 *12 * @return array<string, string>13 */14 protected function casts(): array15 {16 return [17 'is_admin' => 'boolean',18 ];19 }20}
定義 Cast 後,當您訪問 is_admin
屬性時,它將始終被 Cast 為布林值,即使底層值在資料庫中儲存為整數。
1$user = App\Models\User::find(1);2 3if ($user->is_admin) {4 // ...5}
如果您需要在執行時新增新的暫時性 Cast,您可以使用 mergeCasts
方法。這些 Cast 定義將被添加到模型上已定義的任何 Cast 中。
1$user->mergeCasts([2 'is_admin' => 'integer',3 'options' => 'object',4]);
null
的屬性將不會被 Cast。此外,您永遠不應定義與關聯關係同名的 Cast(或屬性),也不要將 Cast 指派給模型的主鍵。
Stringable Cast
您可以使用 Illuminate\Database\Eloquent\Casts\AsStringable
Cast 類別將模型屬性 Cast 為 fluent Illuminate\Support\Stringable
物件。
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Casts\AsStringable; 6use Illuminate\Database\Eloquent\Model; 7 8class User extends Model 9{10 /**11 * Get the attributes that should be cast.12 *13 * @return array<string, string>14 */15 protected function casts(): array16 {17 return [18 'directory' => AsStringable::class,19 ];20 }21}
陣列與 JSON Cast
當處理儲存為序列化 JSON 的欄位時,array
Cast 特別有用。例如,如果您的資料庫具有包含序列化 JSON 的 JSON
或 TEXT
欄位類型,則將 array
Cast 新增到該屬性將在您於 Eloquent 模型上訪問它時自動將該屬性反序列化為 PHP 陣列。
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Model; 6 7class User extends Model 8{ 9 /**10 * Get the attributes that should be cast.11 *12 * @return array<string, string>13 */14 protected function casts(): array15 {16 return [17 'options' => 'array',18 ];19 }20}
一旦定義了 Cast,您就可以訪問 options
屬性,它將自動從 JSON 反序列化為 PHP 陣列。當您設定 options
屬性的值時,給定的陣列將自動序列化回 JSON 以進行儲存。
1use App\Models\User; 2 3$user = User::find(1); 4 5$options = $user->options; 6 7$options['key'] = 'value'; 8 9$user->options = $options;10 11$user->save();
要使用更簡潔的語法更新 JSON 屬性的單個欄位,您可以使該屬性可大量賦值,並在呼叫 update
方法時使用 ->
運算子。
1$user = User::find(1);2 3$user->update(['options->key' => 'value']);
Array Object 和 Collection Cast
雖然標準的 array
Cast 對於許多應用程式來說已足夠,但它確實有一些缺點。由於 array
Cast 傳回原始類型,因此無法直接修改陣列的偏移量。例如,以下程式碼將觸發 PHP 錯誤:
1$user = User::find(1);2 3$user->options['key'] = $value;
為了解决此問題,Laravel 提供了 AsArrayObject
Cast,可將您的 JSON 屬性 Cast 為 ArrayObject 類別。此功能是使用 Laravel 的 自訂 Cast 實作來實作的,這允許 Laravel 智慧地快取和轉換修改後的物件,以便可以修改單個偏移量而不會觸發 PHP 錯誤。要使用 AsArrayObject
Cast,只需將其指派給一個屬性即可。
1use Illuminate\Database\Eloquent\Casts\AsArrayObject; 2 3/** 4 * Get the attributes that should be cast. 5 * 6 * @return array<string, string> 7 */ 8protected function casts(): array 9{10 return [11 'options' => AsArrayObject::class,12 ];13}
類似地,Laravel 提供了 AsCollection
Cast,可將您的 JSON 屬性 Cast 為 Laravel Collection 實例。
1use Illuminate\Database\Eloquent\Casts\AsCollection; 2 3/** 4 * Get the attributes that should be cast. 5 * 6 * @return array<string, string> 7 */ 8protected function casts(): array 9{10 return [11 'options' => AsCollection::class,12 ];13}
如果您希望 AsCollection
Cast 實例化自訂的 collection 類別而不是 Laravel 的基礎 collection 類別,您可以提供 collection 類別名稱作為 Cast 參數。
1use App\Collections\OptionCollection; 2use Illuminate\Database\Eloquent\Casts\AsCollection; 3 4/** 5 * Get the attributes that should be cast. 6 * 7 * @return array<string, string> 8 */ 9protected function casts(): array10{11 return [12 'options' => AsCollection::using(OptionCollection::class),13 ];14}
日期 Cast
預設情況下,Eloquent 會將 created_at
和 updated_at
欄位 Cast 為 Carbon 的實例,它擴展了 PHP DateTime
類別並提供了各種有用的方法。您可以透過在模型的 casts
方法中定義額外的日期 Cast 來 Cast 其他日期屬性。通常,日期應使用 datetime
或 immutable_datetime
Cast 類型來 Cast。
當定義 date
或 datetime
Cast 時,您還可以指定日期的格式。當模型序列化為陣列或 JSON時,將使用此格式。
1/** 2 * Get the attributes that should be cast. 3 * 4 * @return array<string, string> 5 */ 6protected function casts(): array 7{ 8 return [ 9 'created_at' => 'datetime:Y-m-d',10 ];11}
當欄位被 Cast 為日期時,您可以將對應的模型屬性值設定為 UNIX 時間戳記、日期字串 (Y-m-d
)、日期時間字串或 DateTime
/ Carbon
實例。日期的值將被正確轉換並儲存在您的資料庫中。
您可以透過在模型上定義 serializeDate
方法來自訂所有模型日期的預設序列化格式。此方法不會影響日期在資料庫中儲存時的格式。
1/**2 * Prepare a date for array / JSON serialization.3 */4protected function serializeDate(DateTimeInterface $date): string5{6 return $date->format('Y-m-d');7}
要指定實際在資料庫中儲存模型日期時應使用的格式,您應在模型上定義 $dateFormat
屬性。
1/**2 * The storage format of the model's date columns.3 *4 * @var string5 */6protected $dateFormat = 'U';
日期 Cast、序列化和時區
預設情況下,無論您的應用程式的 timezone
設定選項中指定的時區為何,date
和 datetime
Cast 都會將日期序列化為 UTC ISO-8601 日期字串 (YYYY-MM-DDTHH:MM:SS.uuuuuuZ
)。強烈建議您始終使用此序列化格式,並透過不將應用程式的 timezone
設定選項從其預設 UTC
值變更來將應用程式的日期儲存在 UTC 時區中。在整個應用程式中一致地使用 UTC 時區將為您提供與 PHP 和 JavaScript 中編寫的其他日期操作函式庫的最大互操作性。
如果自訂格式應用於 date
或 datetime
Cast,例如 datetime:Y-m-d H:i:s
,則在日期序列化期間將使用 Carbon 實例的內部時區。通常,這將是應用程式的 timezone
設定選項中指定的時區。但是,重要的是要注意,諸如 created_at
和 updated_at
之類的時間戳記欄位不受此行為的約束,並且始終以 UTC 格式格式化,而與應用程式的時區設定無關。
Enum Cast
Eloquent 還允許您將屬性值 Cast 為 PHP Enums。為了實現這一點,您可以在模型的 casts
方法中指定屬性和您希望 Cast 的 enum。
1use App\Enums\ServerStatus; 2 3/** 4 * Get the attributes that should be cast. 5 * 6 * @return array<string, string> 7 */ 8protected function casts(): array 9{10 return [11 'status' => ServerStatus::class,12 ];13}
一旦您在模型上定義了 Cast,當您與屬性交互時,指定的屬性將自動 Cast 為和從 enum Cast。
1if ($server->status == ServerStatus::Provisioned) {2 $server->status = ServerStatus::Ready;3 4 $server->save();5}
Cast Enum 陣列
有時您可能需要您的模型在單個欄位中儲存 enum 值陣列。為了實現這一點,您可以使用 Laravel 提供的 AsEnumArrayObject
或 AsEnumCollection
Cast。
1use App\Enums\ServerStatus; 2use Illuminate\Database\Eloquent\Casts\AsEnumCollection; 3 4/** 5 * Get the attributes that should be cast. 6 * 7 * @return array<string, string> 8 */ 9protected function casts(): array10{11 return [12 'statuses' => AsEnumCollection::of(ServerStatus::class),13 ];14}
加密 Cast
encrypted
Cast 將使用 Laravel 的內建加密功能來加密模型的屬性值。此外,encrypted:array
、encrypted:collection
、encrypted:object
、AsEncryptedArrayObject
和 AsEncryptedCollection
Cast 的工作方式與它們的未加密對應項類似;但是,正如您可能期望的那樣,底層值在儲存到資料庫中時會被加密。
由於加密文字的最終長度是不可預測的,並且比其純文字對應項更長,因此請確保關聯的資料庫欄位為 TEXT
類型或更大。此外,由於值在資料庫中被加密,因此您將無法查詢或搜尋加密的屬性值。
金鑰輪換
您可能知道,Laravel 使用您的應用程式 app
設定檔中指定的 key
設定值來加密字串。通常,此值對應於 APP_KEY
環境變數的值。如果您需要輪換應用程式的加密金鑰,則需要使用新金鑰手動重新加密您的加密屬性。
查詢時間 Cast
有時您可能需要在執行查詢時應用 Cast,例如當從表格中選擇原始值時。例如,考慮以下查詢:
1use App\Models\Post;2use App\Models\User;3 4$users = User::select([5 'users.*',6 'last_posted_at' => Post::selectRaw('MAX(created_at)')7 ->whereColumn('user_id', 'users.id')8])->get();
此查詢結果中的 last_posted_at
屬性將是一個簡單的字串。如果我們可以在執行查詢時將 datetime
Cast 應用於此屬性,那就太好了。值得慶幸的是,我們可以使用 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();
自訂 Cast
Laravel 有各種內建的、有用的 Cast 類型;但是,您有時可能需要定義自己的 Cast 類型。要建立 Cast,請執行 make:cast
Artisan 命令。新的 Cast 類別將放置在您的 app/Casts
目錄中。
1php artisan make:cast Json
所有自訂 Cast 類別都實作 CastsAttributes
介面。實作此介面的類別必須定義 get
和 set
方法。 get
方法負責將來自資料庫的原始值轉換為 Cast 值,而 set
方法應將 Cast 值轉換為可以儲存在資料庫中的原始值。作為範例,我們將重新實作內建的 json
Cast 類型作為自訂 Cast 類型。
1<?php 2 3namespace App\Casts; 4 5use Illuminate\Contracts\Database\Eloquent\CastsAttributes; 6use Illuminate\Database\Eloquent\Model; 7 8class Json implements CastsAttributes 9{10 /**11 * Cast the given value.12 *13 * @param array<string, mixed> $attributes14 * @return array<string, mixed>15 */16 public function get(Model $model, string $key, mixed $value, array $attributes): array17 {18 return json_decode($value, true);19 }20 21 /**22 * Prepare the given value for storage.23 *24 * @param array<string, mixed> $attributes25 */26 public function set(Model $model, string $key, mixed $value, array $attributes): string27 {28 return json_encode($value);29 }30}
一旦您定義了自訂 Cast 類型,您就可以使用其類別名稱將其附加到模型屬性。
1<?php 2 3namespace App\Models; 4 5use App\Casts\Json; 6use Illuminate\Database\Eloquent\Model; 7 8class User extends Model 9{10 /**11 * Get the attributes that should be cast.12 *13 * @return array<string, string>14 */15 protected function casts(): array16 {17 return [18 'options' => Json::class,19 ];20 }21}
Value Object Cast
您不僅限於將值 Cast 為原始類型。您也可以將值 Cast 為物件。定義將值 Cast 為物件的自訂 Cast 與 Cast 為原始類型非常相似;但是,set
方法應傳回鍵 / 值對的陣列,該陣列將用於在模型上設定原始的可儲存值。
作為範例,我們將定義一個自訂 Cast 類別,將多個模型值 Cast 為單個 Address
value object。我們將假設 Address
value object 具有兩個 public 屬性:lineOne
和 lineTwo
。
1<?php 2 3namespace App\Casts; 4 5use App\ValueObjects\Address as AddressValueObject; 6use Illuminate\Contracts\Database\Eloquent\CastsAttributes; 7use Illuminate\Database\Eloquent\Model; 8use InvalidArgumentException; 9 10class Address implements CastsAttributes11{12 /**13 * Cast the given value.14 *15 * @param array<string, mixed> $attributes16 */17 public function get(Model $model, string $key, mixed $value, array $attributes): AddressValueObject18 {19 return new AddressValueObject(20 $attributes['address_line_one'],21 $attributes['address_line_two']22 );23 }24 25 /**26 * Prepare the given value for storage.27 *28 * @param array<string, mixed> $attributes29 * @return array<string, string>30 */31 public function set(Model $model, string $key, mixed $value, array $attributes): array32 {33 if (! $value instanceof AddressValueObject) {34 throw new InvalidArgumentException('The given value is not an Address instance.');35 }36 37 return [38 'address_line_one' => $value->lineOne,39 'address_line_two' => $value->lineTwo,40 ];41 }42}
當 Cast 為 value objects 時,對 value object 所做的任何變更都將在模型儲存之前自動同步回模型。
1use App\Models\User;2 3$user = User::find(1);4 5$user->address->lineOne = 'Updated Address Value';6 7$user->save();
如果您計劃將包含 value objects 的 Eloquent 模型序列化為 JSON 或陣列,則應在 value object 上實作 Illuminate\Contracts\Support\Arrayable
和 JsonSerializable
介面。
Value Object 快取
當解析 Cast 為 value objects 的屬性時,Eloquent 會快取它們。因此,如果再次訪問該屬性,將傳回相同的物件實例。
如果您想停用自訂 Cast 類別的物件快取行為,您可以在自訂 Cast 類別上宣告 public withoutObjectCaching
屬性。
1class Address implements CastsAttributes2{3 public bool $withoutObjectCaching = true;4 5 // ...6}
陣列 / JSON 序列化
當使用 toArray
和 toJson
方法將 Eloquent 模型轉換為陣列或 JSON 時,您的自訂 Cast value objects 通常也會被序列化,只要它們實作了 Illuminate\Contracts\Support\Arrayable
和 JsonSerializable
介面。但是,當使用第三方函式庫提供的 value objects 時,您可能無法將這些介面添加到物件中。
因此,您可以指定您的自訂 Cast 類別將負責序列化 value object。為此,您的自訂 Cast 類別應實作 Illuminate\Contracts\Database\Eloquent\SerializesCastableAttributes
介面。此介面指出您的類別應包含一個 serialize
方法,該方法應傳回 value object 的序列化形式。
1/**2 * Get the serialized representation of the value.3 *4 * @param array<string, mixed> $attributes5 */6public function serialize(Model $model, string $key, mixed $value, array $attributes): string7{8 return (string) $value;9}
Inbound Cast
有時,您可能需要編寫一個自訂 Cast 類別,該類別僅轉換正在模型上設定的值,並且在從模型檢索屬性時不執行任何操作。
Inbound 僅限的自訂 Cast 應實作 CastsInboundAttributes
介面,該介面僅需要定義 set
方法。可以使用 --inbound
選項調用 make:cast
Artisan 命令來產生僅限 inbound 的 Cast 類別。
1php artisan make:cast Hash --inbound
Inbound 僅限 Cast 的經典範例是「雜湊」Cast。例如,我們可以定義一個 Cast,透過給定的演算法雜湊 inbound 值。
1<?php 2 3namespace App\Casts; 4 5use Illuminate\Contracts\Database\Eloquent\CastsInboundAttributes; 6use Illuminate\Database\Eloquent\Model; 7 8class Hash implements CastsInboundAttributes 9{10 /**11 * Create a new cast class instance.12 */13 public function __construct(14 protected string|null $algorithm = null,15 ) {}16 17 /**18 * Prepare the given value for storage.19 *20 * @param array<string, mixed> $attributes21 */22 public function set(Model $model, string $key, mixed $value, array $attributes): string23 {24 return is_null($this->algorithm)25 ? bcrypt($value)26 : hash($this->algorithm, $value);27 }28}
Cast 參數
當將自訂 Cast 附加到模型時,可以透過使用 :
字元將 Cast 參數與類別名稱分隔開來指定 Cast 參數,並以逗號分隔多個參數。這些參數將傳遞給 Cast 類別的建構子。
1/** 2 * Get the attributes that should be cast. 3 * 4 * @return array<string, string> 5 */ 6protected function casts(): array 7{ 8 return [ 9 'secret' => Hash::class.':sha256',10 ];11}
Castables
您可能希望允許應用程式的 value objects 定義它們自己的自訂 Cast 類別。您可以選擇附加實作 Illuminate\Contracts\Database\Eloquent\Castable
介面的 value object 類別,而不是將自訂 Cast 類別附加到您的模型。
1use App\ValueObjects\Address;2 3protected function casts(): array4{5 return [6 'address' => Address::class,7 ];8}
實作 Castable
介面的物件必須定義一個 castUsing
方法,該方法傳回負責 Cast 為和從 Castable
類別 Cast 的自訂 caster 類別的類別名稱。
1<?php 2 3namespace App\ValueObjects; 4 5use Illuminate\Contracts\Database\Eloquent\Castable; 6use App\Casts\Address as AddressCast; 7 8class Address implements Castable 9{10 /**11 * Get the name of the caster class to use when casting from / to this cast target.12 *13 * @param array<string, mixed> $arguments14 */15 public static function castUsing(array $arguments): string16 {17 return AddressCast::class;18 }19}
當使用 Castable
類別時,您仍然可以在 casts
方法定義中提供參數。這些參數將傳遞給 castUsing
方法。
1use App\ValueObjects\Address;2 3protected function casts(): array4{5 return [6 'address' => Address::class.':argument',7 ];8}
Castables & 匿名 Cast 類別
透過將「castables」與 PHP 的 匿名類別 結合使用,您可以將 value object 及其 Cast 邏輯定義為單個 castable 物件。為了實現這一點,請從 value object 的 castUsing
方法傳回一個匿名類別。匿名類別應實作 CastsAttributes
介面。
1<?php 2 3namespace App\ValueObjects; 4 5use Illuminate\Contracts\Database\Eloquent\Castable; 6use Illuminate\Contracts\Database\Eloquent\CastsAttributes; 7 8class Address implements Castable 9{10 // ...11 12 /**13 * Get the caster class to use when casting from / to this cast target.14 *15 * @param array<string, mixed> $arguments16 */17 public static function castUsing(array $arguments): CastsAttributes18 {19 return new class implements CastsAttributes20 {21 public function get(Model $model, string $key, mixed $value, array $attributes): Address22 {23 return new Address(24 $attributes['address_line_one'],25 $attributes['address_line_two']26 );27 }28 29 public function set(Model $model, string $key, mixed $value, array $attributes): array30 {31 return [32 'address_line_one' => $value->lineOne,33 'address_line_two' => $value->lineTwo,34 ];35 }36 };37 }38}