---
title: "Eloquent Refreshes: автоматичне завантаження згенерованих колонок після збереження"
url: https://laravelukraine.com/blog/eloquent-refreshes-avtomaticne-zavantazennia-zgenerovanix-kolonok-pislia-zberezennia
date: 2026-09-25
source: https://laravel-news.com/eloquent-refreshes-attribute
---

# Eloquent Refreshes: автоматичне завантаження згенерованих колонок після збереження

## Проблема застарілих даних у моделях

Під час роботи з Eloquent моделями, які мають колонки зі значеннями, згенерованими базою даних, виникає типова проблема: після створення або оновлення моделі ці колонки залишаються порожніми або містять застарілі дані.

Розглянемо таблицю `orders`, де база даних автоматично обчислює колонку `total` на основі двох інших колонок:

```php
Schema::create('orders', function (Blueprint $table) {
    $table->id();
    $table->decimal('subtotal', 10, 2);
    $table->decimal('tax', 10, 2);
    $table->decimal('total', 10, 2)->storedAs('subtotal + tax');
    $table->timestamps();
});
```

Хоча колонку `total` можна індексувати та використовувати в запитах як звичайну колонку, модель, отримана після `create()`, не містить її значення:

```php
$order = Order::create(['subtotal' => 100, 'tax' => 8.25]);
$order->total; // null
$order->update(['tax' => 9.00]);
$order->total; // все ще null
```

До виходу Laravel 13.33 доводилося вручну викликати `$order->refresh()` після кожного запису, що перезавантажувало всі колонки та всі завантажені зв'язки.

## Атрибут #[Refreshes]

Caleb White додав атрибут `#[Refreshes]` у pull request #61523. Цей атрибут розміщується на моделі зі списком колонок, які встановлює база даних:

```php
use Illuminate\Database\Eloquent\Attributes\Refreshes;
use Illuminate\Database\Eloquent\Model;

#[Refreshes('total')]
class Order extends Model
{
    protected $fillable = ['subtotal', 'tax'];
}
```

Після кожної операції вставки або оновлення Eloquent автоматично виконує SELECT цих колонок для збереженого рядка та копіює їх у модель:

```php
$order = Order::create(['subtotal' => 100, 'tax' => 8.25]);
$order->total; // "108.25"
$order->update(['tax' => 9.00]);
$order->total; // "109.00"
```

Для оновлення кількох колонок можна передати масив або кілька аргументів. Обидва варіанти `#[Refreshes(['total', 'slug'])]` та `#[Refreshes('total', 'slug')]` працюють однаково.

## Альтернативна конфігурація через властивість

Якщо ви налаштовуєте моделі через властивості замість атрибутів, можна використати властивість `$refreshes`:

```php
class Order extends Model
{
    protected array $refreshes = ['total'];
}
```

Якщо модель має обидва варіанти конфігурації, використовується властивість, а атрибут ігнорується. Модель без жодного з них не виконує додаткових запитів.

## Згенеровані значення в подіях моделі

Оновлення виконується після `INSERT` або `UPDATE`, але перед тим, як Eloquent викликає події `created` або `updated`. Це означає, що обробники цих подій бачать нові значення. Спостерігач (observer), який надсилає квитанцію, може прочитати total, обчислений базою даних:

```php
class OrderObserver
{
    public function created(Order $order): void
    {
        Mail::to($order->customer)->send(new OrderReceipt($order));
    }
    
    public function updated(Order $order): void
    {
        if ($order->wasChanged('total')) {
            $order->customer->notify(new OrderTotalChanged($order));
        }
    }
}
```

Перевірка `wasChanged('total')` працює коректно, оскільки Eloquent реєструє зміни після оновлення. Хоча ваш код ніколи безпосередньо не встановлює `total`, ця колонка з'являється у `getChanges()`, коли база даних обчислює нове значення.

## Які операції запису запускають оновлення

Оновлення виконується для екземпляра моделі в таких сценаріях:

- Вставки через `create()`, `save()`, `saveQuietly()` та `saveOrIgnore()`
- Оновлення через `update()`, `save()` та `saveQuietly()`
- Виклики increment/decrement: `increment()`, `decrement()`, `incrementEach()` та `decrementEach()`

## Як працює запит оновлення

Оновлення виконується одним запитом `SELECT` для перелічених колонок з обмеженням по первинному ключу моделі:

```sql
select `total` from `orders` where `id` = ? limit 1
```

Запит виконується на з'єднанні для запису. При використанні read replicas репліка може ще не мати нового рядка.

Запит також пропускає глобальні scope, що означає, що tenant або soft-delete scope не можуть приховати рядок, який Eloquent щойно зберіг. Використовується `firstOrFail()`: якщо рядок зникне до моменту виконання запиту, збереження викине `ModelNotFoundException`.

## #[Refreshes] або refresh()

Атрибут `#[Refreshes]` підходить для колонок, які ви читаєте одразу після запису: колонки `storedAs` та `virtualAs`, значення, встановлені тригерами, та значення за замовчуванням з бази даних, які Eloquent не встановлює. Атрибут додає запит до кожного запису, тому вказуйте лише ті колонки, які ви дійсно читаєте.

Викликайте `$model->refresh()`, коли потрібно перечитати весь рядок або завантажені зв'язки. Також можна використовувати його для разових операцій запису, де додавання атрибута до моделі створило б додатковий запит при кожному іншому збереженні.

Документація Eloquent висвітлює цей атрибут у розділі "Refreshing Attributes After Writes".
