Що це таке
Всі три механізми вирішують одну задачу — перетворення даних при читанні з моделі або записі в модель. Замість ручного форматування щоразу — описуєш правило один раз, і Laravel застосовує його автоматично.
Casts — автоматичне приведення типів
Cast вказує тип — Laravel конвертує автоматично в обидва боки: при читанні з БД і при записі в БД.
class User extends Model
{
protected $casts = [
'is_active' => 'boolean', // "1" з БД → true в PHP
'settings' => 'array', // JSON рядок з БД → масив в PHP
'price' => 'float', // "19.99" → 19.99
'birthday' => 'date', // "2000-01-15" → Carbon обʼєкт
'email_verified_at' => 'datetime', // рядок → Carbon
'metadata' => 'object', // JSON → stdClass
'secret' => 'encrypted', // автоматичне шифрування/дешифрування
'status' => OrderStatus::class, // Enum cast (PHP 8.1)
];
}
Приклад використання:
$user = User::find(1);
// Без каста — "сирі" дані з БД
$user->is_active; // "1" (рядок)
$user->settings; // '{"theme":"dark"}' (JSON-рядок)
// З кастом — перетворені типи
$user->is_active; // true (boolean)
$user->settings; // ['theme' => 'dark'] (масив)
$user->settings['theme']; // 'dark'
// Запис — конвертує назад автоматично
$user->settings = ['theme' => 'light', 'locale' => 'uk'];
$user->save();
// В БД збережеться: '{"theme":"light","locale":"uk"}'
Доступні типи кастів
| Каст | Що робить | Приклад |
|---|---|---|
boolean | Рядок/число → true/false | "1" → true |
integer | Рядок → ціле число | "42" → 42 |
float | Рядок → дробове число | "19.99" → 19.99 |
string | Число → рядок | 42 → "42" |
array | JSON-рядок → масив | '{"a":1}' → ['a' => 1] |
object | JSON-рядок → stdClass | '{"a":1}' → object->a |
collection | JSON → Collection | '[1,2,3]' → collect([1,2,3]) |
date | Рядок → Carbon (без часу) | "2025-01-15" → Carbon |
datetime | Рядок → Carbon (з часом) | "2025-01-15 14:30" → Carbon |
timestamp | Рядок → Unix timestamp | → 1705315200 |
encrypted | Шифрує при записі, дешифрує при читанні | Чутливі дані |
Enum::class | Рядок → PHP Enum | "active" → Status::Active |
Accessors — перетворення при ЧИТАННІ
Accessor змінює значення коли ти його читаєш з моделі. Корисно для форматування, обчислюваних полів, дефолтних значень.
Новий синтаксис (Laravel 9+)
use Illuminate\Database\Eloquent\Casts\Attribute;
class User extends Model
{
// Комбінує два поля в одне
protected function fullName(): Attribute
{
return Attribute::make(
get: fn () => $this->first_name . ' ' . $this->last_name,
);
}
// Форматує ціну
protected function formattedPrice(): Attribute
{
return Attribute::make(
get: fn () => number_format($this->price, 2) . ' ₴',
);
}
// Дефолтна аватарка якщо немає своєї
protected function avatarUrl(): Attribute
{
return Attribute::make(
get: fn () => $this->avatar
? Storage::url($this->avatar)
: 'https://ui-avatars.com/api/?name=' . urlencode($this->name),
);
}
}
Використання:
$user->full_name; // "Олексій Шевченко"
$user->formatted_price; // "1 299.00 ₴"
$user->avatar_url; // "/storage/avatars/abc.jpg" або дефолтна
Імʼя методу в camelCase (fullName) автоматично перетворюється в snake_case при зверненні (full_name).
Старий синтаксис (все ще працює)
class User extends Model
{
public function getFullNameAttribute(): string
{
return $this->first_name . ' ' . $this->last_name;
}
}
$user->full_name; // "Олексій Шевченко"
Конвенція іменування: get + FullName + Attribute.
Mutators — перетворення при ЗАПИСІ
Mutator змінює значення коли ти його записуєш у модель. Корисно для очистки, нормалізації, хешування.
Новий синтаксис (Laravel 9+)
class User extends Model
{
// Хешувати пароль автоматично при записі
protected function password(): Attribute
{
return Attribute::make(
set: fn (string $value) => Hash::make($value),
);
}
// Завжди lowercase email
protected function email(): Attribute
{
return Attribute::make(
set: fn (string $value) => strtolower(trim($value)),
);
}
// Очистити номер телефону від зайвих символів
protected function phone(): Attribute
{
return Attribute::make(
set: fn (string $value) => preg_replace('/[^\d+]/', '', $value),
);
}
}
Використання:
$user->password = 'secret123';
// В БД збережеться: "$2y$12$xK9mN8pQ..." (хеш)
$user->email = ' [email protected] ';
// В БД збережеться: "[email protected]"
$user->phone = '+38 (099) 123-45-67';
// В БД збережеться: "+380991234567"
Старий синтаксис
class User extends Model
{
public function setPasswordAttribute(string $value): void
{
$this->attributes['password'] = Hash::make($value);
}
public function setEmailAttribute(string $value): void
{
$this->attributes['email'] = strtolower(trim($value));
}
}
Конвенція іменування: set + Password + Attribute.
Accessor + Mutator разом
Один метод може мати і get:, і set::
class User extends Model
{
protected function name(): Attribute
{
return Attribute::make(
get: fn (string $value) => ucfirst($value), // при читанні: "олексій" → "Олексій"
set: fn (string $value) => strtolower(trim($value)), // при записі: " ОЛЕКСІЙ " → "олексій"
);
}
}
$user->name = ' ОЛЕКСІЙ '; // mutator: зберіг "олексій"
echo $user->name; // accessor: вивів "Олексій"
Custom Cast — свій клас касту
Для складної логіки можна створити окремий клас касту:
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
class MoneyCast implements CastsAttributes
{
public function get($model, string $key, $value, array $attributes): Money
{
return new Money(
amount: $value,
currency: $attributes['currency'] ?? 'UAH'
);
}
public function set($model, string $key, $value, array $attributes): int
{
if ($value instanceof Money) {
return $value->amount;
}
return (int) $value;
}
}
Використання:
class Order extends Model
{
protected $casts = [
'total' => MoneyCast::class,
];
}
$order->total; // Money { amount: 1500, currency: "UAH" }
$order->total->amount; // 1500
Практичні приклади
Модель User з усіма трьома
class User extends Model
{
// Касти — прості перетворення типів
protected $casts = [
'is_active' => 'boolean',
'settings' => 'array',
'birthday' => 'date',
'email_verified_at' => 'datetime',
];
// Accessor — обчислюване поле (немає в БД)
protected function fullName(): Attribute
{
return Attribute::make(
get: fn () => $this->first_name . ' ' . $this->last_name,
);
}
// Accessor — вік на основі дня народження
protected function age(): Attribute
{
return Attribute::make(
get: fn () => $this->birthday?->age,
);
}
// Accessor — дефолтна аватарка
protected function avatarUrl(): Attribute
{
return Attribute::make(
get: fn () => $this->avatar
? Storage::url($this->avatar)
: 'https://ui-avatars.com/api/?name=' . urlencode($this->name),
);
}
// Mutator — хешування пароля
protected function password(): Attribute
{
return Attribute::make(
set: fn (string $value) => Hash::make($value),
);
}
// Accessor + Mutator — нормалізація email
protected function email(): Attribute
{
return Attribute::make(
get: fn (string $value) => $value,
set: fn (string $value) => strtolower(trim($value)),
);
}
}
Використання в Blade
<h1>{{ $user->full_name }}</h1> {{-- accessor --}}
<p>Вік: {{ $user->age }}</p> {{-- accessor --}}
<img src="{{ $user->avatar_url }}"> {{-- accessor --}}
<p>Активний: {{ $user->is_active ? 'Так' : 'Ні' }}</p> {{-- cast --}}
<p>Тема: {{ $user->settings['theme'] }}</p> {{-- cast array --}}
<p>Дата: {{ $user->birthday->format('d.m.Y') }}</p> {{-- cast date --}}
Порівняння
| Casts | Accessors | Mutators | |
|---|---|---|---|
| Коли працює | При читанні і записі | Тільки при читанні | Тільки при записі |
| Де оголошується | Масив $casts | Метод з Attribute::make(get:) | Метод з Attribute::make(set:) |
| Для чого | Приведення типів (JSON→array, string→bool) | Форматування, обчислювані поля | Очистка, хешування, нормалізація |
| Віртуальні поля | Ні — працює з реальними колонками | Так — full_name без колонки в БД | Ні |
| Складна логіка | Через Custom Cast клас | Будь-яка логіка в get: | Будь-яка логіка в set: |
Коли що використовувати
Cast — простий тип, конвертація в обидва боки: 'is_active' => 'boolean', 'settings' => 'array', 'birthday' => 'date'.
Accessor — форматування при відображенні, обчислювані поля: full_name, avatar_url, formatted_price, age.
Mutator — очистка і перетворення при збереженні: хешування пароля, lowercase email, очистка телефону від зайвих символів.
Custom Cast — складна логіка перетворення в обидва боки: Money, Address, Coordinates.