<? phpukraine ЕКОСИСТЕМА
⌕Пошук по платформі
LARAVEL · ЩО НОВОГО

Що нового в Laravel 13

  1. 01Queue::route() задає connection і queue для класів job в одному місці, без onQueue() у кожному dispatch.
  2. 02Атрибути замість властивостей: #[Tries] і #[Timeout] у jobs, #[Table] і #[Fillable] у моделях, #[Middleware] і #[Authorize] у контролерах.
  3. 03Мінімум PHP 8.3, CSRF-захист з перевіркою Sec-Fetch-Site і мало ламких змін: офіційна оцінка оновлення 10 хвилин.
СТАТУС Активна підтримка
Реліз
17 березня 2026
Останній патч
13.35.0
Активна підтримка до
30.09.2027
Безпека до
17.03.2028
НОВІ МОЖЛИВОСТІ · 6

Нові можливості

1.1 · НОВЕ

Queue::route()

Раніше чергу для job вказували або в самому класі, або через onQueue() при кожному dispatch, і ці правила розповзались по коду. Тепер вони живуть у boot() сервіс-провайдера. Маршрут можна задати й для інтерфейсу, трейта чи батьківського класу, а окремий job усе ще може його перевизначити.

+ LARAVEL 13
// AppServiceProvider::boot()
Queue::route(ProcessPodcast::class, connection: 'redis', queue: 'podcasts');
Queue::route(ShouldBroadcast::class, queue: 'events');

// далі звичайний dispatch
ProcessPodcast::dispatch($podcast);
− LARAVEL 12
ProcessPodcast::dispatch($podcast)
    ->onConnection('redis')
    ->onQueue('podcasts');
1.2 · 12.45+

JSON:API resources

Клас зʼявився ще в Laravel 12.45 у січні 2026, а в Laravel 13 увійшов до офіційного опису релізу. Досить перелічити $attributes і $relationships, а структуру з id і type, блок included, sparse fieldsets через ?fields і заголовок application/vnd.api+json ресурс збирає сам. Звʼязки потрапляють у відповідь лише тоді, коли клієнт попросив їх через ?include.

+ LARAVEL 13
use Illuminate\Http\Resources\JsonApi\JsonApiResource;

class PostResource extends JsonApiResource
{
    public $attributes = ['title', 'body', 'created_at'];

    public $relationships = ['author', 'comments'];
}

Route::get('/api/posts/{post}', fn (Post $post) => $post->toResource());

// GET /api/posts/1?include=author&fields[posts]=title
− LARAVEL 12
class PostResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => (string) $this->id,
            'type' => 'posts',
            'attributes' => [
                'title' => $this->title,
                'body' => $this->body,
            ],
        ];
    }
}
1.3 · 12.47+

Vector search у query builder

Методи зʼявились ще в Laravel 12.47 у січні 2026, а в Laravel 13 увійшли до офіційного опису релізу. whereVectorSimilarTo() відбирає рядки за косинусною схожістю до переданого вектора і сортує від найближчих, а selectVectorDistance(), whereVectorDistanceLessThan() і orderByVectorDistance() дають ті самі кроки окремо. Потрібен PostgreSQL з розширенням pgvector або MariaDB 11.7+.

+ LARAVEL 13
// у міграції
Schema::ensureVectorExtensionExists();
$table->vector('embedding', dimensions: 1536);

// $queryEmbedding: масив float від вашої моделі embeddings
$documents = DB::table('documents')
    ->whereVectorSimilarTo('embedding', $queryEmbedding, minSimilarity: 0.4)
    ->limit(10)
    ->get();
1.4 · 13.x

Debounce для jobs

Товар редагують десять разів за хвилину, і кожне збереження ставить у чергу переіндексацію. З #[DebounceFor(30)] job з тим самим debounceId() виконається один раз, для останнього dispatch, а витіснені копії зникнуть з черги. maxWait обмежує відкладання, з ShouldBeUnique атрибут не поєднується, доступно з 13.6.

+ LARAVEL 13
use Illuminate\Queue\Attributes\DebounceFor;

#[DebounceFor(30, maxWait: 120)]
class UpdateSearchIndex implements ShouldQueue
{
    use Queueable;

    public function __construct(public int $productId) {}

    public function debounceId(): string
    {
        return (string) $this->productId;
    }
}
1.5 · 13.x

Обробка зображень

Laravel отримав власний fluent API поверх Intervention Image. $request->image() повертає обʼєкт з cover(), scale(), crop() і toWebp(), трансформації складаються в ланцюжок, а кодується картинка один раз у кінці. Потрібні пакет intervention/image ^4.0 і розширення GD або Imagick, API доступний з 13.20.

+ LARAVEL 13
$path = $request->image('avatar')
    ->cover(400, 400)
    ->toWebp()
    ->storePublicly('avatars', 'public');

$thumb = Storage::disk('public')->image('avatars/photo.jpg')->scale(width: 200);
1.6 · НОВЕ

schedule:pause

Під час міграції даних чи інциденту буває треба, щоб cron-задачі не стартували, а правити routes/console.php і деплоїти заради цього незручно. schedule:pause ставить прапорець у cache, і schedule:run пропускає задачі до schedule:continue. Задача з evenWhenPaused() працює й під час паузи.

+ LARAVEL 13
php artisan schedule:pause
php artisan schedule:continue

Schedule::command('emails:send')->evenWhenPaused();
СИНТАКСИС · 5

Синтаксис

2.1 · НОВЕ

#[Middleware] і #[Authorize]

Щоб задати middleware в самому контролері, у Laravel 12 реалізовували HasMiddleware зі статичним middleware(), а only і except перелічували назви методів рядками. Тепер атрибут стоїть над методом, і одразу видно, що на ньому висить. #[Authorize] працює як скорочення для middleware can: перший аргумент задає ability, другий передає в policy клас моделі або параметр маршруту.

+ LARAVEL 13
use Illuminate\Routing\Attributes\Controllers\Authorize;
use Illuminate\Routing\Attributes\Controllers\Middleware;

#[Middleware('auth')]
class CommentController
{
    #[Middleware('subscribed')]
    #[Authorize('create', [Comment::class, 'post'])]
    public function store(Post $post) { /* … */ }
}
− LARAVEL 12
class CommentController implements HasMiddleware
{
    public static function middleware(): array
    {
        return [
            'auth',
            new Middleware('subscribed', only: ['store']),
        ];
    }
}
2.2 · НОВЕ

#[Tries], #[Backoff], #[Timeout]

Раніше це були публічні властивості $tries, $backoff і $timeout, які Laravel шукав за назвою, тож одруківка просто ігнорувалась. Атрибут є класом з типізованим аргументом, і помилку підсвітить IDE. Поруч є #[MaxExceptions], #[FailOnTimeout] і #[UniqueFor], а #[Tries] працює також для queued listeners і notifications.

+ LARAVEL 13
use Illuminate\Queue\Attributes\{Backoff, FailOnTimeout, Timeout, Tries};

#[Tries(5)]
#[Backoff(3)]
#[Timeout(120)]
#[FailOnTimeout]
class ImportVacancies implements ShouldQueue
{
    use Queueable;
}
− LARAVEL 12
class ImportVacancies implements ShouldQueue
{
    public $tries = 5;
    public $backoff = 3;
    public $timeout = 120;
    public $failOnTimeout = true;
}
2.3 · НОВЕ

#[Table], #[Fillable], #[Hidden]

Таблиця, первинний ключ, mass assignment і приховані при серіалізації поля описуються над класом моделі. У #[Table] можна одразу передати key, keyType, incrementing і timestamps, тож кілька властивостей стискаються в один рядок. $table і $fillable теж лишаються робочими.

+ LARAVEL 13
use Illuminate\Database\Eloquent\Attributes\{Fillable, Hidden, Table};

#[Table('job_vacancies')]
#[Fillable(['title', 'salary_from'])]
#[Hidden(['internal_note'])]
class Vacancy extends Model {}
− LARAVEL 12
class Vacancy extends Model
{
    protected $table = 'job_vacancies';

    protected $fillable = ['title', 'salary_from'];

    protected $hidden = ['internal_note'];
}
2.4 · НОВЕ

#[Signature] і #[Description]

Рядок з назвою, аргументами й опціями команди переїхав над клас, у тілі лишається handle(). Синтаксис сигнатури той самий, що був у $signature. Другим аргументом #[Signature] можна передати aliases.

+ LARAVEL 13
use Illuminate\Console\Attributes\Description;
use Illuminate\Console\Attributes\Signature;

#[Signature('mail:send {user}')]
#[Description('Надіслати листа користувачу')]
class SendEmails extends Command
{
    public function handle(): void { /* … */ }
}
− LARAVEL 12
class SendEmails extends Command
{
    protected $signature = 'mail:send {user}';

    protected $description = 'Надіслати листа користувачу';
}
2.5 · НОВЕ

#[StopOnFirstFailure] і #[ErrorBag]

Те, що раніше жило у властивостях $stopOnFirstFailure, $redirectRoute і $errorBag, тепер пишеться над класом запиту. #[RedirectToRoute] і #[RedirectTo] вказують, куди повернути користувача, а #[ErrorBag] складає помилки в окремий named error bag. Зручно, коли на сторінці дві форми.

+ LARAVEL 13
use Illuminate\Foundation\Http\Attributes\{ErrorBag, RedirectToRoute, StopOnFirstFailure};

#[StopOnFirstFailure]
#[RedirectToRoute('login')]
#[ErrorBag('login')]
class LoginRequest extends FormRequest {}
− LARAVEL 12
class LoginRequest extends FormRequest
{
    protected $stopOnFirstFailure = true;

    protected $redirectRoute = 'login';
}
ФУНКЦІЇ · 1

Нові функції

3.1 · НОВЕ

Cache::touch()

Щоб ключ пожив довше, значення доводилось діставати з cache і класти назад з новим TTL. Виходило два звернення до Redis чи бази, а великий обʼєкт ганявся туди й назад. touch() повертає true, якщо ключ існує і TTL оновлено, і false, якщо ключа вже немає.

+ LARAVEL 13
Cache::touch('report:42', 3600);
Cache::touch('report:42', now()->addHours(2));
− LARAVEL 12
$report = Cache::get('report:42');
Cache::put('report:42', $report, 3600);
ПРОДУКТИВНІСТЬ · 1

Продуктивність

4.1 · 13.x

Pooled-зʼєднання PostgreSQL

Керовані PostgreSQL часто дають transaction pooler на кшталт PgBouncer, і з 13.17 Laravel вміє з ним працювати. Запитам застосунку pooler підходить, а міграціям і службовим командам потрібне пряме зʼєднання. З опцією pooled Laravel вмикає emulated prepares і сам відправляє migrate, schema dump, db:wipe, db:show і db:table через direct.

+ LARAVEL 13
// config/database.php
'pgsql' => [
    'driver' => 'pgsql',
    // ...
    'pooled' => env('DB_POOLED', false),
    'direct' => array_filter([
        'host' => env('DB_DIRECT_HOST'),
        'port' => env('DB_DIRECT_PORT'),
    ]),
],

DB::connection('pgsql::direct')->statement('create extension if not exists "uuid-ossp"');
БЕЗПЕКА · 3

Безпека

5.1 · НОВЕ

PreventRequestForgery

Сучасні браузери самі ставлять заголовок Sec-Fetch-Site, і запит з того самого origin проходить без звірки токена. Якщо перевірка origin не пройшла, наприклад у старому браузері чи без HTTPS, middleware звіряє _token як раніше. Режим originOnly вимикає токени зовсім і відповідає 403 замість 419, а allowSameSite пускає запити з піддоменів.

+ LARAVEL 13
->withMiddleware(function (Middleware $middleware): void {
    $middleware->preventRequestForgery(except: ['stripe/*'], allowSameSite: true);
})
− LARAVEL 12
->withMiddleware(function (Middleware $middleware): void {
    $middleware->validateCsrfTokens(except: ['stripe/*']);
})
5.2 · 13.x

#[FailOnUnknownFields]

Якщо в запит підкинули is_admin чи інше поле поза правилами, валідація поверне для нього помилку prohibited. Так зайве поле не дійде до create() чи fill(). Увімкнути можна атрибутом для одного запиту або через FormRequest::failOnUnknownFields() для всіх, доступно з 13.4.

+ LARAVEL 13
use Illuminate\Foundation\Http\Attributes\FailOnUnknownFields;

#[FailOnUnknownFields]
class StoreVacancyRequest extends FormRequest
{
    public function rules(): array
    {
        return ['title' => ['required', 'string']];
    }
}

// або для всіх запитів в AppServiceProvider::boot()
FormRequest::failOnUnknownFields();
5.3 · ЗМІНА

Сесії в JSON, cache без обʼєктів

Якщо APP_KEY витече, підроблений серіалізований payload може запустити gadget chain через unserialize(). Тому скелет Laravel 13 серіалізує сесію в JSON, а для cache ставить serializable_classes => false. Хто кешує обʼєкти, перелічує дозволені класи явно.

+ LARAVEL 13
// config/session.php
'serialization' => 'json',

// config/cache.php: false або список дозволених класів
'serializable_classes' => [
    App\Data\CachedDashboardStats::class,
],
DEPRECATED

Застаріло

Ще працює, але дає попередження і зникне в одній із наступних версій.

VerifyCsrfToken і ValidateCsrfTokenЛишились для сумісності як застарілі аліаси PreventRequestForgery.
BREAKING

Ламає сумісність

Перевірте це до оновлення: такий код перестане працювати або поводитиметься інакше.

PHP 8.3Laravel 13 вимагає щонайменше PHP 8.3.
Нові версії залежностейУ composer.json: laravel/framework ^13.0, laravel/tinker ^3.0, laravel/boost ^2.0, phpunit/phpunit ^12.0, pestphp/pest ^4.0.
Laravel installerЩоб створювати проєкти на 13.x, оновіть installer через composer global update або поставте свіжий Herd.
VerifyCsrfToken став PreventRequestForgeryMiddleware перейменовано і він додатково перевіряє Sec-Fetch-Site, тож у withoutMiddleware() в тестах і маршрутах вказуйте новий клас.
cache.serializable_classesЯкщо переносите конфіг зі скелета і кладете в cache PHP-обʼєкти, перелічіть їхні класи, інакше вони не розсеріалізуються.
upsert() з порожнім uniqueByНа MySQL і MariaDB порожній uniqueBy тепер кидає InvalidArgumentException, хоча ці драйвери його ігнорують.
Сесії в JSONЗаміна 'php' на 'json' у config/session.php скине всі активні сесії. Щоб їх зберегти, лишіть 'php'.

Як оновитися

0 / 7