Laravel v12.54.0 додає Model::withoutRelation() для вибіркового видалення зв’язків у клонованому екземплярі моделі, вводить interval() в InteractsWithData для парсингу значень тривалості та додає композитний індекс у таблицю jobs для прискорення опитування черги.
Основні нововведення:
Model::withoutRelation() — вибірково видаляє завантажені зв’язки без зміни оригіналуinterval() у InteractsWithData — перетворення даних запиту в CarbonIntervalResponse::dump() HTTP-клієнтаBinaryFileResponse у тестах HTTP для асерту на стрімінг контентуqueue:monitor показує найстарішу очікувану задачу в текстовому виводіtsvector у схемі для PostgreSQLModel::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 перетворює вхідні значення запиту в екземпляр 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() HTTP-клієнта тепер показує метод запиту, URL і код статусу разом з тілом відповіді. Раніше виводилося лише тіло, що ускладнювало ідентифікацію відповіді при ланцюжку запитів.
// Before
{"error": {"message": "Invalid card"}}
// After
"POST https://api.stripe.com/v1/charges" 422
{"error": {"message": "Invalid card"}}
Pull Request: #59136
Тестові відповіді від response()->file() і response()->download() тепер підтримують асерти на стрімінг контенту. Раніше assertStreamedContent() на BinaryFileResponse падало, бо тестовий response не міг прочитати файл.
$this->get('/download/report.pdf')
->assertOk()
->assertStreamedContent(file_get_contents('report.pdf'));
Pull Request: #59018
Команда 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 тепер дозволяє додавати власні 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 тепер створює композитний індекс на (queue, reserved_at, available_at) замість індексу лише на queue. На навантажених чергах попередній одно-колонковий індекс змушував БД сканувати рядки, фільтруючи по reserved_at та available_at під час кожного опитування. Новий індекс відповідає формі запиту для опитування черги.
Це нова міграція й діє лише для чистих інсталяцій або додатків, що повторно запускають міграції. Існуючим проєктам слід додати індекс вручну за потреби.
Pull Request: #59111
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:
repeatEvery() (#58987)Database:
migrate:fresh, коли база даних не існує (#59113)ModelNotFoundException (#59132)HTTP & Filesystem:
Filesystem::replace() на файлових системах без POSIX (#59126)Console & Views:
view:cache (#59145)TwoColumnDetail для значень другої колонки (#59010)app.editor.base_path був порожнім рядком (#58991)Інше:
after callbacks (#58990)-ing (#59058)DisallowedRawHtmlRenderer (#59131)Ви готові відкрити нові горизонти у роботі з геопросторовими даними в Laravel? Дізнайтеся, як за допомогою PostGIS та пакету Laravel-Magellan можна легко зберігати, запитувати та маніпулювати інформацією про розташування, перетворюючи ваші проекти на вражаючі рішення у сфері картографії та геолокації!
Ви хочете навчитися, як інтегрувати Google OAuth у вашому проекті Laravel, використовуючи Socialite? Дізнайтеся, як налаштувати доступ до сервісів Google, таких як Календар, у нашій сьогоднішній статті
PHP 8.5 обіцяє безліч нових можливостей, таких як оператор Pipe, функції `array_first()` та `array_last()`, а також нове розширення URI. Чи готові ви дізнатися, як ці функції можуть спростити вашу розробку? Читайте далі, щоб дізнатися більше про ці захоплюючі нововведення