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

Laravel 6 - what's new

Laravel 6.0 станет версией LTS (Long Term Support) — с поддержкой в течении длительного времени, вплоть до сентября 2022 года. Шестая версия фреймворка продолжает улучшения, сделанные в Laravel 5.8, переход на семантическое управление версиями, совместимость с Laravel Vapor, улучшенные ответы авторизации, мидлвары задач, ленивые коллекции, улучшения подзапросов, извлечение фронтенд каркаса ( frontend scaffolding) в отдельный пакет laravel/ui, и множество других исправлений и улучшений. Официальный релиз запланирован на 3 сентября 2019 года.

Семантическое управление версиями

Фреймворк Laravel (laravel/framework) теперь соответствует стандарту семантического управления версиями. Это делает фреймворк совместимым с другими пакетами Laravel, уже использующими этот стандарт. Цикл выпуска Laravel останется неизменным.

Совместимость с Laravel Vapor

Автор: Taylor Otwell

Laravel 6.0 обеспечивает совместимость с Laravel Vapor, автоматически масштабируемой безсерверной платформой для развертывания Laravel. Vapor абстрагирует сложность управления приложениями Laravel в AWS Lambda, а также сопряжения этих приложений с очередями SQS, базами данных, кластерами Redis, сетями, CloudFront CDN и многим другим.

Улучшенные ответы авторизации (Improved Authorization Responses)

Реализация: Gary Green

В предыдущих версиях Laravel было сложно получать и выставлять пользовательские авторизационные сообщения конечным пользователям. Это затрудняло объяснение им, почему конкретный запрос был отклонен. В Laravel 6.0 делать это теперь намного проще через авторизационные ответные сообщения и новый метод Gate::inspect. Например, учитывая следующий метод политики:

/**
 * Определить, может ли пользователь просматривать данный рейс
 *
 * @param  \App\User  $user
 * @param  \App\Flight  $flight
 * @return mixed
 */
public function view(User $user, Flight $flight)
{
    return $this->deny('Объяснение отказа.');
}

Ответ и сообщение политики авторизации могут быть легко получены при помощи метода Gate::inspect:

$response = Gate::inspect('view', $flight);

if ($response->allowed()) {
    // Пользователь имеет право просматривать рейс...
}

if ($response->denied()) {
    echo $response->message();
}

Кроме того, эти пользовательские сообщения будут автоматически возвращаться на фронтенд при использовании вспомогательных методов, таких как $this->authorize или Gate::authorize из ваших маршрутов или контроллеров.

Мидлвары задач (Job Middleware)

Реализация: Taylor Otwell

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

/**
 * Выполнение задачи
 *
 * @return void
 */
public function handle()
{
    Redis::throttle('key')->block(0)->allow(1)->every(5)->then(function () {
        info('Получена блокировка...');

        // Выполняем задачу...
    }, function () {
        // Блокировка не получена...

        return $this->release(5);
    });
}

В Laravel 6.0 эта логика может быть перемещена в мидлвар задачи, освобождая метод ваш handle задачи от лимитирования скорости:

namespace App\Jobs\Middleware;

use Illuminate\Support\Facades\Redis;

class RateLimited
{
    /**
     * Обработка задачи из очереди
     *
     * @param  mixed  $job
     * @param  callable  $next
     * @return mixed
     */
    public function handle($job, $next)
    {
        Redis::throttle('key')
                ->block(0)->allow(1)->every(5)
                ->then(function () use ($job, $next) {
                    // Получена блокировка...

                    $next($job);
                }, function () use ($job) {
                    // Блокировка не получена...

                    $job->release(5);
                });
    }
}

После создания мидлвара их можно прикрепить к задаче, вернув из метода middleware:

use App\Jobs\Middleware\RateLimited;

/**
 * Получение мидлвара, через которое должна пройти задача
 *
 * @return array
 */
public function middleware()
{
    return [new RateLimited];
}

Ленивые Коллекции

Реализация Joseph Silber

Многим разработчикам нравятся методы Laravel Collection. Чтобы дополнить и без того мощный класс Collection, Laravel 6.0 представляет LazyCollection, использующий генераторы PHP, для работы с очень большими наборами данных, сохраняя при этом низкое потребление памяти.

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

use App\LogEntry;
use Illuminate\Support\LazyCollection;

LazyCollection::make(function () {
    $handle = fopen('log.txt', 'r');

    while (($line = fgets($handle)) !== false) {
        yield $line;
    }
})
->chunk(4)
->map(function ($lines) {
    return LogEntry::fromLines($lines);
})
->each(function (LogEntry $logEntry) {
    // обработка записи лога...
});

Или представьте, что вам нужно перебрать 10 000 моделей Eloquent. При использовании традиционных коллекций Laravel все 10 000 моделей Eloquent должны быть загружены в память одновременно:

$users = App\User::all()->filter(function ($user) {
    return $user->id > 500;
});

Однако, начиная с Laravel 6.0, метод cursor в построителе запросов был обновлен и теперь возвращает экземпляр LazyCollection. Это позволяет вам по-прежнему выполнять только один запрос к базе данных, но одновременно сохранять в памяти только одну модель Eloquent. В этом примере обратный вызов filter не выполняется до тех пор, пока мы не проведем итерацию по каждому пользователю индивидуально, что позволяет значительно сократить использование памяти:

$users = App\User::cursor()->filter(function ($user) {
    return $user->id > 500;
});

foreach ($users as $user) {
    echo $user->id;
}

Расширения Eloquent Subquery

Реализация Jonathan Reinink

Laravel 6.0 представляет ряд новых усовершенствований и улучшений в поддержке подзапросов базы данных. Например, давайте представим, что у нас есть таблица destinations и таблица flight. Таблица flights содержит столбец arrived_at который указывает, когда рейс прибыл в пункт назначения.

Используя новую функцию выбора подзапроса в Laravel 6.0, мы можем выбрать все destinations и название рейса, который последний раз прибыл в этот пункт назначения, используя один запрос:

return Destination::addSelect(['last_flight' => Flight::select('name')
    ->whereColumn('destination_id', 'destinations.id')
    ->orderBy('arrived_at', 'desc')
    ->latest()
    ->limit(1)
])->get();

Кроме того, мы можем использовать новые функции подзапроса, добавленные в функцию orderBy, чтобы отсортировать все пункты назначения на основе того, когда последний рейс прибыл в этот пункт назначения. Опять же, это может быть сделано при выполнении одного запроса к базе данных:

return Destination::orderByDesc(
    Flight::select('arrived_at')
        ->whereColumn('destination_id', 'destinations.id')
        ->orderBy('arrived_at', 'desc')
        ->latest()
        ->limit(1)
)->get();

Laravel UI

Каркас фронтенда, обычно поставляемый с предыдущими версиями Laravel, были перенесен в отдельный пакет laravel/ui. Это позволяет создавать и версионировать пользовательские интерфейсы отдельно от основного фреймворка. В результате этого изменения в дефолтном каркасе фреймворка не будет Bootstrap и Vue. Также была вынесена из фреймворка команда make:auth.

Чтобы восстановить традиционный каракас Vue/Bootstrap, имеющийся в предыдущих версиях Laravel, вы можете установить пакет laravel/ui
и использовать artisan команду ui для установки фронтенд каркаса:

composer require laravel/ui

php artisan ui vue --auth

Что нового в Ларавел 6

Оригинал: Laravel 6.0 Release Notes
Перевод: Алексей Широков

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