9 интересных новшеств в Laravel 9

от автора

иллюстрация © GOLTS
иллюстрация © GOLTS

Я сразу, как только вышла новость о релизе, решил, что нужно посмотреть, пощупать и разобраться, чего же изменилось. Да-да, на днях, а именно 8 февраля 2022, вышел официальный релиз Laravel 9, который включает довольно много новых улучшений. Для тех же из нас, кто не боится таких слов, как alfa и beta, девятая версия фреймворка давно не новость и уже в работе.

Теперь эта версия будет поддерживаться дольше (LTS), и разработчики фреймворка пришли к решению не выпускать новые версии каждые 6 месяцев, а делать это раз в год — в феврале. Судя из расписания, эта версия останется актуальной год, а обновления безопасности будут выпускаться вплоть до 2025 года.

Версия

Язык

Дата релиза

Выпуск багфиксов

Выпуск патчей безопасности

6 (LTS)

7.2 — 8.0

3 сен 2019

25 янв 2022

6 сен 2022

7

7.2 — 8.0

3 марта 2020

6 окт 2020

3 марта 2021

8

7.3 — 8.1

8 сен 2020

26 июля 2022

24 янв 2023

9 (LTS)

8.0 — 8.1

8 фев 2022

8 фев 2024

8 фев 2025

10

8.0 — 8.1

7 фев 2023

7 авг 2024

7 фев 2025

Версия языка

Новый Laravel работает только с php 8.0 и выше. Почему это так? Как мы увидим далее, разработчики воплотили в девятом фреймворке немало фишек последней версии языка, а значит, что использование php7 означало бы потерю именно этих нововведений.

composer create-project laravel/laravel example-app

Команда создала директорию, наполнила ее файлами нового проекта и установила зависимости, среди которых основным является laravel/framework версии v9.0.2. Как видим, релизную версию уже патчат.

Новые помощники

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

Добавленная функция str создает объект класса Illuminate\Support\Stringable для переданной строки. Это позволяет применять к тексту все методы манипуляции строкой, доступные данному классу. Такая возможность существовала и в 8 версии фреймворка и реализовывалась через Str::of, но теперь получается немного лаконичнее.

<?php  Route::get('/', function () {     return str('Hello, ') // Создаем класс из строки       ->append('Max')     // Метод добавления в конец строки       ->upper();          // Метод делает все буквы строки заглавными });

Функция to_route создает редирект на существующий роут по его имени. Мы можем воспользоваться ей как в наших роутах, так и вернуть ее результат из метода контроллера.

<?php  // Главная страница Route::get('/', function () {     return view('welcome'); })->name('home'); // Имя роута для главной страницы  // Старый способ редиректа по имени роута Route::get('/test', function () {     return redirect()->route('home'); });  // Новый способ редиректа с помощью функции to_route Route::get('/new_test', function () {     return to_route('home'); });

А еще мы можем передавать в новую функцию параметры роута, статус HTTP и дополнительные заголовки:

<?php  Route::get('/', function () { return to_route('users.show',    // Наименование роута   ['user' => 1],                 // Параметры роута     302,                           // Код статуса редиректа     ['X-Framework' => 'Laravel']); // Дополнительные заголовки });

Также благодаря базированию на языке PHP 8, в классе \Illuminate\Support\Str добавилась поддержка таких функций для работы со строкой как str_contains(), str_starts_with() и str_ends_with().

Страница исключений

Встроенная в фреймворк страница сообщения об исключении была и раньше крайне удобной, информативной и симпатичной. Теперь в ней изменилось оформление. Добавлены возможность переключения темы на светлую/темную, настройка функционала «открыть в редакторе» и др.

Темное оформление мне понравилось даже больше, чем Dracula в IDE
Темное оформление мне понравилось даже больше, чем Dracula в IDE

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

Тема меняется очень красиво
Тема меняется очень красиво

Анонимные миграции

Возможность создавать миграции в виде анонимных классов появилось чуть ранее в Laravel 8.37. А затем в 9 — это стало своего рода стандартом, и при вызове консольной команды php artisan make:migration создается класс без названия, расширяющий Migration. Довольно таки небольшое изменение, но мне показалось достаточно интересным, чтобы отметить и его.

Миграция, добавляющаяся в database/migrations при создании проекта:

<?php  use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema;  return new class extends Migration {     /**      * Run the migrations.      *      * @return void      */     public function up()     {         Schema::create('password_resets', function (Blueprint $table) {             $table->string('email')->index();             $table->string('token');             $table->timestamp('created_at')->nullable();         });     }      /**      * Reverse the migrations.      *      * @return void      */     public function down()     {         Schema::dropIfExists('password_resets');     } };

Общий контроллер

Используя методы роутера controller и group, появилась возможность объединять несколько роутов в одну группу с общим для них контроллером. Это довольно удобно и позволяет экономить на количестве кода, не указывая одно и тоже в нескольких строках. Если раньше нам пришлось бы писать как-то так:

<?php use \App\Http\Controllers\UsersController;  Route::get('/users', [UsersController::class, 'index']); Route::get('/users/{id}', [UsersController::class, 'showOne']);

То теперь можно это сгруппировать:

<?php use \App\Http\Controllers\UsersController;  Route::controller(UsersController::class)->group(function () {   Route::get('/users', 'index');   Route::get('/users/{id}', 'showOne'); });

Scoped Bindings в роутерах

Благодаря усилиям разработчика из Амстердама Клаудио Деккера (Claudio Dekker) была реализована и внедрена удобная возможность связывать параметры строки запроса между собой. Лично я не сразу смог понять, что за связанность такая, но на примере кода все становится «ясно-понятно».

Предположим, что мы создали таблицы с пользователями и статьями, причем каждая статья относится к определенному пользователю, как многое-к-одному. То есть у каждого пользователя есть статьи, которые он написал. И вот мы сделали url для вывода списка статей: /users/{user}/posts. Отсюда логично построить url для вывода отдельной статьи конкретного пользователя по следующей ссылке: /users/{user}/posts/{post}.

Мы используем два параметра независимых друг от друга для идентификаторов пользователя и статьи. Это позволит сопоставлять любого пользователя с любым постом. Конечно, этого нам не нужно, но и делать проверку вручную — идея так себе. Новый метод scopeBindings сделает это за нас.

<?php  use App\Models\Post; use App\Models\User;  Route::get('/users/{user}/posts/{post}', function (User $user, Post $post) {     return $post; })->scopeBindings();

Теперь, если мы попытаемся открыть статью несоответствующую пользователю (связь по внешнему ключу в таблице с другим пользователем), то получим страницу 404 ошибки:

Страница ошибка с оформлением по умолчанию
Страница ошибка с оформлением по умолчанию

Также есть возможность объединить в одну группу роуты, для которых важно соблюдение связывания параметров:

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

Laravel Scout

Полнотекстовый поиск по отдельным параметрам Eloquent моделей, основанный на драйвере базы данных — вот, что представляет из себя этот Scout. Он отлично подходит для поиска по тексту в небольших и даже среднего размера базах. Если наша база вполне умещается на одном сервере, тогда мы можем не использовать такие драйверы как Algolia или MeiliSerach, а воспользоваться простым и удобным Scout с драйвером MySQL/PostgreSQL.

Для начала нужно установить Laravel Scout и выбрать его провайдер-класс для полнотекстового поиска:

composer require laravel/scout php artisan vendor:publish  Which provider or tag's files would you like to publish?:   [0 ] Publish files from all providers and tags listed below   [1 ] Provider: Fruitcake\Cors\CorsServiceProvider   [2 ] Provider: Illuminate\Foundation\Providers\FoundationServiceProvider   [3 ] Provider: Illuminate\Mail\MailServiceProvider   [4 ] Provider: Illuminate\Notifications\NotificationServiceProvider   [5 ] Provider: Illuminate\Pagination\PaginationServiceProvider   [6 ] Provider: Laravel\Sail\SailServiceProvider   [7 ] Provider: Laravel\Sanctum\SanctumServiceProvider   [8 ] Provider: Laravel\Scout\ScoutServiceProvider   [9 ] Provider: Laravel\Tinker\TinkerServiceProvider   [10] Provider: Spatie\LaravelIgnition\IgnitionServiceProvider   [11] Tag: cors   [12] Tag: laravel-errors   [13] Tag: laravel-mail   [14] Tag: laravel-notifications   [15] Tag: laravel-pagination   [16] Tag: sail   [17] Tag: sail-bin   [18] Tag: sail-docker   [19] Tag: sanctum-config   [20] Tag: sanctum-migrations  > 8    Copied File [/vendor/laravel/scout/config/scout.php] To [/config/scout.php]

Был создан конфигурационный файл для Scout. И в нем мы можем установить нужный нам драйвер database.

Настройки посковика Scout
Настройки посковика Scout

Теперь можно настраивать поиск по в классах — моделях, чтобы определить какие модели имеют поддержку полнотекстового поиска и по каким полям. И обязательно добавим трейт Searchable к модели, что позволит использовать все необходимые нам методы поиска. Как видно из скриншота ниже, кроме имени я добавил поиск и к нестандартному полю bio (биография).

Метод toSearchableArray возвращает массив полей для поиска
Метод toSearchableArray возвращает массив полей для поиска

Поищем всех пользователей, у которых в биографии есть упоминание обучения в ВУЗе.

<?php  Route::get('/', function () {     return \App\Models\User::search('институт')->get(); })->name('home');

Полнотекстовая индексация

Если мы пользуемся такими реляционными системами БД как MySQL или PostgreSQL, то можем прям в миграции добавить для текстовых полей полнотекстовую индексацию. При чем это делается всего лишь вызовом одного метода:

<?php  $table->text('bio')->fulltext();

По таким полям мы можем искать специальными методами полнотекстового поиска whereFullText и orWhereFullText, добавляя их как условие where. Эти методы преобразуются в SQL запросы поиска по индексу текста.

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

Покрытие кода тестами

В Laravel 9 мы теперь можем генерировать отчет о покрытии кода тестами с помощью консольной команды php artisan test. Давайте посмотрим, что отобразится, если запустить команду как и раньше.

Тесты успешно выполнились
Тесты успешно выполнились

Если посмотрим подсказку по команде запуска тестов, то увидим 2 новых ключа --coverage и --min[=MIN].

php artisan help test  Usage:   test [options]  Options:       --without-tty         Disable output to TTY       --coverage            Indicates whether code coverage information should be collected       --min[=MIN]           Indicates the minimum threshold enforcement for code coverage

Coverage — указывает, следует ли собирать информацию о покрытии кода.

Min — минимальное пороговое значение для покрытия кода. Другими словами, это возможность указать, какой минимальный уровень покрытия кода тестами для нас удовлетворителен.

Я запускаю команду в консоли, но вижу ошибку.

Ошибка запуска команды
Ошибка запуска команды

Не установлен драйвер, но, думаю, это легко починить, установив Xdebug для php. Как несложно было догадаться по скриншотам, у меня MacOS, поэтому воспользуюсь встроенными утилитами для установки и перезапуска сервисов. Предположу, что на другие ОС установка не намного сложнее.

pecl install xdebug brew services restart php brew services restart nginx
После установки xdebug и перезагрузки сервисов
После установки xdebug и перезагрузки сервисов

Казалось бы, запускаем команду и радуемся результату, но нет, опять ошибка.

Xdebug ругается :(
Xdebug ругается 🙁

Xdebug ругается о том, что не установлен режим покрытия кода тестами. Это мы легко исправляем и видим красивое описание покрытия кода.

Пару слов в конце

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


ссылка на оригинал статьи https://habr.com/ru/company/reksoft/blog/651553/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *