Команда Laravel випустила версію 13.33.0 з підтримкою тегів для мемоїзованого кешу, атрибутом #[Refreshes] для автоматичного оновлення згенерованих колонок моделей та низкою інших покращень.
Тегований мемоїзований кеш
Joost de Bruijn додав метод tags() до мемоїзованого кеш-сховища, тому тепер Cache::memo() працює з тегованими кешами. Читання в межах одного запиту звертаються до бекенду кешу лише один раз, а всі наступні запити виконуються з пам'яті:
// Два виклики, один звернення до Redis
Cache::memo()->tags(['permissions'])->get("permissions:{$user->id}");
Cache::memo()->tags(['permissions'])->get("permissions:{$user->id}");
// Записи йдуть у тегований кеш і видаляють мемоїзовану копію
Cache::memo()->tags(['permissions'])->put("permissions:{$user->id}", $permissions);
// Очищення тегу також видаляє мемоїзовані записи
Cache::memo()->tags(['permissions'])->flush();
До цього релізу той самий патерн вимагав обгортання виклику тегованого кешу у додатковий пошук Cache::store('array') вручну. Нетеговану версію було представлено у Laravel 12.9.
Оновлення атрибутів моделі після запису
Caleb White додав атрибут #[Refreshes] (та відповідну властивість $refreshes), який перезавантажує вказані колонки з бази даних після створення або оновлення моделі. Це призначено для колонок virtualAs і storedAs та інших значень, які встановлює база даних, і які інакше залишаються відсутніми або застарілими в моделі в пам'яті до виклику refresh():
use Illuminate\Database\Eloquent\Attributes\Refreshes;
#[Refreshes('name')]
class User extends Model
{
//
}
$user = User::create(['first_name' => 'Taylor', 'last_name' => 'Otwell']);
$user->name; // "Taylor Otwell" без виклику refresh()
Оновлення виконується одним запитом лише для перелічених колонок, на з'єднанні для запису. Атрибут приймає масив або варіативні імена колонок, а властивість $refreshes працює аналогічно, якщо ви не використовуєте атрибути.
Збереження справжнього NULL з AsCollection та AsArrayObject
Zein Ahmad додав опціональний режим nullable() для кастів AsCollection та AsArrayObject. Присвоєння null одному з цих кастів зберігає JSON-рядок "null" у колонці, тому whereNull() ніколи не знаходить рядок. З nullable() каст зберігає базу даних NULL замість цього:
protected function casts(): array
{
return [
'items' => AsCollection::class, // без змін: зберігає "null"
'meta' => AsCollection::nullable(), // зберігає NULL
'options' => AsArrayObject::nullable(),
];
}
Тепер запити whereNull() коректно працюють з такими колонками.
Модифікатори inplace() та lock() для міграцій індексів
Sander Muller додав модифікатор inplace() для операцій з індексами та зовнішніми ключами, а також модифікатор lock(), щоб міграція MySQL могла запитувати ALGORITHM=INPLACE та LOCK=NONE замість повного блокуючого перебудови таблиці:
Schema::table('video_sessions', function (Blueprint $table) {
$table->index('foo', 'foo_index')->inplace()->lock('none');
});
Модифікатор працює з наступними методами:
index()
unique()
primary()
fullText()
spatialIndex()
foreign()
Він віддзеркалює модифікатор instant(), який вже існує для визначень колонок.
Атрибути Form Request з батьківських класів
Md Sukkur Ali виправив атрибути form request, щоб дочірній запит успадковував їх від батьківського класу. PHP не успадковує атрибути автоматично, тому атрибути на кшталт #[StopOnFirstFailure] на спільному базовому запиті ігнорувалися кожним підкласом:
#[StopOnFirstFailure]
#[FailOnUnknownFields]
abstract class ApiRequest extends FormRequest
{
//
}
// Обидва атрибути тепер застосовуються
class StorePostRequest extends ApiRequest
{
//
}
Тепер успадкування атрибутів працює коректно для усіх підкласів.
Відмова від завершення воркера при таймауті
Jack Bayliss додав прапорець Worker::$killOnTimeout. За замовчуванням джоба, яка перевищує таймаут, завершує весь процес воркера, і супервайзер запускає новий. Встановіть прапорець у false, і воркер викине TimeoutExceededException замість цього, що дозволить джобі очистити ресурси, а воркер продовжить працювати:
use Illuminate\Queue\Worker;
Worker::$killOnTimeout = false;
Увага: джоба, яка обгортає тіло handle() у широкий try/catch, може проковтнути виняток.
Пов'язаний PR від Kieran Brown додає Worker::killUsing() - хук, який виконується перед SIGKILL, щоб користувацький код виходу міг досягти супервайзера.
Тестові хелпери mockArtisan() та realArtisan()
Jenthe Noordsij додав два тестові хелпери, які розділяють дві функції $this->artisan(). Метод mockArtisan() завжди повертає PendingCommand для очікувань, а realArtisan() завжди виконує команду та повертає код виходу як int, тому вам більше не потрібно перемикати $mockConsoleOutput для перемикання між двома режимами:
$this->mockArtisan('inspire')
->expectsOutputToContain('Simplicity')
->assertExitCode(0);
$code = $this->realArtisan('migrate', ['--force' => true]);
Це спрощує тестування Artisan-команд і робить тести більш явними.
Інші покращення
Версія 13.33.0 також включає:
- Підтримку протоколів
valkey:// та valkeys:// для Redis-з'єднань
- Виправлення для дублікатів у
Eloquent Collection duplicates() з ключем або callback
- Опцію
--pretend для команди install:broadcasting
- Методи
createQuietly та createManyQuietly для BelongsToMany
- Покращену обробку PostgreSQL server options та нативний pooling для Laravel Cloud
- Підтримку MariaDB 11 та 12.3 у тестах
- Виправлення
LazyCollection::take() з від'ємним лімітом, більшим за колекцію
- Покращення обробки батчів у черзі та Cloud job retries
Повний список змін та оновлень доступний у changelog та diff між версіями 13.32.0 та 13.33.0 на GitHub.