Laravel 9 — Что нового?

Laravel 9 вышла 8 февраля 2022 года. Релиз содержит следующие нововведения и улучшения: поддержка компонентов Symfony 6, Symfony Mailer, Flysystem 3, улучшенный вывод route:list, драйвера Laravel Scout, новый синтаксис аксессор/мутатор Eloquent  и различных других исправлений ошибок и улучшений удобства использования.

PHP 8.0

Минимальный требования для Laravel 9.x — версия PHP 8.0.

Symfony Mailer

Предыдущие релизы Laravel для отправки почты использовали библиотеку Swift Mailer. Однако эта библиотека больше не поддерживается, и ее заменили на Symfony Mailer.

Пожалуйста, просмотрите руководство по обновлению, чтобы узнать как обеспечить совместимость вашего приложения.

Flysystem 3

Система Flysystem обновлена до третьей версии. Flysystem обеспечивает все взаимодействия фреймворка с файловой системой, предлагаемые фасадом Storage.

Пожалуйста, ознакомьтесь с руководством по обновлению, чтобы узнать как обеспечить совместимость вашего приложения.

Улучшенные Аксессоры/Мутаторы Eloquent

Новый способ определения аксессоров и мутаторов Eloquent . Теперь можно делать это в одном методе без префикса, просто указывая тип возвращаемого значения Illuminate\Database\Eloquent\Casts\Attribute:

use Illuminate\Database\Eloquent\Casts\Attribute;

public function name(): Attribute
{
    return new Attribute(
        get: fn ($value) => strtoupper($value),
        set: fn ($value) => $value,
    );
}

Кроме того, этот способ будет кэшировать значения объекта, возвращаемые атрибутом точно также как и кастомные касты:

use App\Support\Address;
use Illuminate\Database\Eloquent\Casts\Attribute;

public function address(): Attribute
{
    return new Attribute(
        get: fn ($value, $attributes) => new Address(
            $attributes['address_line_one'],
            $attributes['address_line_two'],
        ),
        set: fn (Address $value) => [
            'address_line_one' => $value->lineOne,
            'address_line_two' => $value->lineTwo,
        ],
    );
}

Неявные привязки Enums в маршрутах

В PHP 8.1 появилась поддержка Enums. В Laravel 9 теперь есть возможность указывать тип Enum в определении вашего маршрута, и Laravel будет вызывать маршрут только тогда, когда этот сегмент маршрута является допустимым значением Enum в URI. В противном случае будет автоматически выдан ответ HTTP 404. Например, учитывая следующее перечисление:

enum Category: string
{
    case Fruits = 'fruits';
    case People = 'people';
}

Вы можете задать маршрут, который будет вызываться только в том случае, если сегмент {category} имеет значение fruits или people. В противном случае будет возвращен ответ HTTP 404:

Route::get('/categories/{category}', function (Category $category) {
    return $category->value;
});

Приведение атрибутов Enum Eloquent

Работае только на PHP 8.1+.

Eloquent теперь позволяет приводить значения ваших атрибутов к Enum. Для этого нужно указать атрибут и enum в массиве $casts вашей модели:

use App\Enums\ServerStatus;

/**
 * The attributes that should be cast.
 *
 * @var array
 */
protected $casts = [
    'status' => ServerStatus::class,
];

После того, как вы задали приведение каст в своей модели, то указанный атрибут будет автоматически преобразован в enum и из него, при взаимодействии с атрибутом:

if ($server->status == ServerStatus::provisioned) {
    $server->status = ServerStatus::ready;

    $server->save();
}

Принудительные привязки с областью действия

В предыдущих версиях Laravel вы могли заскоупить вторую Eloquent-модель в определении маршрута, чтобы она была дочерней по отношению к первой модели. Например, маршрут, который извлекает сообщение в блоге по слагу для определенного пользователя:

use App\Models\Post;
use App\Models\User;

Route::get('/users/{user}/posts/{post:slug}', function (User $user, Post $post) {
    return $post;
});

При использовании неявной привязки с кастомным ключом в качестве параметра маршрута Laravel автоматически скоупит запрос для извлечения вложенной модели его родителем, используя соглашения, чтобы предугадать его имя. Однако такое поведение ранее поддерживалось только тогда, когда для привязки дочернего маршрута использовался кастомный ключ.

Но теперь вы можете дать указание Laravel использовать скоуп «child», даже если кастомный ключ не назначен. Для этого вы можете вызвать метод scopeBindings при определении вашего маршрута:

use App\Models\Post;
use App\Models\User;

Route::get('/users/{user}/posts/{post}', function (User $user, Post $post) {
    return $post;
})->scopeBindings();

Или вы можете указать всей группе маршрутов использовать скоупы:

Route::scopeBindings()->group(function () {
    Route::get('/users/{user}/posts/{post}', function (User $user, Post $post) {
        return $post;
    });
});

Laravel Breeze API & Next.js

Стартовый комплект Laravel Breeze получил каркасный режим «API» и фронтенд реализацию Next.js. Этот каркас может использоваться для быстрого запуска ваших приложений Laravel, которые служат в качестве бэкэнда, аутентифицированного API Laravel Sanctum для фронтенда JavaScript.

Движок базы данных Laravel Scout

Если ваше приложение взаимодействует с базами данных малого и среднего размера или имеет небольшую рабочую нагрузку, то теперь вы можете использовать движок «базы данных» Scout вместо специализированных служб поиска, таких как Algolia или MeiliSerach. Движок будет использовать запросы вида «where like» и полнотекстовые индексы при фильтрации результатов из вашей существующей базы данных.

Чтобы узнать больше о движке Scout, посмотрите документацию.

Полнотекстовые индексы и операторы Where

При использовании MySQL или PostgreSQL теперь в определении полей можно указывать метод fullText для создания полнотекстовых индексов:

$table->text('bio')->fullText();

Кроме того, методы whereFullText и orWhereFullText можно использовать для добавления полнотекстовых операторов «where» в запрос для полей имеющих полнотекстовый индексы. Эти методы будут преобразованы в соответствующий SQL-запросы для используемой базы данных. Например, для MYSQL будет использоваться MATCH AGAINST:

$users = DB::table('users')
           ->whereFullText('bio', 'web developer')
           ->get();

Рендеринг Blade строк

Иногда вам может понадобиться преобразовать необработанную строку Blade-шаблона в рабочий HTML. Теперь вы можете сделать это, используя метод render, предоставляемый фасадом Blade. Он принимает blade-строку и, необязательный параметр, массив данных для шаблона:

use Illuminate\Support\Facades\Blade;

return Blade::render('Hello, {{ $name }}', ['name' => 'Julian Bashir']);

Проверка данных вложенного массива

Иногда необходимо получить доступ к значению вложенного элемента массива при назначении правил валидации. Теперь можно сделать это с помощью метода Rule::foreEach. Он принимает замыкание, которое будет вызываться для каждой итерации проверяемого атрибута массива, и будет получать значение атрибута и явное, полностью развернутое имя атрибута. Замыкание должно возвращать массив правил для назначения элементу массива:

use App\Rules\HasPermission;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

$validator = Validator::make($request->all(), [
    'companies.*.id' => Rule::forEach(function ($value, $attribute) {
        return [
            Rule::exists(Company::class, 'id'),
            new HasPermission('manage-company', $value),
        ];
    }),
]);

Ярлык названия слота

В предыдущих версиях Laravel название слота бралось из атрибута name тега <x-slot>:

<x-alert>
    <x-slot name="title">
        Server Error
    </x-slot>

    <strong>Whoops!</strong> Something went wrong!
</x-alert>

Начиная с Laravel 9 вы можете использовать более короткий синтаксис:

<x-slot:title>
    Server Error
</x-slot>

Blade-директивы checked и selected

С помощью директивы @checked вы легко можете указать, установлен ли флаг для данного чекбокса. Если условие true, то выводится checked.

<input type="checkbox"
        name="active"
        value="active"
        @checked(old('active', $user->active)) />

Точно также работает директива @selected, которая используется для показа выбранного пункта в списке.

<select name="version">
    @foreach ($product->versions as $version)
        <option value="{{ $version }}" @selected(old('version') == $version)>
            {{ $version }}
        </option>
    @endforeach
</select>

Улучшенный вывод списка маршрутов

Вывод результата команды route:list значительно улучшен:

Отображение покрытия кода тестами

Команда php artisan test получила новую опцию --coverage, которая показывает объем покрытия кода тестами.

php artisan test --coverage

Результаты покрытия отображаются непосредственно в командой строке.

Кроме того, вы можете задать минимальный процент покрытия с помощью опции --min. Набор тестов завершится ошибкой, если заданный порог не будет достигнут:

php artisan test --coverage --min=80.3

Улучшенная поддержка Коллекций в IDE

Laravel 9 в пакет коллекций добавляет улучшенные определения типов в стиле дженериков для использования в IDE и системах статического анализа. PHPStorm, PHPStan и им подобные инструменты теперь будут лучше понимать Коллекции Laravel.

Soketi Echo сервер

Добавлена поддержка Soketi — сервера веб-сокетов написанного для Node.js, совместимого с Laravel Echo. Soketi с открытым исходным кодом предоставляет отличную альтернативу Pusher и Ably для приложений, которые предпочитают содержать собственный Web Socket сервер.

Для получения дополнительной информации об использовании Soketi, смотрите документацию.

Шаблоны пагинации Bootstrap 5

Теперь можно использовать пагинацию созданные с помощью Bootstrap 5. Для того, чтобы их подключить вместо дефолтного Tailwind, нужно вызвать метод пагинатора useBootstrapFive в методе boot провайдера App\Providers\AppServiceProvider:

use Illuminate\Pagination\Paginator;

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    Paginator::useBootstrapFive();
}

Ignition —улучшенная страница ошибок

Опенсорсный пакет Ignition для отладки исключений был переработан с нуля. Новая версия устанавливается вместе Laravel 9 и включает в себя светлые/темные темы, настраиваемую функцию «открыть в редакторе» и многое другое.

Новые хелперы

str

Функция str возвращает новый экземпляр Illuminate\Support\Stringable для данной строки. Эта функция эквивалентна методу Str::of:

$string = str('Taylor')->append(' Otwell');

// 'Taylor Otwell'

Если функции не предоставлен аргумент str, то функция возвращает экземпляр Illuminate\Support\Str:

$snake = str()->snake('LaravelFramework');

// 'laravel_framework'

to_route

Функция to_route генерирует редирект для заданного именованного маршрута:

return to_route('users.show', ['user' => 1]);

При необходимости вы можете передать код HTTP-состояния и любые дополнительные заголовки ответов в качестве третьего и четвертого аргументов:

return to_route('users.show', ['user' => 1], 302, ['X-Framework' => 'Laravel']);

 

Автор: Laravel
Перевод: Алексей Широков

Наш Телеграм-канал — следите за новостями о Laravel.