Laravel v12.54.0 додає Model::withoutRelation() для вибіркового видалення зв’язків у клонованому екземплярі моделі, вводить interval() в InteractsWithData для парсингу значень тривалості та додає композитний індекс у таблицю jobs для прискорення опитування черги.
Основні нововведення:
Model::withoutRelation()— вибірково видаляє завантажені зв’язки без зміни оригіналуinterval()уInteractsWithData— перетворення даних запиту вCarbonInterval- Контекст запиту (метод, URL, статус) додається у вивід
Response::dump()HTTP-клієнта - Підтримка
BinaryFileResponseу тестах HTTP для асерту на стрімінг контенту queue:monitorпоказує найстарішу очікувану задачу в текстовому виводі- Користувацькі розширення CommonMark для рендерингу Markdown у mail
- Композитний індекс у таблиці jobs для кращої продуктивності опитування черги
- Підтримка типу колонки
tsvectorу схемі для PostgreSQL
Що нового
Model::withoutRelation()
Model::withoutRelation() створює клон моделі з видаленими вказаними зв’язками, не змінюючи оригінал. Це проміжний варіант між withoutRelations() — яке прибирає всі зв’язки — та unsetRelation(), яке мутує модель на місці.
// Remove a single relation from a clone
$lightweight = $post->withoutRelation('comments');
// Remove multiple relations
$lightweight = $post->withoutRelation(['comments', 'tags']);
// Original is untouched
$post->relationLoaded('comments'); // true
Зручно для уникнення циклічних посилань, зменшення розміру payload у queued jobs та підготовки моделей до серіалізації, не видаляючи всі eager-loaded дані.
Pull Request: #59137
interval() у InteractsWithData
Новий метод interval() у InteractsWithData перетворює вхідні значення запиту в екземпляр CarbonInterval. Він приймає рядки ISO 8601, або числові значення з вказаною одиницею.
// ISO 8601 duration string ("P1DT2H" → 1 day, 2 hours)
$request->interval('duration');
// Numeric value with a string unit
$request->interval('timeout', 'second'); // "90" → 90 seconds
$request->interval('cooldown', 'day'); // "7" → 7 days
// Or using the Carbon\Unit enum
$request->interval('delay', Unit::Minute);
Тепер, поряд із date(), форми мають нативний спосіб працювати з полями тривалості.
Pull Request: #59114
Контекст запиту у Response::dump()
Response::dump() HTTP-клієнта тепер показує метод запиту, URL і код статусу разом з тілом відповіді. Раніше виводилося лише тіло, що ускладнювало ідентифікацію відповіді при ланцюжку запитів.
// Before
{"error": {"message": "Invalid card"}}
// After
"POST https://api.stripe.com/v1/charges" 422
{"error": {"message": "Invalid card"}}
Pull Request: #59136
Підтримка BinaryFileResponse в асертах
Тестові відповіді від response()->file() і response()->download() тепер підтримують асерти на стрімінг контенту. Раніше assertStreamedContent() на BinaryFileResponse падало, бо тестовий response не міг прочитати файл.
$this->get('/download/report.pdf')
->assertOk()
->assertStreamedContent(file_get_contents('report.pdf'));
Pull Request: #59018
queue:monitor показує найстарішу очікувану задачу
Команда queue:monitor тепер виводить в стандартний текстовий потік вік найстарішої pending job. Раніше ця інформація була доступна лише в JSON-виводі.
Pending jobs ...................................... 3
Delayed jobs ...................................... 0
Reserved jobs ..................................... 1
Oldest pending job ................................ 2 minutes ago
Pull Request: #59073
Користувацькі розширення Markdown для Mail
Рендеринг Markdown у mail тепер дозволяє додавати власні CommonMark-розширення через конфіг mail.markdown.extensions. Раніше завантажувалися лише Core і Table extensions.
// config/mail.php
'markdown' => [
'extensions' => [
League\CommonMark\Extension\Strikethrough\StrikethroughExtension::class,
League\CommonMark\Extension\TaskList\TaskListExtension::class,
],
],
Тут можна реєструвати будь-яке розширення, що реалізує CommonMark ExtensionInterface.
Pull Request: #59051
Композитний індекс у таблиці jobs
Міграція таблиці jobs тепер створює композитний індекс на (queue, reserved_at, available_at) замість індексу лише на queue. На навантажених чергах попередній одно-колонковий індекс змушував БД сканувати рядки, фільтруючи по reserved_at та available_at під час кожного опитування. Новий індекс відповідає формі запиту для опитування черги.
Це нова міграція й діє лише для чистих інсталяцій або додатків, що повторно запускають міграції. Існуючим проєктам слід додати індекс вручну за потреби.
Pull Request: #59111
Тип колонки tsvector для PostgreSQL
Schema builder тепер підтримує тип колонки tsvector для PostgreSQL, тож більше не потрібно використовувати raw SQL при визначенні колонок для повнотекстового пошуку.
Schema::table('articles', function (Blueprint $table) {
$table->tsvector('search_vector')->nullable()->storedAs(
"setweight(to_tsvector('english', coalesce(title, '')), 'A') || " .
"setweight(to_tsvector('english', coalesce(body, '')), 'B')"
);
});
Pull Request: #59004
Виправлення помилок і покращення
Queue & Jobs:
- Запобігання deadlock у черзі, коли при резервуванні job кидається виключення (наприклад, overflow) (#58978)
- Виправлено ділення на нуль у
repeatEvery()(#58987)
Database:
- Виправлено помилку
migrate:fresh, коли база даних не існує (#59113) - Виправлено відображення enum у повідомленнях про помилку
ModelNotFoundException(#59132)
HTTP & Filesystem:
- Виправлено валідацію URL для punycode-піддоменів (#58982)
- Підавлення помилок chmod у
Filesystem::replace()на файлових системах без POSIX (#59126) - Виправлено права файлу кешу фасадів (#59059)
Console & Views:
- Дедуплікація шляхів у
view:cache(#59145) - Виправлено обрізання фінальних знаків пунктуації у
TwoColumnDetailдля значень другої колонки (#59010) - Дозволено, щоб
app.editor.base_pathбув порожнім рядком (#58991)
Інше:
- Виправлено ігнорування Redis throttle для
aftercallbacks (#58990) - Виправлено after-commit observers, які ламали скасування подій з
-ing(#59058) - Виправлено попередження про застаріле використання зсуву масиву (#59019)
- Оновлено обмеження версії CommonMark, щоб усунути проблему безпеки
DisallowedRawHtmlRenderer(#59131)