نسخه:

Floquent: Mutators & Casting

معرفی

لوازم جانبی، جهش‌دهنده‌ها و ریخته‌گری ویژگی به شما امکان می‌دهند تا مقادیر ویژگی Eloquent را هنگام بازیابی یا تنظیم آن‌ها در نمونه‌های مدل تغییر دهید. به عنوان مثال، ممکن است بخواهید از رمزگذار لاراول برای رمزگذاری یک مقدار در زمانی که در پایگاه داده ذخیره می شود، استفاده کنید، و سپس زمانی که به آن در مدل Eloquent دسترسی پیدا می کنید، ویژگی را به طور خودکار رمزگشایی کنید. یا، ممکن است بخواهید یک رشته JSON را که در پایگاه داده شما ذخیره می شود، زمانی که از طریق مدل Eloquent شما قابل دسترسی است، به یک آرایه تبدیل کنید.

Accessors و Mutators

تعریف Accessor

هنگامی که یک Accessor به یک مقدار مشخصه Eloquent دسترسی پیدا می کند، تبدیل می کند. برای تعریف یک Accessor، یک متد محافظت شده در مدل خود ایجاد کنید تا ویژگی قابل دسترسی را نشان دهد. این نام روش باید مطابق با نمایش "camel case" از ویژگی اصلی مدل / ستون پایگاه داده در صورت لزوم باشد.

در این مثال، یک Accessor برای ویژگی تعریف می کنیم first_name . هنگام تلاش برای بازیابی مقدار مشخصه، Accessor به طور خودکار توسط Eloquent فراخوانی می شود first_name . همه متدهای Accessor/mutator ویژگی باید نوع بازگشتی را اعلام کنند 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 نمونه ای را برمی گردانند که نحوه دسترسی به ویژگی و در صورت تمایل، جهش را مشخص می کند. در این مثال، ما فقط نحوه دسترسی به ویژگی را تعریف می کنیم. برای انجام این کار، get آرگومان را به Attribute سازنده کلاس ارائه می کنیم.

همانطور که می بینید، مقدار اصلی ستون به Accessor ارسال می شود و به شما امکان می دهد مقدار را دستکاری و برگردانید. برای دسترسی به مقدار Accessor، می‌توانید به سادگی به 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 نمونه های بازگردانده شده توسط Accessor ها را حفظ می کند تا بتواند هر بار که Accessor فراخوانی می شود همان نمونه را برگرداند:

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 در هنگام تعریف Accessor خود از روش استفاده کنید:

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 را هنگامی که تنظیم می شود تبدیل می کند. برای تعریف یک mutator، ممکن است set هنگام تعریف ویژگی خود، آرگومان را ارائه دهید. بیایید یک mutator برای 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),
);
}
}

بسته شدن mutator مقداری را که روی ویژگی تنظیم شده است دریافت می کند و به شما امکان می دهد مقدار را دستکاری کنید و مقدار دستکاری شده را برگردانید. برای استفاده از mutator خود، فقط باید first_name ویژگی را روی یک مدل Eloquent تنظیم کنیم:

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

در این مثال، set callback با مقدار Sally . سپس mutator 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

برای نشان دادن ریختن ویژگی، اجازه دهید is_admin ویژگی را که در پایگاه داده ما به عنوان یک عدد صحیح ( 0 یا 1 ) ذخیره می‌شود به یک مقدار بولی تبدیل کنیم:

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

پس از تعریف cast، is_admin مشخصه همیشه هنگام دسترسی به آن به یک Boolean فرستاده می شود، حتی اگر مقدار اساسی در پایگاه داده به عنوان یک عدد صحیح ذخیره شود:

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

اگر نیاز به اضافه کردن یک بازیگر جدید و موقت در زمان اجرا دارید، می‌توانید از این mergeCasts روش استفاده کنید. این تعاریف بازیگری به هر یک از بازیگرانی که قبلاً در مدل تعریف شده اند اضافه می شوند:

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

ویژگی‌هایی که هستند null پخش نمی‌شوند. علاوه بر این، هرگز نباید یک cast (یا یک ویژگی) که نام یک رابطه را دارد تعریف کنید یا یک cast را به کلید اصلی مدل اختصاص دهید.

ریخته گری رشته ای

می توانید از Illuminate\Database\Eloquent\Casts\AsStringable کلاس cast برای فرستادن یک ویژگی مدل به یک شی روان Illuminate\Support\Stringable استفاده کنید :

<?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 یا TEXT نوع فیلد است که حاوی JSON سریالی است، افزودن array cast به آن ویژگی، هنگامی که در مدل 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',
];
}
}

هنگامی که cast تعریف شد، می توانید به 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 cast یک نوع اولیه را برمی گرداند، امکان جهش مستقیم افست آرایه وجود ندارد. به عنوان مثال، کد زیر یک خطای PHP ایجاد می کند:

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

برای حل این مشکل، لاراول یک AsArrayObject cast ارائه می دهد که ویژگی JSON شما را به یک کلاس ArrayObject می فرستد . این ویژگی با استفاده از پیاده‌سازی کست سفارشی لاراول پیاده‌سازی می‌شود ، که به لاراول اجازه می‌دهد تا به‌طور هوشمند شی جهش‌یافته را کش و تبدیل کند به طوری که ممکن است افست‌های فردی بدون ایجاد خطای PHP اصلاح شوند. برای استفاده از AsArrayObject Cast، به سادگی آن را به یک ویژگی اختصاص دهید:

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

به طور مشابه، لاراول AsCollection بازیگری را ارائه می‌کند که ویژگی JSON شما را به نمونه‌ای از مجموعه لاراول می‌فرستد :

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 بازیگران به جای کلاس مجموعه پایه لاراول، یک کلاس مجموعه سفارشی را نمونه سازی کنند، می توانید نام کلاس مجموعه را به عنوان آرگومان cast ارائه کنید:

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

ریخته گری تاریخ

created_at به‌طور پیش‌فرض، Eloquent ستون‌ها و 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',
];
}

هنگامی که یک ستون به عنوان تاریخ فرستاده می شود، می توانید مقدار ویژگی مدل مربوطه را به یک مهر زمانی یونیکس، رشته تاریخ ( 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 شما قویاً تشویق می‌شوید همیشه از این قالب سریال‌سازی استفاده کنید، و همچنین با تغییر ندادن timezone گزینه پیکربندی برنامه خود از مقدار پیش‌فرض، تاریخ‌های برنامه خود را در منطقه زمانی UTC ذخیره کنید UTC . استفاده مداوم از منطقه زمانی UTC در سراسر برنامه، حداکثر سطح همکاری را با سایر کتابخانه های دستکاری تاریخ نوشته شده در PHP و جاوا اسکریپت فراهم می کند.

date اگر یک قالب سفارشی برای پخش یا بازیگران اعمال شود datetime ، مانند datetime:Y-m-d H:i:s , منطقه زمانی داخلی نمونه کربن در طول سریال‌سازی تاریخ استفاده می‌شود. به طور معمول، این منطقه زمانی مشخص شده در timezone گزینه پیکربندی برنامه شما خواهد بود .

Enum Casting

Eloquent همچنین به شما این امکان را می دهد که مقادیر ویژگی خود را به Enums PHP ارسال کنید . برای انجام این کار، می‌توانید ویژگی و شماره‌ای را که می‌خواهید در casts متد مدل خود اعمال کنید، مشخص کنید:

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

هنگامی که cast را روی مدل خود تعریف کردید، هنگامی که با ویژگی تعامل می کنید، ویژگی مشخص شده به طور خودکار به و از یک enum فرستاده می شود:

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

ریخته گری آرایه های Enums

گاهی اوقات ممکن است به مدل خود نیاز داشته باشید که آرایه ای از مقادیر enum را در یک ستون ذخیره کند. برای انجام این کار، می توانید از 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 مقدار ویژگی مدل را با استفاده از ویژگی‌های رمزگذاری داخلی لاراول رمزگذاری می‌کنند . علاوه بر این encrypted:array ، encrypted:collection , encrypted:object , AsEncryptedArrayObject , و AsEncryptedCollection بازیگران مانند همتایان رمزگذاری نشده خود کار می کنند. با این حال، همانطور که ممکن است انتظار داشته باشید، ارزش اساسی زمانی که در پایگاه داده شما ذخیره می شود رمزگذاری می شود.

از آنجایی که طول نهایی متن رمزگذاری شده قابل پیش بینی نیست و طولانی تر از متن ساده آن است، مطمئن شوید که ستون پایگاه داده مرتبط از TEXT نوع یا بزرگتر باشد. علاوه بر این، از آنجایی که مقادیر در پایگاه داده رمزگذاری شده اند، نمی توانید مقادیر ویژگی رمزگذاری شده را جستجو یا جستجو کنید.

چرخش کلید

همانطور که می دانید، لاراول رشته ها را با استفاده از key مقدار پیکربندی مشخص شده در فایل پیکربندی برنامه شما رمزگذاری می کند app . به طور معمول، این مقدار با مقدار APP_KEY متغیر محیطی مطابقت دارد. اگر نیاز دارید کلید رمزگذاری برنامه خود را بچرخانید، باید به صورت دستی ویژگی های رمزگذاری شده خود را با استفاده از کلید جدید رمزگذاری مجدد کنید.

ارسال زمان پرس و جو

گاهی اوقات ممکن است لازم باشد هنگام اجرای یک پرس و جو، از جمله زمانی که یک مقدار خام را از جدول انتخاب می کنید، Casts را اعمال کنید. به عنوان مثال، پرس و جو زیر را در نظر بگیرید:

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 هنگام اجرای پرس و جو، یک cast برای این ویژگی اعمال کنیم، فوق العاده خواهد بود. خوشبختانه، ممکن است با استفاده از روش زیر این کار را انجام دهیم withCasts :

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

بازیگران سفارشی

لاراول انواع مختلفی از بازیگران داخلی و مفید دارد. با این حال، ممکن است گاهی لازم باشد انواع بازیگران خود را تعریف کنید. برای ایجاد یک بازیگر، make:cast دستور Artisan را اجرا کنید. کلاس بازیگران جدید در app/Casts دایرکتوری شما قرار می گیرد:

php artisan make:cast Json

تمام کلاس‌های کست سفارشی CastsAttributes رابط را پیاده‌سازی می‌کنند. کلاس هایی که این رابط را پیاده سازی می کنند باید a 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);
}
}

هنگامی که یک نوع Cast سفارشی را تعریف کردید، می توانید آن را با استفاده از نام کلاس آن به یک ویژگی مدل متصل کنید:

<?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 روش باید آرایه‌ای از جفت‌های کلید/مقدار را برگرداند که برای تنظیم مقادیر خام و قابل ذخیره‌سازی در مدل استفاده می‌شود.

به عنوان مثال، ما یک کلاس cast سفارشی تعریف می کنیم که چندین مقدار مدل را به یک Address شی مقدار واحد می ریزد. فرض می کنیم Address مقدار دارای دو ویژگی عمومی است: lineOne و lineTwo :

<?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 and JsonSerializable را روی شی مقدار پیاده‌سازی کنید.

مقدار ذخیره شی

هنگامی که ویژگی هایی که به اشیاء ارزشی داده می شوند حل و فصل می شوند، توسط Eloquent ذخیره می شوند. بنابراین، در صورت دسترسی مجدد به ویژگی، همان نمونه شی برگردانده می شود.

اگر می‌خواهید رفتار ذخیره‌سازی شی در کلاس‌های Cast سفارشی را غیرفعال کنید، می‌توانید یک withoutObjectCaching ویژگی عمومی در کلاس Cast سفارشی خود اعلام کنید:

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

سریال سازی آرایه / JSON

هنگامی که یک مدل Eloquent با استفاده از متدهای toArray و به toJson آرایه یا JSON تبدیل می‌شود، اشیاء با ارزش ریخته‌شده سفارشی شما معمولاً تا زمانی که واسط‌ها Illuminate\Contracts\Support\Arrayable و را پیاده‌سازی می‌کنند، سریال‌سازی می‌شوند JsonSerializable . با این حال، هنگام استفاده از اشیاء ارزش ارائه شده توسط کتابخانه های شخص ثالث، ممکن است توانایی اضافه کردن این رابط ها به شی را نداشته باشید.

بنابراین، می‌توانید تعیین کنید که کلاس cast سفارشی شما مسئول سریال‌سازی شی مقدار باشد. برای انجام این کار، کلاس cast سفارشی شما باید 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;
}

ریخته گری ورودی

گاهی اوقات، ممکن است نیاز داشته باشید که یک کلاس cast سفارشی بنویسید که فقط مقادیری را که روی مدل تنظیم می‌شوند تبدیل می‌کند و هیچ عملیاتی را هنگام بازیابی ویژگی‌ها از مدل انجام نمی‌دهد.

کست‌های سفارشی فقط ورودی باید CastsInboundAttributes رابط را پیاده‌سازی کنند، که فقط به یک set روش نیاز دارد تا تعریف شود. دستور Artisan ممکن است با گزینه ای برای ایجاد یک کلاس cast فقط ورودی make:cast فراخوانی شود : --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);
}
}

پارامترهای بازیگری

هنگام پیوست کردن یک Cast سفارشی به یک مدل، پارامترهای Cast ممکن است با جدا کردن آنها از نام کلاس با استفاده از یک : کاراکتر و تعیین چند پارامتر با کاما مشخص شوند. پارامترها به سازنده کلاس cast ارسال می شود:

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

ریخته گری

ممکن است بخواهید به اشیاء ارزش برنامه خود اجازه دهید تا کلاس های Cast سفارشی خود را تعریف کنند. به جای اینکه کلاس cast سفارشی را به مدل خود وصل کنید، می‌توانید یک کلاس شیء ارزش را که Illuminate\Contracts\Database\Eloquent\Castable رابط را پیاده‌سازی می‌کند، پیوست کنید:

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

اشیایی که Castable اینترفیس را پیاده سازی می کنند باید castUsing متدی را تعریف کنند که نام کلاس کلاس caster سفارشی که مسئول ارسال به کلاس و از Castable کلاس است را برمی گرداند:

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

کلاس‌های بازیگران Castable و ناشناس

با ترکیب «castables» با کلاس‌های ناشناس PHP ، می‌توانید یک شی مقدار و منطق ریخته‌گری آن را به‌عنوان یک شیء کست‌پذیر منفرد تعریف کنید. برای انجام این کار، یک کلاس ناشناس را از متد آبجکت مقدار خود برگردانید castUsing . کلاس ناشناس باید 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,
];
}
};
}
}