Laravel 6.0 - What`s New?
🍪 печеньеПривет.
Данный пост - перевод секции Release Notes из уже доступной, обновленной документации по новой LTS версии фреймворка Laravel - 6.0. Его релиз состоится уже буквально завтра, а обновления будут выходить вплоть до 3 сентября 2021 года (обновления безопасности - до 3 сентября 2022 года). Перед обновлением не забудьте ознакомиться с изменениями существующего функционала.
И не забывайте заглядывать на мой канал @gtxtymt_xyz, где я публикую дев-мемы (иногда даже смешные).
Итак, каких же нововведений стоит ожидать?
Улучшенные ответы авторизации
В предыдущих версиях Laravel не было возможности легко работать с сообщениями о том, почему при проверке прав через гейты и политики был отклонен определенный запрос. В Laravel 6.0 это стало делать намного проще при помощи ответных сообщений и нового метода Gate::inspect. Например, учитывая следующий метод политики:
/**
* Determine if the user can view the given flight.
*
* @param \App\User $user
* @param \App\Flight $flight
* @return mixed
*/
public function view(User $user, Flight $flight)
{
return $this->deny('Explanation of denial.');
}
...информация об ответе может быть легко получена при помощи Gate::inspect.
$response = Gate::inspect('view', $flight);
if ($response->allowed()) {
// User is authorized to view the flight...
}
if ($response->denied()) {
echo $response->message();
}
Кроме того, пользовательские сообщения будут отображаться при использовании вспомогательных методов, таких как $this->authorize или Gate::authorize.
Middleware для задач
Middleware для задач (jobs) поможет переместить логику выполнения задач в очереди в middleware, тем самым уменьшив количество кода непосредственно в задачах. Например, ранее вы могли установить ограничение скорости выполнения задач в методе handle:
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
Redis::throttle('key')->block(0)->allow(1)->every(5)->then(function () {
info('Lock obtained...');
// Handle job...
}, function () {
// Could not obtain lock...
return $this->release(5);
});
}
В Laravel 6.0 эта логика может быть перемещена в middleware, освободив тем самым метод handle от этого кода.
<?php
namespace App\Jobs\Middleware;
use Illuminate\Support\Facades\Redis;
class RateLimited
{
/**
* Process the queued job.
*
* @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) {
// Lock obtained...
$next($job);
}, function () use ($job) {
// Could not obtain lock...
$job->release(5);
});
}
}
После создания middleware его можно прикрепить к заданию, указав в методе middleware:
use App\Jobs\Middleware\RateLimited;
/**
* Get the middleware the job should pass through.
*
* @return array
*/
public function middleware()
{
return [new RateLimited];
}
"Ленивые" коллекции
Многие уже оценили по достоинству всю мощь и простоту коллекций Laravel. Как дополнение к ним добавлен новый использующий генераторы PHP класс LazyCollection, позволяющий работать в огромными массивами данных, сохраняя при этом низкое использование памяти.
Например, представьте что вашему приложению необходимо обработать лог-файл в несколько гигабайт, используя коллекции Laravel для парсинга файла. Вместо загрузки всего файла в память, "ленивые" коллекции могут хранить в памяти лишь небольшую его часть:
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) {
// Process the log entry...
});
Или представьте, что вам необходимо перебрать 10000 моделей Eloquent. При использовании традиционных коллекций все эти модели будут загружены в память одновременно:
$users = App\User::all()->filter(function ($user) {
return $user->id > 500;
});
Однако начиная с Laravel 6.0 метод cursor в конструкторе запросов был обновлен и теперь возвращает экземпляр LazyCollection. Это позволяет сохранять в память всего одну модель, оставляя неизменным количество запросов.
$users = App\User::cursor()->filter(function ($user) {
return $user->id > 500;
});
foreach ($users as $user) {
echo $user->id;
}
Расширение подзапросов Eloquent
Laravel 6.0 добавляет несколько нововведений при работе с подзапросами баз данных. Например давайте представим, что у нас есть таблица рейсов (flights) и таблицах пунктов назначения (destinations). Таблица рейсов содержит столбец arrived_at со временем прибытия в пункт назначения.
Используя новый функционал мы можем выбрать все пункты назначения и название рейса, который последним прибыл в этот пункт назначения используя один запрос:
return Destination::addSelect(['last_flight' => Flight::select('name')
->whereColumn('destination_id', 'destinations.id')
->orderBy('arrived_at', 'desc')
->limit(1)
])->get();
Кроме того, при помощи обновленного orderBy конструктора запросов мы можем отсортировать все пункты назначения на основе того, когда последний рейс прибыл в этот пункт назначения. Опять же, это все будет сделано в рамках одного запроса в базу данных:
return Destination::orderByDesc(
Flight::select('arrived_at')
->whereColumn('destination_id', 'destinations.id')
->orderBy('arrived_at', 'desc')
->limit(1)
)->get();
Laravel UI
Все фронт-интерфейсы, поставляемые с фреймворком по-умолчанию были перемещены в пакет composer laravel/ui. Это позволит создавать пользовательские интерфейсы отдельно от фреймворка. В результате этого изменения из шаблонов удален весь код Bootstrap и Vue, а также команда make:auth.
Для восстановления традиционных шаблонов вы можете доустановить пакет и использовать команду artisan ui.
composer require laravel/ui php artisan ui vue --auth
Изменения существующего функционала
Я не буду углубляться в изменения, просто пробегусь поверхностно. Подробней читайте в Upgrade Guide.
- Минимальная версия PHP - 7.2.
Авторизация
- Политики авторизации, связанные с контроллерами c использованием метода
authorizeResourceдолжны определять методviewAny, вызываемый в момент обращения кindex. - Если вы переопределили методы
registerиregisteredконтроллераRegisterControllerи не вызываете соответствующие родительские методы - обновите логику, иначе регистрация будет неудачной. - Список аргументов
__constructклассаIlluminate\Auth\Access\Responseбыл изменен. - В контракт
Illuminate\Contracts\Auth\Access\Gateдобавлен новый методinspect.
Carbon
- Carbon 1.x больше не поддерживается.
Конфигурация
- Если вы планируете использовать Laravel Vapor - измените все вхождения
AWS_REGIONв конфигах наAWS_DEFAULT_REGION,.envтакже должен содержать новое имя переменной.
База данных
- Аргументы метода
tableклассаIlluminate\Database\Capsule\Managerобновлены для указания псевдонима таблицы вторым аргументом -public static function table($table, $as = null, $connection = null) - Метод
cursorтеперь возвращает экземплярIlluminate\Support\LazyCollection.
Eloquent
- Метод
updateдля отношенийbelongsToтеперь работает как ah-doc запрос, то есть не обеспечивает защиту от массовых назначений или запуск событий Eloquent. - Метод Eloquent
toArrayтеперь будет приводить любые атрибуты, реализующиеIlluminate\Contracts\Support\Arrayableв массив. - Из-за оптимизации производительности целочисленных типов ключей если в качестве ключа вы используете строку - необходимо указать это в свойстве
protected $keyType = 'string';
Верификация email
- Роут
email/resendизменен сGETнаPOST. - В контракт
Illuminate\Contracts\Auth\MustVerifyEmailдобавлен методgetEmailForVerification, возвращающий адрес email, связанный с объектом (не актуально дляApp\User, так как изменения уже реализованы в трейте).
Хелперы
- Все
str_иarray_хелперы перемещены в пакет composerlaravel/helpersи удалены из фреймворка.
Переводы
- Методы
Lang::transиLang::transChoiceпереводчика переименованы вLang::getиLang::choice. Аналогичные изменения содержатся в контрактеIlluminate\Contracts\Translation\Translator. - Методы
Lang::getиLang::getFromJsonбыли объединены.
Почта
- Удалены драйвера
mandrillиsparkpost.
Уведомления
- Удалена устаревшая часть канала уведомлений Nexmo.
Сброс пароля
PasswordBrokerбольше не занимается проверкой и ограничением пароля, все происходит в классеResetPasswordController.
Очереди
- Команда
queue:workтеперь пытается выполнить задание только 1 раз в случае ошибки (ранее - бесконечно).
Requests
- Фасад
Input, дубликаторRequest, удален.
Планировщик задач
- Метод
betweenтеперь запускает задачу каждую минуту в течении указанного промежутка времени (раньше - каждую минуту между указанными промежутками).
Storage
- Удален драйвер
rackspace.