1. Eloquent ORM
  2. Eloquent: Мутаторы и кастинг

Введение

Аксессоры, мутаторы и приведение атрибутов позволяют вам преобразовывать значения атрибутов Eloquent при их получении или установке на экземпляры модели. Например, вы можете использовать шифровщик Laravel, чтобы шифровать значение во время его хранения в базе данных, а затем автоматически дешифровать атрибут при доступе к нему через модель Eloquent. Или вы можете преобразовать JSON-строку, хранящуюся в вашей базе данных, в массив при ее доступе через вашу модель Eloquent.

Аксессоры и мутаторы

Определение аксессора

Аксессор преобразует значение атрибута Eloquent при его доступе. Чтобы определить аксессор, создайте защищенный метод в вашей модели для представления доступного атрибута. Имя этого метода должно соответствовать "camel case" представлению истинного базового атрибута модели / столбца базы данных, когда это применимо.

В этом примере мы определим аксессор для атрибута first_name. Аксессор будет автоматически вызван Eloquent при попытке получения значения атрибута first_name. Все методы аксессоров / мутаторов атрибутов должны объявлять тип возврата Illuminate\Database\Eloquent\Casts\Attribute:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Получить имя пользователя.
*/
protected function firstName(): Attribute
{
return Attribute::make(
get: fn (string $value) => ucfirst($value),
);
}
}

Все методы аксессоров возвращают экземпляр Attribute, который определяет, как будет осуществлен доступ к атрибуту и, при необходимости, его изменение. В этом примере мы определяем только, как будет осуществлен доступ к атрибуту. Для этого мы предоставляем аргумент get конструктору класса Attribute.

Как видите, исходное значение колонки передается аксессору, позволяя вам манипулировать и возвращать значение. Чтобы получить доступ к значению аксессора, вы можете просто обратиться к атрибуту 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;
/**
* Взаимодействует с адресом пользователя.
*/
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 при определении атрибута:

/**
* Взаимодействует с адресом пользователя.
*/
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
{
/**
* Взаимодействует с именем пользователя.
*/
protected function firstName(): Attribute
{
return Attribute::make(
get: fn (string $value) => ucfirst($value),
set: fn (string $value) => strtolower($value),
);
}
}

Замыкание мутатора получит значение, которое устанавливается в атрибут, что позволяет вам манипулировать значением и возвращать измененное значение. Чтобы использовать наш мутатор, нам нужно всего лишь установить атрибут first_name в модели Eloquent:

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;
/**
* Взаимодействует с адресом пользователя.
*/
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), к значению boolean:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Атрибуты, которые должны быть приведены.
*
* @var array
*/
protected $casts = [
'is_admin' => 'boolean',
];
}

После определения каста, атрибут is_admin будет всегда приведен к boolean при его доступе, даже если базовое значение хранится в базе данных как целое число:

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

Если вам нужно добавить новый временный каст во время выполнения, вы можете использовать метод mergeCasts. Эти определения кастов будут добавлены к любым уже определенным на модели кастам:

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

Внимание Атрибуты со значением null не будут приведены. Кроме того, никогда не стоит определять каст (или атрибут) с тем же именем, что и у отношения, или присваивать каст первичному ключу модели.

Приведение к строке

Вы можете использовать класс приведения Illuminate\Database\Eloquent\Casts\AsStringable, чтобы привести атрибут модели к объекту строки Illuminate\Support\Stringable:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Casts\AsStringable;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Атрибуты, которые должны быть приведены.
*
* @var array
*/
protected $casts = [
'directory' => AsStringable::class,
];
}

Кастовые массива и JSON

Приведение к типу array особенно полезно при работе с колонками, хранящимися в виде сериализованного JSON. Например, если ваша база данных имеет тип поля JSON или TEXT, содержащего сериализованный JSON, добавление приведения к типу array к этому атрибуту автоматически десериализует атрибут в PHP-массив при его доступе в вашей модели Eloquent:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Атрибуты, которые должны быть приведены.
*
* @var array
*/
protected $casts = [
'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 предлагает каст AsArrayObject, который приводит ваш атрибут JSON к классу ArrayObject. Эта функция реализована с использованием механизма пользовательских кастов Laravel, что позволяет Laravel интеллектуально кэшировать и трансформировать мутированный объект так, чтобы можно было изменять отдельные смещения без вызова ошибки PHP. Чтобы использовать каст AsArrayObject, просто назначьте его атрибуту:

use Illuminate\Database\Eloquent\Casts\AsArrayObject;
/**
* Атрибуты, которые должны быть приведены.
*
* @var array
*/
protected $casts = [
'options' => AsArrayObject::class,
];

Точно так же Laravel предлагает каст AsCollection, который приводит ваш атрибут JSON к экземпляру Laravel Collection:

use Illuminate\Database\Eloquent\Casts\AsCollection;
/**
* Атрибуты, которые должны быть приведены.
*
* @var array
*/
protected $casts = [
'options' => AsCollection::class,
];

Если вы хотите, чтобы каст AsCollection создавал экземпляр пользовательского класса коллекции вместо базового класса коллекции Laravel, вы можете предоставить имя класса коллекции в качестве аргумента каста:

use App\Collections\OptionCollection;
use Illuminate\Database\Eloquent\Casts\AsCollection;
/**
* Атрибуты, которые должны быть приведены.
*
* @var array
*/
protected $casts = [
'options' => AsCollection::class.':'.OptionCollection::class,
];

Приведение даты

По умолчанию Eloquent будет приводить столбцы created_at и updated_at к экземплярам Carbon, который расширяет класс PHP DateTime и предоставляет ассортимент полезных методов. Вы можете приводить дополнительные атрибуты дат, определяя дополнительные касты дат в массиве свойства $casts вашей модели. Обычно даты следует приводить с использованием типов datetime или immutable_datetime.

При определении каста date или datetime вы также можете указать формат даты. Этот формат будет использоваться, когда модель сериализуется в массив или JSON:

/**
* Атрибуты, которые должны быть приведены.
*
* @var array
*/
protected $casts = [
'created_at' => 'datetime:Y-m-d',
];

Когда столбец приводится к типу дата, вы можете установить значение соответствующего атрибута модели в метку времени UNIX, строку даты (Y-m-d), строку даты и времени или экземпляр DateTime / Carbon. Значение даты будет правильно преобразовано и сохранено в вашей базе данных.

Вы можете настроить формат сериализации по умолчанию для всех дат вашей модели, определив метод serializeDate в вашей модели. Этот метод не влияет на форматирование ваших дат для хранения в базе данных:

/**
* Подготавливает дату для сериализации в массив / JSON.
*/
protected function serializeDate(DateTimeInterface $date): string
{
return $date->format('Y-m-d');
}

Чтобы указать формат, который следует использовать при хранении фактических дат модели в вашей базе данных, вы должны определить свойство $dateFormat в вашей модели:

/**
* Формат хранения столбцов даты модели.
*
* @var string
*/
protected $dateFormat = 'U';

Приведение, сериализация и часовые пояса для дат

По умолчанию касты date и datetime сериализуют даты в UTC строку даты в формате ISO-8601 (YYYY-MM-DDTHH:MM:SS.uuuuuuZ), независимо от часового пояса, указанного в опции конфигурации часового пояса вашего приложения. Вам настоятельно рекомендуется всегда использовать этот формат сериализации, а также хранить даты вашего приложения в часовом поясе UTC, не изменяя опцию конфигурации часового пояса вашего приложения с ее значения по умолчанию UTC. Постоянное использование часового пояса UTC в вашем приложении обеспечит максимальный уровень совместимости с другими библиотеками для работы с датами на PHP и JavaScript.

Если применен пользовательский формат к касту date или datetime, например, datetime:Y-m-d H:i:s, во время сериализации даты будет использоваться внутренний часовой пояс экземпляра Carbon. Обычно это будет часовой пояс, указанный в опции конфигурации часового пояса вашего приложения.

Приведение Enum

Eloquent также позволяет приводить значения ваших атрибутов к перечислениям PHP. Для этого вы можете указать атрибут и перечисление, которое вы хотите привести, в массиве свойства $casts вашей модели:

use App\Enums\ServerStatus;
/**
* Атрибуты, которые должны быть приведены.
*
* @var array
*/
protected $casts = [
'status' => ServerStatus::class,
];

После определения каста в вашей модели указанный атрибут будет автоматически приведен к перечислению и обратно при взаимодействии с атрибутом:

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

Кастинг массивов Enum

Иногда вам может понадобиться, чтобы ваша модель хранила массив значений перечисления в одной колонке. Для этого вы можете использовать касты AsEnumArrayObject или AsEnumCollection, предоставленные Laravel:

use App\Enums\ServerStatus;
use Illuminate\Database\Eloquent\Casts\AsEnumCollection;
/**
* Атрибуты, которые должны быть приведены.
*
* @var array
*/
protected $casts = [
'statuses' => AsEnumCollection::class.':'.ServerStatus::class,
];

Шифрованное приведение

Каст encrypted будет шифровать значение атрибута модели с использованием встроенных средств шифрования Laravel. Кроме того, касты encrypted:array, encrypted:collection, encrypted:object, AsEncryptedArrayObject и AsEncryptedCollection работают так же, как и их незашифрованные аналоги; однако, как вы могли бы ожидать, базовое значение шифруется при сохранении в вашей базе данных.

Поскольку окончательная длина зашифрованного текста непредсказуема и длиннее, чем соответствующий текст в открытом виде, убедитесь, что связанная колонка базы данных имеет тип TEXT или больше. Кроме того, поскольку значения шифруются в базе данных, вы не сможете выполнять запросы или поиск значений зашифрованных атрибутов.

Ротация ключей

Как вы можете знать, Laravel шифрует строки, используя значение конфигурации key, указанное в файле конфигурации app вашего приложения. Обычно это значение соответствует значению переменной окружения 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 есть различные встроенные и полезные типы кастов; однако иногда вам может потребоваться определить свои собственные типы кастов. Чтобы создать каст, выполните команду Artisan make:cast. Новый класс каста будет размещен в вашем каталоге 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
{
/**
* Привести заданное значение.
*
* @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);
}
/**
* Подготовить заданное значение для хранения.
*
* @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
{
/**
* Атрибуты, которые должны быть приведены.
*
* @var array
*/
protected $casts = [
'options' => Json::class,
];
}

Приведение объектов значений

Вы не ограничены приведением значений к примитивным типам. Вы также можете приводить значения к объектам. Определение пользовательских кастов, которые приводят значения к объектам, очень похоже на приведение к примитивным типам; однако метод set должен возвращать массив пар ключ / значение, который будет использоваться для установки сырых, хранимых значений в модели.

В качестве примера определим пользовательский класс каста, который приводит несколько значений модели в один объект значения 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
{
/**
* Привести заданное значение.
*
* @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']
);
}
/**
* Подготовить заданное значение для хранения.
*
* @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 в массив или JSON с использованием методов toArray и toJson ваши объекты значений пользовательских кастов обычно также будут сериализованы, если они реализуют интерфейсы Illuminate\Contracts\Support\Arrayable и JsonSerializable. Однако при использовании объектов значений, предоставленных библиотеками сторонних разработчиков, у вас может не быть возможности добавить эти интерфейсы к объекту.

Поэтому вы можете указать, что ваш пользовательский класс каста будет отвечать за сериализацию объекта значения. Для этого ваш пользовательский класс каста должен реализовать интерфейс Illuminate\Contracts\Database\Eloquent\SerializesCastableAttributes. В этом интерфейсе указано, что ваш класс должен содержать метод serialize, который должен возвращать сериализованную форму вашего объекта значения:

/**
* Получить сериализованное представление значения.
*
* @param array<string, mixed> $attributes
*/
public function serialize(Model $model, string $key, mixed $value, array $attributes): string
{
return (string) $value;
}

Входящее приведение

Временами вам может потребоваться написать пользовательский класс каста, который преобразует только те значения, которые устанавливаются в модели, и не выполняет никаких операций при получении атрибутов из модели.

В кастах, применяемых только входящим образом, должен реализовываться интерфейс CastsInboundAttributes, который требует только определения метода set. Команду Artisan 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
{
/**
* Создать новый экземпляр класса каста.
*/
public function __construct(
protected string|null $algorithm = null,
) {}
/**
* Подготовить заданное значение для хранения.
*
* @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);
}
}

Параметры кастинга

При присоединении пользовательского класса каста к модели можно указать параметры каста, разделяя их от имени класса с использованием символа : и разделяя несколько параметров запятой. Параметры будут переданы в конструктор класса каста:

/**
* Атрибуты, которые должны быть приведены.
*
* @var array
*/
protected $casts = [
'secret' => Hash::class.':sha256',
];

Кастовые

Вы можете разрешить вашим объектам значения приложения определять свои собственные классы пользовательских кастов. Вместо присоединения пользовательского класса каста к вашей модели вы можете альтернативно присоединить класс объекта значения, который реализует интерфейс Illuminate\Contracts\Database\Eloquent\Castable:

use App\Models\Address;
 
protected $casts = [
'address' => Address::class,
];

Объекты, реализующие интерфейс Castable, должны определять метод castUsing, который возвращает имя класса пользовательского кастера, ответственного за приведение класса каста и из него, в класс Castable:

<?php
namespace App\Models;
use Illuminate\Contracts\Database\Eloquent\Castable;
use App\Casts\Address as AddressCast;
class Address implements Castable
{
/**
* Получить имя класса кастера для использования при кастинге в/из этой целевой модели.
*
* @param array<string, mixed> $arguments
*/
public static function castUsing(array $arguments): string
{
return AddressCast::class;
}
}

При использовании классов Castable вы все равно можете предоставлять аргументы в определении $casts. Аргументы будут переданы методу castUsing:

use App\Models\Address;
 
protected $casts = [
'address' => Address::class.':argument',
];

Кастовые и анонимные классы кастов

Комбинируя "касты" с анонимными классами PHP, вы можете определить объект значения и его логику приведения в одном объекте каста. Для этого верните анонимный класс из метода castUsing вашего объекта значения. Анонимный класс должен реализовывать интерфейс CastsAttributes:

<?php
namespace App\Models;
use Illuminate\Contracts\Database\Eloquent\Castable;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Database\Eloquent\Model;
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,
];
}
};
}
}