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

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

Laravel 8 вышел 8 сентября 2020 года и содержит следующие нововведения и улучшения.

Laravel Jetstream

Laravel Jetstream — это прекрасно сдизайненный каркас приложений для Laravel. Идеальная отправная точка для создания сайтов, которая включает в себя систему регистрации и логина, верификации почты, двухфакторную аутентификацию, управление сессиями, поддержку API через Laravel Sanctum и опциональный менеджмент команды. Laravel Jetstream заменяет и улучшает устаревший каркас аутентификации предыдущих версий Laravel.

Jetstream разработан с использованием Tailwind CSS и предлагает на ваш выбор каркасы Livewire и Inertia.

Каталог моделей

По многочисленным просьбам в Laravel теперь по дефолту есть каталог app/Models. Надеемся, что вам понравится новый дом для ваших Eloquent-моделей! Все соответствующие команды генератора обновлены. Они учитывают наличие новой директории и работают с моделями в ней. Если же такой директории нет, то фреймворк размещает модели в корне каталога app.

Классы фабрики моделей

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

namespace Database\Factories;

use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

class UserFactory extends Factory
{
    /**
     * The name of the factory's corresponding model.
     *
     * @var string
     */
    protected $model = User::class;

    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        return [
            'name' => $this->faker->name,
            'email' => $this->faker->unique()->safeEmail,
            'email_verified_at' => now(),
            'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
            'remember_token' => Str::random(10),
        ];
    }
}

Благодаря новому трейту HasFactory, доступному для сгенерированных моделей, фабрика моделей может использоваться следующим образом:

use App\User;

User::factory()->count(50)->create();

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

Например, ваша модель User может иметь состояние suspended, изменяющее одно из её дефолтный значений атрибута. Вы можете задать свои преобразования состояний, используя метод state из базовой фабрики. Свой метод состояния вы можете называть как угодно. В конце концов, это просто обычный PHP-метод:

/**
 * Указываем, что пользователь заблокирован (suspended)
 *
 * @return \Illuminate\Database\Eloquent\Factories\Factory
 */
public function suspended()
{
    return $this->state([
        'account_status' => 'suspended',
    ]);
}

После определения метода преобразования состояния мы можем использовать его таким образом:

use App\User;

User::factory()->count(5)->suspended()->create();

Как уже упоминалось, в Laravel 8 фабрики моделей содержат первоклассную поддержку отношений. Предположим, что наша модель User имеет метод отношений posts, соответственно, мы можем просто запустить следующий код, чтобы сгенерировать пользователя с тремя сообщениями:

$users = User::factory()
            ->hasPosts(3, [
                'published' => false,
            ])
            ->create();

Чтобы упростить процесс обновления, был выпущен пакет laravel/legacy-factoryies, обеспечивающий в Laravel 8 поддержку предыдущей итерации фабрик моделей.

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

Сжатие миграции

По мере создания приложения накапливается все больше и больше миграций. Со временем каталог может стать потенциально огромным из-за сотен файлов миграций. Теперь, если захотите, вы можете «сжать» все свои миграции в один SQL-файл. Для начала выполните команду schema:dump

php artisan schema:dump

// Сдампить текущую схему базы данных и удалить все существующие миграции
php artisan schema:dump --prune

В результате выполнения этой команды, Laravel запишет файл «схемы» в ваш каталог. Теперь, когда вы попытаетесь перенести свою базу данных, и никакие другие миграции еще не выполнялись, то Laravel сначала запустит SQL-файл схемы. После выполнения команд из файла схемы Laravel выполнит все оставшиеся миграции, которые не были частью дампа.

Пакетирование задач

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

Новый метод batch фасада Bus может использоваться для отправки пакета задач. Пакетирование, в первую очередь, практично в сочетании с коллбэками завершения. Таким образом, вы можете использовать методы then, catch и finally для определение коллбэков завершения для пакета. Каждый из этих коллбэков получит экземпляр Illuminate\Bus\Batch.

use App\Jobs\ProcessPodcast;
use App\Podcast;
use Illuminate\Bus\Batch;
use Illuminate\Support\Facades\Batch;
use Throwable;

$batch = Bus::batch([
    new ProcessPodcast(Podcast::find(1)),
    new ProcessPodcast(Podcast::find(2)),
    new ProcessPodcast(Podcast::find(3)),
    new ProcessPodcast(Podcast::find(4)),
    new ProcessPodcast(Podcast::find(5)),
])->then(function (Batch $batch) {
    // All jobs completed successfully...
})->catch(function (Batch $batch, Throwable $e) {
    // First batch job failure detected...
})->finally(function (Batch $batch) {
    // The batch has finished executing...
})->dispatch();

return $batch->id;

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

Улучшенное ограничение скорости

Функция ограничения частоты запросов в Laravel стала более гибкой и мощной, при этом сохранив обратную совместимость с API мидлвара throttle прошлой версии.

Ограничители скорости определяются с помощью метода for из фасада RateLimiter. Метод принимает название ограничителя и Замыкание, возвращающее настройку ограничения, которое должно применяться к маршрутам, присвоенных этому ограничителю:

use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;

RateLimiter::for('global', function (Request $request) {
    return Limit::perMinute(1000);
});

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

RateLimiter::for('uploads', function (Request $request) {
    return $request->user()->vipCustomer()
                ? Limit::none()
                : Limit::perMinute(100);
});

Иногда нужно сегментировать ограничения на некоторое произвольное значение. Например, вы можете разрешить пользователям доступ к заданному маршруту 100 раз в минуту на каждый IP-адрес. Для этого вы можете использовать метод by при задании лимита:

RateLimiter::for('uploads', function (Request $request) {
    return $request->user()->vipCustomer()
                ? Limit::none()
                : Limit::perMinute(100)->by($request->ip());
});

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

Route::middleware(['throttle:uploads'])->group(function () {
    Route::post('/audio', function () {
        //
    });

    Route::post('/video', function () {
        //
    });
});

Чтобы узнать больше об ограничителях, смотрите документацию по маршрутизации.

Улучшенный режим обслуживания

В предыдущих версиях Laravel функцию режим обслуживания php artisan down можно было обойти с помощью списка разрешенных IP-адресов. Эта фишка удалена в пользу более простого решения «секрет»/токен.

Находясь в режиме обслуживания, вы можете использовать опцию secret, чтобы указать токен обхода режима обслуживания:

php artisan down --secret="1630542a-246b-4b66-afa1-dd72a4c43515"

После перевода приложения в режим обслуживания вы можете перейти на URL-адрес приложения, соответствующий этому токену, и Laravel выдаст вашему браузеру cookie обхода режима обслуживания:

https://example.com/1630542a-246b-4b66-afa1-dd72a4c43515

При доступе к этому скрытому маршруту вы будете перенаправлены на адрес / . Как только cookie будет отправлен вашему браузеру — вы сможете просматривать приложение в обычном режиме, как если бы оно не находилось в режиме обслуживания.

Предварительный рендеринг шаблона режима обслуживания

Когда вы используете команду php artisan down во время развертывания, то ваши пользователи могут иногда сталкиваться с ошибками во время обновления ваших Composer-зависимостей или других компонентов инфраструктуры. Это происходит потому, что предварительно должна подгрузиться значительная часть фреймворка, чтобы определить, находится ли ваше приложение в режиме обслуживания, и отобразить страницу режима обслуживания с помощью механизма шаблонов.

По этой причине теперь Laravel позволяет вам заранее отрендерить шаблон режима обслуживания, который будет возвращен в самом начале цикла запроса. Этот шаблон отображается до загрузки любых зависимостей вашего приложения. Вы можете предварительно выбрать шаблон с помощью опции render команды down:

php artisan down --render="errors::503"

Добавление Замыканий / Цепочка catch

Используя новый метод catch, теперь вы можете предоставить Замыкание, которое должно быть выполнено, если Замыкание в очереди не удалось выполнить после исчерпания всех попыток:

use Throwable;

dispatch(function () use ($podcast) {
    $podcast->publish();
})->catch(function (Throwable $e) {
    // Эта задача сфейлилась...
});

Динамические Blade-компоненты

Иногда вам может потребоваться отрендерить компонент, но вы, до момента выполнения, не знаете, какой компонент вам потребуется. В этой ситуации теперь вы можете использовать встроенный компонент dynamic-component, базирующийся на значении или переменной.

<x-dynamic-component :component="$componentName" class="mt-4" />

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

Улучшения Слушателя Событий (Event Listener)

Слушатели событий, основанные на замыкании, теперь могут быть зарегистрированы только путем передачи Замыкания в метод Event::listen. Laravel проверит Замыкание, чтобы определить, какой тип события обрабатывает слушатель:

use App\Events\PodcastProcessed;
use Illuminate\Support\Facades\Event;

Event::listen(function (PodcastProcessed $event) {
    //
});

Кроме того, Слушатели событий, на основе Замыканий теперь могут быть помечены как queueable с помощью функции Illuminate\Events\queueable

use App\Events\PodcastProcessed;
use function Illuminate\Events\queueable;
use Illuminate\Support\Facades\Event;

Event::listen(queueable(function (PodcastProcessed $event) {
    //
}));

Как и для задач в очередях, вы можете использовать методы onConnection, onQueue и delay для настройки выполнения очереди слушателей:

Event::listen(queueable(function (PodcastProcessed $event) {
    //
})->onConnection('redis')->onQueue('podcasts')->delay(now()->addSeconds(10)));

Если вы хотите обрабатывать фейлы анонимного слушателя в очереди, то вы можете предоставить Замыкание в метод catch при задании queueable-слушателя:

use App\Events\PodcastProcessed;
use function Illuminate\Events\queueable;
use Illuminate\Support\Facades\Event;
use Throwable;

Event::listen(queueable(function (PodcastProcessed $event) {
    //
})->catch(function (PodcastProcessed $event, Throwable $e) {
    // Слушатель в очереди сфейлился...
}));

Хелперы тестирования времени

При тестировании иногда может потребоваться изменить время, возвращаемое такими хелперами, как now или Illuminate\Support\Carbon::now(). Базовый класс тестирования теперь содержит хелперы, которые позволят вам управлять текущим временем:

public function testTimeCanBeManipulated()
{
    // Путешествуем в будущее...
    $this->travel(5)->milliseconds();
    $this->travel(5)->seconds();
    $this->travel(5)->minutes();
    $this->travel(5)->hours();
    $this->travel(5)->days();
    $this->travel(5)->weeks();
    $this->travel(5)->years();

    // Путешествуем в прошлое...
    $this->travel(-5)->hours();

    // Путешествуем в определённое время...
    $this->travelTo(now()->subHours(6));

    // Возвращаемся в настоящее время...
    $this->travelBack();
}

Улучшение artisan serve

В artisan-команду serve добавлена ​​автоматическая перезагрузка при обнаружении изменений переменных среды в вашем локальном файле .env. Раньше приходилось это делать вручную.

Шаблоны пагинации Tailwind

Пагинатор Laravel теперь по дефолту использует фреймворк Tailwind CSS — настраиваемый, низкоуровневый CSS фреймворк, который предоставляет всё необходимое для создания нестандартных дизайнов без каких-либо раздражающих опциональных стилей, которые не так-то просто было раньше переопределить. Конечно, также остаются доступными шаблоны Bootstrap 3 и 4.

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

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