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
Вы можете задать маршрут, который будет вызываться только в том случае, если сегмент имеет значение fruits или people . В противном случае будет возвращен ответ HTTP 404:
Route::get('/categories/', 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//posts/', function (User $user, Post $post) < return $post; >);
При использовании неявной привязки с кастомным ключом в качестве параметра маршрута Laravel автоматически скоупит запрос для извлечения вложенной модели его родителем, используя соглашения, чтобы предугадать его имя. Однако такое поведение ранее поддерживалось только тогда, когда для привязки дочернего маршрута использовался кастомный ключ.
Но теперь вы можете дать указание Laravel использовать скоуп « child », даже если кастомный ключ не назначен. Для этого вы можете вызвать метод scopeBindings при определении вашего маршрута:
use App\Models\Post; use App\Models\User; Route::get('/users//posts/', function (User $user, Post $post) < return $post; >)->scopeBindings();
Или вы можете указать всей группе маршрутов использовать скоупы:
Route::scopeBindings()->group(function () < Route::get('/users//posts/', 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' => '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 тега :
Server Error Whoops! Something went wrong!
Начиная с Laravel 9 вы можете использовать более короткий синтаксис:
Server Error
Blade-директивы checked и selected
С помощью директивы @checked вы легко можете указать, установлен ли флаг для данного чекбокса. Если условие true , то выводится checked .
active)) />
Точно также работает директива @selected , которая используется для показа выбранного пункта в списке.
Улучшенный вывод списка маршрутов
Вывод результата команды 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()
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.
Задать вопросы по урокам можно на нашем форуме.
Интеграция Bootstrap шаблона в Laravel приложение
После установки и настройки локального сервера XAMPP на Windows мы рассмотрим интеграцию шаблона Bootstrap в панель администрирования приложения, созданного на основе фреймворка Laravel.
Фреймворк Bootstrap пользуется огромной популярностью среди веб-разработчиков, а объединение шаблонов Bootstrap с Laravel значительно упрощает процесс создания мощных и сложных веб-приложений. Интеграция Bootstrap и Laravel обеспечивает огромные преимущества для разработчиков.
В этом руководстве мы будем использовать тему Bootstrap для оформления панели администратора в Laravel-приложении.

Прежде всего, нам понадобится HTML-шаблон панели администратора для фреймворка Bootstrap. Я скачал пример на сайте creative-tim.com, вы же можете выбрать любой другой.
Шаг 1: установка Laravel и создание проекта
Фреймворк Laravel устанавливают в каталог /var/www с помощью следующей команды:
composer create-project –prefer-dist laravel/laravel laraveltest
Чтобы проверить правильность установки, выполните в командной строке следующую команду:
Результат – версия приложения.
Шаг 2: создание макета
Макет – главный файл проекта, мы добавляем в него CSS и JavaScript. В папке layouts создайте файл dashboard.blade.php и вставьте в него приведенный ниже код:
WebApp @include('includes.sidebar')@include('includes.header') @yield('content') @include('includes.footer')
Затем создайте файл панели администратора, назовите его index.blade.php и вставьте в него следующий код:
@extends('layoutes.dashboard') @section('content') Capacity
105GB
Updated now Revenue
$1,345
Last day Errors
23
In the last hour Followers
+45
Updated now Users Behavior
24 Hours performance
Open Click Click Second Time
Updated 3 minutes ago Email Statistics
Last Campaign Performance
Open Bounce Unsubscribe
Campaign sent 2 days ago 2015 Sales
All products including Taxes
Tesla Model S BMW 5 Series
Data information certified @endsection
Теперь мы создадим файл для генерирования шапки страницы панели администрирования. Назовем этот файл header.blade.php и вставим в него приведенный ниже код:
Для боковой панели страницы создадим файл sidebar.blade.php и вставим в него следующий код:
Следующий код генерирует футер панели администрирования. Вставьте его в созданный файл footer.blade.php :
Запустите проект в браузере – вы увидите администраторскую панель, как на иллюстрации к статье.
Laravel: 20 полезных советов
Итак, я решил составить список из 20 моих любимых советов, которые я размещал в своих аккаунтах в соцсетях, чтобы все могли познакомиться с ними. Они не размещены в каком-то определённом порядке, но я надеюсь, что вы найдёте хотя бы один новый совет, который окажется полезным.
Вступление
Я регулярно публикую небольшие сниппеты и советы в Твиттере (@AshAllenDesign), которые вы можете использовать в своих Laravel-приложениях. Но из-за особенностей социальной сети, старый контент может быть перемещён вглубь ленты и не виден через несколько дней после его публикации.
1. Используйте поля типа DATETIME вместо Boolean
В ваших Laravel приложениях, зачастую можно использовать поля типа DATETIME вместо boolean .
Например, если бы у нас была модель Post , вместо поля is_published типа boolean вы могли бы использовать поле published_at типа DATETIME .
Используя этот подход, вы по-прежнему можете проверить опубликована ли запись, а также получить дополнительную информацию, о том, когда именно она была опубликована.
Возможно вам не нужна точная дата сейчас, но она может быть полезной в будущих функциях (таких, как отчётность).
Например, мы могли бы обновить модель Post , что бы она выглядела следующим образом:
class Post extends Model
public function isPublished(): bool
return $this->published_at !== null;
>
>
Это означает, что мы можем использовать $post->isPublished() для получения логического значения. И мы могли бы использовать $post->published_at для получения даты и времени публикации записи.
Сам фреймворк Laravel использует этот подход для обратимого удаления (soft delete) моделей и устанавливает поле deleted_at при мягком удалении модели.
2. Именование столбцов типа Date и Time
Может быть, весьма полезным использовать соглашение об именовании action_at для ваших полей DATETIME и TIMESTAMP . Это помогает мгновенно распознать является ли поле, с которым вы работаете, полем даты и времени (и, вероятно, экземпляром класса Carbon , если вы выполнили приведение к нему).
Например, вместо использования таких полей как:
- publish_time
- verified_date
- password_reset
Было бы полезнее переименовать их в:
- published_at
- verified_at
- password_reset_at
3. Используйте Матричные Последовательности в Фабриках
Вы можете использовать MatrixSequence в фабриках моделей для создания дополнительных данных для тестов.
User::factory(4)
->state(
new MatrixSequence(
[['first_name' => 'John', 'last_name' => 'Jane']],
[['first_name' => 'Alice', 'last_name' => 'Bob']],
),
)
->create();
Исполнение приведённого выше фрагмента кода создаст четыре записи модели User со следующими полями:
- first_name: John, last_name: Alice
- first_name: John, last_name: Bob
- first_name: Jane, last_name: Alice
- first_name: Jane, last_name: Bob
4. Используйте when в PendingRequest
Вы можете использовать метод when в классе PendingRequest при построении запросов с фасадом http .
Предположим, что у вас есть следующий код:
$http = Http::withBasicAuth($username, $password);
if (app()->environment('local'))
$http->withoutVerifying();
>
Если вы предпочитаете, чтобы логика запроса была объединена, а не разделена с помощью оператора if , вы можете переписать её используя when :
$http = Http::withBasicAuth($username, $password)
->when(app()->environment('local'), function (PendingRequest $request)
$request->withoutVerifying();
>);
При использовании любого из этих подходов нет правильного или неправильного варианта, всё зависит от личных предпочтений в написании кода.
5. Использование директив Blade checked и selected
Когда вы создаёте формы в Blade, вам может понадобиться установить значение checkbox в checked или выбрать из списка select один или несколько элементов option . Для этого вы можете использовать директивы Blade @checked и @selected .
Например, если мы хотим, чтобы checkbox был отмечен, если пользователь активен, мы могли бы использовать следующий подход:
input type="checkbox"
name="active"
value="active"
@checked($user->active) />
Точно так же мы могли бы использовать тот же подход, если бы хотели выбрать определённый option в элементе select с помощью директивы @selected :
select name="version">
@foreach ($product->versions as $version)
option value="" @selected(old('version') == $version)>
/option>
@endforeach
/select>
6. Используйте Mockery::on() в PHPUnit тестах
При написании тестов на Laravel и PHP вам может понадобиться смоделировать класс (такой, как сервис или action). Смоделировав класс, вы можете убедиться, что он был вызван, как ожидалось, с правильными аргументами, но без запуска кода внутри него. Это может быть особенно полезно при тестировании ваших контроллеров.
Вам может захотеться сделать тесты более строгими и убедится, что конкретная модель или объект передаются методу. Для этого вы можете использовать Mockery::on() .
В качестве базового пример возьмём следующий контроллер. Метод контроллера выполняет action PublishPost , при этом action принимает модель Post . Затем мы возвращаем в ответ простой JSON .
// app/Http/Controllers/PublishPostController
use App\Actions\PublishPost;
use App\Models\Post;
class PublishPostController extends Controller
public function __invoke(Post $post, PublishPost $action): Response
$action->execute($post);
return response()->json([
'success' => true,
]);
>
>
В нашем тесте мы можем настроить смоделированный action, до того как мы сделаем HTTP-вызов. В смоделированном методе мы можем указать, что ожидаем, что метод execute будет вызван один раз и ему будет переданная нами модель Post
Если эти критерии соблюдены, ассерты будут пройдены и мы будем знать, что action был вызван так, как мы и ожидали. В противном случае, если критерии не соблюдены, тест не будет выполнен.
// tests/Feature/PublishPostControllerTest
use App\Actions\PublishPost;
use App\Models\Post;
use Mockery;
use Mockery\MockInterface;
use Tests\TestCase;
class PublishPostControllerTest extends TestCase
/** @test */
public function post_can_be_deleted(): void
$post = Post::factory()->create();
$this->mock(PublishPost::class, function (MockInterface $mock) use ($post)
$mock->shouldReceive('execute')
->once()
->withArgs([
Mockery::on(fn (Post $arg): bool => $arg->is($post)),
]);
>);
$this->post(route('post.publish', $post))
->assertOk()
->assertJson([
'success' => true,
]);
>
>
Если вам интересно больше узнать о тестировании, то возможно вас заинтересует статья Laravel: Как сделать ваше приложение более тестируемым
7. Используйте getOrPut() в Коллекциях/Collection
Есть полезный метод getOrPut() , который вы можете использовать в своих Коллекциях. Его можно использовать для извлечения элемента (если он уже существует) или для его вставки и извлечения, если он не существует.
Это может быть полезно при создании коллекции с данными из нескольких источников, и если вы не хотите дублировать элементы в своих данных.
Например, вместо того, что бы писать:
if (! $collection->has($key))
$collection->put($key, $this->builtItem($data));
>
return $collection->get($key);
Вы можете использовать метод getOrPut() следующим образом:
return $collection->getOrPut($key, fn () => $this->buildItem($data));
8. Отладка HTTP Запросов
При отправке HTTP запросов из вашего приложения Laravel с использованием HTTP фасада вы можете захотеть посмотреть дамп запроса. Это может быть чрезвычайно полезно для отладки, и я сам этим пользуюсь во время разработки для устранения проблем с запросами к внешним API.
Для дампа данных запроса, вы можете использовать метод dump() следующим образом:
Http::dump()->get($url);
Точно так же вы можете использовать метод dd , для остановки приложения и вывода данных:
Http::dd()->get($url);
9. Репликация Моделей
В Laravel приложении можно дублировать Модель используя метод replicate() . Это упрощает копирование Моделей.
Я использую эту функциональность в своём блоге для создания копии общего шаблона записи в блоге, который я использую для создания новой статьи.
Например, вы можете продублировать модель следующим образом:
$post = Post::find(123);
$copiedPost = $post->replicate();
$copiedPost->save();
Если вы хотите исключить копирование некоторых свойств, то можете передать их имена в виде массива:
$post = Post::find(123);
$copiedPost = $post->replicate([
'author_id',
]);
$copiedPost->save();
Кроме того, метод replicate() создаёт не сохранённую модель, поэтому вы можете связать вместе со своими обычными методами модели. Например, вы можете скопировать модель и добавить copy в конце заголовка, что бы вы могли видеть, что запись была реплицирована.
$post = Post::find(123);
$copiedPost = $post->replicate([
'author_id',
])->fill([
'title' => $post->title.' (copy)',
]);
$copiedPost->save();
Важно помнить, что модели не сохраняются в базе данных после использования метода replicate() . Итак, вам нужно убедиться, что вы сохраняете их используя метод save .
10. Добавление подсказок автозаполнения к командам artisan
Когда вы создаёте свои artisan-команды в своём приложении Laravel, вы можете использовать метод anticipate для предоставления пользователю подсказок автозаполнения.
Например, у нас может быть команда, которая находит пользователя по электронной почте. В этой команде мы могли бы передать список возможных адресов электронной почты методу anticipate , что бы они отображались на экране когда пользователь начинает печатать:
class TestCommand extends Command
public function handle()
$email = $this->anticipate('Find user by email: ', [
'mail@ashallendesign.co.uk',
'hello@example.com',
]);
>
>
Стоит отметить, что пользователь по-прежнему может ввести ответ, которого нет в списке. Метод anticipate используется только для подсказок, а не для проверки ввода.
11. Использование wasRecentlyCreated в Моделях
Бывают случаи, когда в Laravel приложении нужно проверить, была ли модель извлечена из базы или только что создана, в текущем жизненном цикле запроса — например, при использовании метода firstOrCreate .
Для этого вы можете использовать поле wasRecentlyCreated в модели следующим образом:
$user = User::firstOrCreate(
['email' => request('email')],
['name' => request('name')],
);
if ($user->wasRecentlyCreated)
// Ваш пользователь был только что создан.
> else
// Ваш пользователь уже существует и был получен из базы данных.
>
12. Изменение ключа для привязки Модели к Route
В маршрутах вашего Laravel приложения вы можете изменять ключ, который используется для определения моделей использующих привязку модели к маршруту.
Например, предположим, что у вас есть маршрут, который принимает slug записи в блоге:
Route::get('blog/', [BlogController::class, 'show']);
Затем в нашем контроллере нужно будет вручную попытаться найти запись в блоге. Допустим, внутри контроллера этот метод выглядит так:
use App\Actions\PublishPost;
use App\Models\Post;
class BlogController extends Controller
public function show($slug)
$post = Post::where('slug', $slug)->firstOrFail();
return view('blog.show', [
'post' => $post,
]);
>
>
Чтобы упростить и очистить этот код, мы могли бы заменить в маршруте параметр slug на post:slug :
Route::get('blog/', [BlogController::class, 'show']);
Теперь, мы можем обновить наш метод контроллера на ожидание модели Post в качестве параметра $post , и Laravel автоматически найдёт модель Post которой принадлежит slug переданный в URL.
Это означает, что нам не нужно вручную находить модель в контроллере, и мы можем позволить Laravel определить её следующим образом:
use App\Actions\PublishPost;
use App\Models\Post;
class BlogController extends Controller
public function show(Post $post)
return view('blog.show', [
'post' => $post,
]);
>
>
13. Использование Внедрения Зависимости / Dependency Injection
Внедрение зависимости в коде вашего Laravel приложения позволяет разрешать зависимости от контейнера всякий раз, когда вы создаёте новый класс. Это сделает код лучше поддерживаемым и тестируемым.
В этом примере мы не используем Внедрение Зависимости, а просто создадим новый класс:
class MyController extends Controller
public function __invoke()
$service = new MyService();
$service->handle();
>
>
Теперь мы удалим в первую строку метода и добавим MyService в качестве параметра. Laravel будет при вызове этого метода каждый раз внедрять $service для нас, что бы мы могли его использовать.
class MyController extends Controller
public function __invoke(MyService $service)
$service->handle();
>
>
Также бывают случаи, когда вы находитесь внутри класса, и оказывается, что без серьёзного рефакторинга вы не сможете внедрить свой класс, передав его в качестве дополнительного параметра метода. В таком случае можно использовать хэлпер resolve() предоставляемый Laravel, например:
class MyClass
public function execute()
$service = resolve(MyService::class);
$service->handle();
>
>
14. Фильтрация Коллекций по типу класса
Вы можете фильтровать Коллекции laravel по заданному типу класса, используя метод whereInstanceOf . Это может быть полезным если вы создаёте Коллекции из нескольких источников данных (например, полиморфных отношений) и вам нужно отфильтровать их до определённых классов.
Например, мы могли бы иметь следующую Коллекцию и отфильтровать её, что бы она содержала только класс User :
$collection = collect([
new User(),
new User(),
new User(),
new Comment(),
]);
$filtered = $collection->whereInstanceOf(User::class)->all();
Метод whereInstanceOf() также принимает массив классов, если вы хотите фильтровать более чем по одному классу. Например, что бы отфильтровать Коллекцию так, что бы она содержала только классы Post и Comment , вы можете сделать это следующим образом:
$filtered = $collection->whereInstanceOf([Post::class, Comment::class])->all();
15. Определение пользовательской логики временного URL
Вы можете настроить способ создания временных URL-адресов для отдельных хранилищ данных. Это может быть удобно, если у вас есть контроллер позволяющий загружать файлы в хранилища, которые не поддерживают временные URL-адреса.
Для использования этой функции необходимо зарегистрировать логику (обычно в сервис провайдере) с помощью метода buildTemporaryUrlsUsing .
Вот пример, как мы могли бы зарегистрировать некую пользовательскую логику для создания временных URL-адресов для локального хранилища данных (локального диска):
public function boot()
Storage::disk('local')->buildTemporaryUrlsUsing(function ($path, $expiration, $options)
return URL::temporarySignedRoute(
'files.download',
$expiration,
array_merge($options, ['path' => $path]),
);
>);
>
После регистрации логики, вы можете её использовать функционал с помощью метода temporaryUrl , например так:
$tempUrl = Storage::disk('local')->temporaryUrl('file.jpg', now()->addMinutes(5));
16. Валидация MAC адресов
В Laravel доступно полезное правило mac_address , которое можно использовать для валидации того, является ли поле mac адресом.
Например, следующая проверка будет пройдена, поскольку значение является валидным MAC-адресом:
Validator::make([
'device_mac' => '00:1A:C2:7B:00:47'
], [
'device_mac' => 'mac_address',
])->passes();
Но следующая проверка завершится ошибкой, поскольку значение не является MAC-адресом:
Validator::make([
'device_mac' => 'invalid-mac-address'
], [
'device_mac' => 'mac_address',
])->passes();
17. Шифрование полей в Базе Данных
Вы можете хранить отдельные поля в зашифрованном формате используя задав в свойстве $cast модели значение encrypted для шифруемого поля. Это полезно, если вы храните личные данные в базе данных, которые нуждаются в дополнительной защите в случае взлома данных.
Например, чтобы зашифровать поле my_encrypted_field в модели User , вам нужно обновить свои модель следующим образом:
class User extends Authenticatable
protected $casts = [
'my_encrypted_field' => 'encrypted',
];
>
Вы можете продолжать использовать поле как обычно. Например, что бы обновить значение хранящееся в my_encrypted_field , мы всё ещё можем использовать метод update , как обычно:
$user->update(['my_encrypted_field' => 'hello123']);
Если бы вы сейчас заглянули в базу данных, то не увидели бы значения hello123 в поле my_encrypted_field . Вместо этого вы увидели бы его зашифрованную версию.
Но вы по прежнему можете использовать оригинальное значение в своём коде без внесения каких-либо изменений:
$result = $user->my_encrypted_field;
// $result is equal to: "hello123"
Важно помнить, что шифрование использует APP_KEY приложения, поэтому если он будет скомпрометирован в результате взлома или изменён, можно будет расшифровать зашифрованные поля, хранящиеся в базе данных.
18. Перемещение Логики в Методы
Вместо прямой проверки полей в условных выражениях иногда можно перенести логику в метод.
Это поможет улучшить читаемость кода, а также поможет придерживаться принципа DRY , если вам нужно повторно использовать туже логику (или если логика изменится в будущем).
Например, предположим, что мы хотим проверить, одобрен ли пользователь. Наш код может выглядеть так:
if ($user->approved === Approval::APPROVED)
// Сделать что-то.
>
Но основная проблема с этим подходом заключается в том, что если мы используем его в нескольких местах кодовой базы, то будет сложно его обновлять, если потребуется изменить логику.
Итак, мы можем переместить логику в метод (например, isApproved ) модели User . Теперь мы можем вызывать этот метод, вместо прямой проверки поля.
Например, теперь наша модель может выглядеть так:
// app/Models/User.php
class User extends Model
public function isApproved(): bool
return $this->approved === Approval::APPROVED;
>
>
Это означает, что мы можем использовать этот метод в нашем коде следующим образом:
if ($user->isApproved())
// Сделать что-то.
>
19. Использование различных параметров режима обслуживания
Laravel предоставляет несколько опций режима обслуживания, которые могут быть очень удобны в использовании.
Для перевода вашего приложения в режим обслуживания, вы можете запустить следующую команду:
php artisan down
Вы можете обновлять страницу обслуживания через заданные промежутки времени, чтобы пользователям не приходилось обновлять её в ручную при резервном копировании сайта. Вы можете сделать это, используя параметр —refresh и указать время обновления в секундах, например:
php artisan down --refresh=30
Возможно, вы захотите предоставить себе доступ к приложению, когда оно находится в режиме обслуживания для ваших пользователей. Для этого вы можете использовать параметр —secret и задать его значение.
Например, мы могли бы установить значение —secret , как your-secret-here . Это будет означать, что если вы зайдёте на your-app-domain.com/your-secret-here , вам будет предоставлен доступ и вы сможете просматривать остальную часть приложения как обычно. Вы можете включить режим обслуживания используя параметр —secret :
php artisan down --secret="your-secret-here"
Если вы не хотите использовать страницу 503 режима обслуживания по умолчанию предоставляемую Laravel, вы можете задать свою с помощью опции —render . Например, если мы хотим использовать resources/views/errors/maintenance.blade.php :
php artisan down --render="errors/maintenance.blade.php"
20. Использование Readonly-свойств
В PHP 8.1 вы можете использовать Readonly-свойств . Они чрезвычайно полезны для уменьшения размера DTO (data transfer objects) и облегчения чтения без ненужных геттеров.
Давайте посмотрим, как DTO может выглядеть без readonly-свойств:
class StoreUserDTO
public function __construct(
private string $name,
private string $email,
private string $password,
)
//
>
public function getName(): string
return $this->name;
>
public function getEmail(): string
return $this->email;
>
public function getPassword(): string
return $this->password;
>
>
Теперь давайте взглянем на тот же DTO, используя readonly-свойства:
class StoreUserDTO
public function __construct(
public readonly string $name,
public readonly string $email,
public readonly string $password,
)
//
>
>
Я думаю, вы согласитесь, что второй вариант с использованием readonly-свойств выглядит намного чище и проще для понимания с первого взгляда.
Заключение
Надеюсь эта статья научит вас хотя бы одному новому совету или трюку, который вы сможете использовать в своих приложениях Laravel.
Если эта статья помогла вам, я хотел бы узнать об этом. Кроме того, если у вас есть отзывы по улучшению этой статьи, я то же хотел бы узнать их.
25 Laravel Tips and Tricks
Было время, достаточно недавно, когда PHP и его сообщество ненавидели. Главная шутка была про то, насколько ужасен PHP.
Да, к сожалению, сообщество и экосистема просто были ниже сообществ других современных языков по уровню. Казалось, что предназначение PHP было прожить большинство времени в форме беспорядочных тем для WordPress.
Но позже, на удивление, вещи начали меняться — и достаточно быстро. Как будто пока ведьма помешивала горшочек, из ниоткуда начали появляться новаторские проекты. Наверно, самый заметный проект был Composer: наиболее полный менеджер зависимостей для PHP (как Bundler для Ruby или NPM для Node.js). В прошлом PHP разработчики были вынуждены совладать с PEAR (что было страшным сном, на самом деле), сейчас, благодаря Composer, они могут просто обновить JSON файл, и немедленно подтянуть все нужные зависимости. Здесь — профайлер, там — фреймворк для тестирования. Это занимает секунды.
В переполненном мире PHP фреймворков, как раз, когда CodeIgniter начал выдыхаться, фреймворк Laravel Тэйлора Отвелла возник из пепла, чтобы стать любимцем общества. С таким простым и элегантным синтаксисом, создавать приложения с Laravel и PHP было абсолютной забавой! Далее, c четвертой версией фреймворка, полностью использовавшим Composer, наконец-то показалось, что для сообщества все вещи встают на места.

Хотите миграций (контроль версий базы данных)? Сделано! Как насчёт мощной реализации Active Record? Конечно, Eloquent сделает всё за вас. Как насчёт возможности тестировать? Безусловно! Маршрутизация (роутинг)? Непременно! Что насчёт хорошо протестированного HTTP слоя? Благодаря Composer, Laravel использует много превосходных Symfony компонентов. Когда доходит до дела, есть все шансы, что Laravel уже это может вам предложить!

Раньше PHP был похож на игру Дженга — в одном кубике от того, чтобы развалиться — вдруг, благодаря Laravel и Composer, загорелся свет в конце тоннеля. Так что уберем все намёки, и давайте пороемся во всем, что фреймворк может предложить!
1. Красноречивые запросы*
Laravel предлагает одну из самых мощных реализаций Active Record в мире PHP. Скажем, у вас есть таблица orders вместе с Eloquent моделью Order.
class Order extends Eloquent <>
Мы с легкостью можем выполнить любое количество запросов в базу данных, используя простой и элегантый код PHP. Не надо разбрасываться беспорядочно SQL. Давайте получим все заказы.
Order::all();
Готово! Или, может, эти заказы должны быть отсортированы по дате. Легко:
$orders = Order::orderBy('release_date', 'desc')->get();
А что, если вместо получения записи, нам надо сохранить новый заказ в базу. Мы, конечно, можем это сделать.
$order = new Order; $order->title = 'Xbox One'; $order->save();
Готово! С Laravel, задачи, которые раньше были громоздкими для выполнения, теперь до смеха просты.
* — Eloquent — название реализации Active Record в Laravel, а также в переводе с английского красноречивый.
2. Гибкая маршрутизация (роутинг)
Laravel уникален тем, что может быть использован разными способами. Предпочитаете более простой и похожий на Sinatra роутинг? Laravel легко может это сделать, используя анонимные функции
Route::get('orders', function() < return View::make('orders.index') ->with('orders', Order::all()); >);
Это может быть полезным для маленьких проектов и API, но есть большие шансы, что вам понадобятся контроллеры для большинства ваших проектов. Окей, Laravel это тоже умеет.
Route::get('orders', 'OrdersController@index');
Готово! Заметили, как Laravel растет по мере ваших потребностей? Уровень приспособления — вот, что делает фреймворк таким популярным сегодня.
3. Отношения без проблем
Что мы делаем в объектах, когда нужно определить отношения? Например, задача точно принадлежит пользователю. Как это указать в Laravel? Предположив, что нужные таблицы в базе данных созданы, мы только должны обратиться к связанным Eloquent моделям.
class Task extends Eloquent < public function user() < return $this->belongsTo('User'); > > class User extends Eloquent < public function tasks() < return $this->hasMany('Task'); > >
Всё готово! Давайте получим все задачи пользователя с Для этого нам понадобится всего 2 строчки кода.
$user = User::find(1); $tasks = $user->tasks;
Впрочем, так как мы указали отношение с обеих сторон, если мы захотим получить пользователя, за которым закреплена данная задача, это также легко сделать.
$task = Task::find(1); $user = $task->user;
4. Связь формы с моделью
Очень часто, будет полезным связать форму с моделью. Очевидный пример — когда Вы хотите изменить какую-то запись в базе. Связав форму с моделью, мы можем моментально заполнить поля формы данными из базы.
Так как форма связана с объектом модели Order, в полях будет отображаться данные из таблицы. Вот так просто!
5. Кеш запросов в базу
Слишком много запросов в базу, и достаточно быстро Ваше приложение может стать, как черная патока. К счастью, Laravel предоставляет простой механизм кеширования этих запросов, используя всего один вызов метода.
Давайте получим все вопросы из базы данных, но при этом закешируем запрос, так как вряд ли эта таблица будет часто изменяться.
$questions = Question::remember(60)->get();
Вот и всё! Теперь, в течение следующего часа, этот запрос будет храниться в кеше, и база будет нетронутой.
6. Композиторы шаблонов
Вы столкнётесь с ситуациями, когда несколько шаблонов потребуют некоторую переменную или кусок данных. Хороший пример этого — навигационное меню, которое отображает список тегов.
Чтобы контроллеры были с минимальным кодом, Laravel предлагает композиторы шаблонов (вьюшек), чтобы управлять такими вещами.
View::composer('layouts.nav', function($view) < $view->with('tags', ['tag1', 'tag2']); >);
Использовав этот кусок кода, в любой момент, когда подгружен файл layouts/nav.blade.php, у него (у файла) будет доступ к переменной $tags.
7. Простая авторизация
Laravel использует очень простой подход к авторизации. Просто передайте массив данных, которые Вы, скорее всего, получили из формы логина, в Auth::attempt(). Если предоставленный массив соответствует тому, что сохранено в таблице users, пользователь моментально будет авторизован.
$user = [ 'email' => 'email', 'password' => 'password' ]; if (Auth::attempt($user)) < // пользователь авторизован >
Что если надо произвести выход при переходе, например на /logout URI?
Route::get('logout', function() < Auth::logout(); return Redirect::home(); >);
8. Ресурсы
Работать RESTfully в Laravel также очень легко! Чтобы объявить контроллер ресурс, просто вызовите Route::resource() следующим образом.
Route::resource('orders', 'OrdersController');
Этот код зарегистрирует 8 роутов.
- GET /orders
- GET /orders/:order
- GET /orders/create
- GET /orders/:order/edit
- POST /orders
- PUT /orders/:order
- PATCH /orders/:order
- DELETE /orders/:order
Далее, OrdersController может быть сгенерирован из командной строки:
php artisan controller:make OrdersController
В этом контроллере, каждый метод будет соответствовать одному из роутов, описанных выше. Например, /orders вызовет метод index, /orders/create — метод create и так далее.
Теперь у нас есть необходимая сила, чтобы с легкостью строить RESTful приложения и API.
9. Шаблонизатор Blade
Да, PHP по натуре язык шаблонов, но он не стал слишком хорошим. Впрочем, ничего страшного. Laravel предлагает свой движок Blade, чтобы восполнить пробел. Просто назовите ваши шаблоны с расширением .blade.php, и они соответствующим образом будут парситься. Теперь мы можем делать следующее:
-
@foreach($orders as $order)
- title >> @endforeach
10. Средства для тестирования
Так как Laravel использует Composer, мы тотчас имеет поддержку PHPUnit “из коробки”. Установите фреймворк и запустите phpunit из командной строки, чтобы протестировать.
В дополнение к этому Laravel предлагает некоторое количество хелперов для некоторых общих типов функциональных тестов
Давайте проверим, что домашняя страница возвращает код ответа 200.
public function test_home_page() < $this->call('GET', '/'); $this->assertResponseOk(); >
Или, может, мы хотим проверить, что, когда контактная форма отправлена на сервер, пользователь перенаправлен на домашнюю страницу с сообщением.
public function test_contact_page_redirects_user_to_home_page() < $postData = [ 'name' =>'Joe Example', 'email' => 'email-address', 'message' => 'I love your website' ]; $this->call('POST', '/contact', $postData); $this->assertRedirectedToRoute('home', null, ['flash_message']); >
11. Компонент “Дистанционное управление”
Частью Laravel 4.1, который был выпущен в ноябре 2013, стала возможность написать консольную команду для Artisan, чтобы по SSH подключаться к серверу и выполнять любые действия. Просто используйте SSH фасад:
SSH::into('production')->run([ 'cd /var/www', 'git pull origin master' ]);
В метод run() передайте массив команд, а Laravel займётся всем остальным! Теперь, так как есть смысл выполнять команды в качестве Artisan команд, вам всего лишь нужно выполнить php artisan command:make DeployCommand и в метод fire() написать нужный код для выполнения деплоя.
12. События
Laravel предлагает элегантную реализацию шаблона Observer, которую вы можете использовать где угодно в Вашем приложении. Подписывайтесь на нативные события, такие, как illuminate.query, или запускайте и слушайте свои собственные.
Продуманное использование событий даст вам много возможностей.
Event::listen('user.signUp', function() < // выполните то, что надо, // когда пользователь регистрируется >);
Как и большинство вещей в Laravel, если вы предпочитаете указывать название класса, а не анонимную функцию, вы можете спокойно это сделать. Laravel разрулит всё, используя IoC контейнер.
Event::listen('user.signUp', 'UserEventHandler');
13. Покажите маршруты

Приложение растёт, и может стать тяжело посмотреть, какие роуты описаны. Особенно, если Вы не уделяли должного внимания файлу routes.php (например, излишния описания роутов).
Laravel предлагает удобную команду routes, которая покажет все зарегистрированные роуты, наряду с методами контроллеров, которые эти роуты вызывают.
php artisan routes
14. Очереди
Подумайте о событии, когда пользователь регистрируется в Вашем приложении. Скорее всего, произойдет некоторое количество побочных событий. База данных должна быть обновлена, должен увеличиться счёт, письмо приветствия должно быть отправлено, и так далее. К сожалению, такие действия имеют тенденцию занимать много времени.
Зачем заставлять пользователей ждать, пока произойдут эти события, если мы можем отправить выполняться эти события в бекграунде?
Queue::push('SignUpService', compact('user'));

Наверно, самое замечательное, это то, что Laravel превосходно работает с Iron.io “push” очередями. Это значит, что даже не имея опыта работы с воркерами или демонами, мы всё равно можем использовать очереди. Просто опишите роут с помощью команды php artisan queue:subscribe, и Iron.io будет отправлять данные на этот урл каждый раз, когда задача отправлена в очередь. А этот роут в свою очередь выполнит нужные действия.
15. Простая валидация
Когда нужна валидация, Laravel снова приходит нам на помощь! Используя класс Validator как нельзя просто. Просто передайте объект для валидации вместе с правилами в метод make, а Laravel сделает всё остальное.
$order = [ 'title' => 'Wii U', 'description' => 'Game console from Nintendo' ]; $rules = [ 'title' => 'required', 'description' => 'required' ]; $validator = Validator::make($order, $rules); if ($validator->fails()) < var_dump($validator->messages()); // validation errors array >
16. Tinker

Особенно, если вы используете Laravel в первый раз, может быть полезным повозиться с ядром. Команда tinker поможет с этим.
Tinker использует популярный компонент Boris.
$ php artisan tinker
> $order = Order::find(1); > var_dump($order->toArray()); > array(. )
17. Миграции
Думайте о миграциях, как о контроле версий базы данных. В любой момент, вы можете “откатить” миграции, вернуть их, обновить, и так далее. Наверно, сила миграций таится в том, чтобы запушить приложение в продакшн и просто выполнить команду php artisan migrate, чтобы сконструировать базу данных.
Чтобы приготовить схема для новой таблицы users, мы можем выполнить:
php artisan migrate:make create_users_table
Команда сгененерирует файл миграции, который вы наполните так, как вам нужно. Как будете готовы, команда php artisan migrate создаст таблицу. Вот и всё! Нужно откатить изменения? Легко! php artisan migrate:rollback.
Вот пример таблица для таблицы ЧаВО.
public function up() < Schema::create('faqs', function(Blueprint $table) < $table->integer('id', true); $table->text('question'); $table->text('answer'); $table->timestamps(); >); > public function down()
Обратите внимание, что метод drop() выполняет обратные действия метода up(). Это то, что позволяет “откатить” миграцию. Не правда ли, что это намного легче, чем мучаться с чистым SQL?
18. Генераторы
Laravel предлагает некоторое количество генераторов. Но также есть пакет, который называется “Laravel 4 Generators”, и он зашел еще дальше. Он может генерировать ресурсы, файлы для наполнения базы, pivot таблицы и миграции.
В предыдущем пункте мы вынуждены были сами писать схему. Но используя пакет генераторов, мы можем выполнить команду:
php artisan generate:migration create_users_table --fields="username:string, password:string"
А генератор сделает всё остальное. С этой командой вы сможет подоготовить и создать новую таблицу в базе.
Laravel 4 Generators может быть установлен через Composer.
19. Консольные команды
Уже было описано некоторое количество случаев, когда полезно будет написать кастомные команды. Их можно использовать при построении приложений, генерации файлов, деплое приложений и все остального.
Так как это распространенная задача, Laravel делает процесс создания команд наиболее простым.
php artisan command:make MyCustomCommand
Это команда сгенерирует нужный шаблон для Вашей кастомной команды. Далее, в только что созданном файле app/commands/MyCustomCommand.php, заполните название и описание.
protected $name = 'command:name'; protected $description = 'Command description.';
И, в методе fire() выполните нужные действия. После этого останется только зарегистрировать команду для Artisan, в файле app/start/artisan.php.
Artisan::add(new MyCustomCommand);
Хотите верьте, хотите нет, но это всё! Теперь вы можете вызывать эту команду из терминала.
20. Тестируйте фасады
Laravel много использует шаблон Фасад. Это даёт возможность использовать “статический” синтаксис, который, без сомнений, Вам понравится (Route::get(), Config::get(), и так далее), и при этом позволяет полностью тестировать их.
Так как “лежащий в основе” класс разруливается через IoC контейнер, мы легко можем подменить “нижние” классы с нашими тестовыми. Это позволяет нам делать следующее:
Validator::shouldReceive('make')->once();
Да, мы вызываем shouldReceive прямо из фасада. “За кулисами”, Laravel использует фреймворк Mockery. Это значит, что Вы абсолютно спокойно можете использовать фасады, и при этом тестировать абсолютно все куски кода.
21. Хелперы форм
Так как построение форм часто бывает громоздкой задачей, в дело вступает построитель форм в Laravel, чтобы облегчить этот процесс, а также использовать некоторые “особенности стиля”, связанные с конструированием форм. Вот несколько примеров:
Что насчёт задачи запоминания введенных данных при прошлой отправке формы? Laravel это делает автоматически!
22. IoC контейнер (Inverse of control)
В ядре Laravel находится мощнейший IoC контейнер, который является инструментом, помогающим в управлении зависимостями класса. Стоит заметить, что у него есть мощь автоматически определять нужные классы без предварительных настроек.
Просто сделайте typehint ваших зависимостей в конструкторе, и при инициализации Laravel, используя PHP Reflection API, грамотно прочитает ваши подсказки и постарается вставить эти классы за вас.
public function __construct(MyDependency $thing) < $this->thing = $thing; >
Пока вы запрашиваете класс из IoC контейнера, разрешение зависимости произойдет автоматически.
$myClass = App::make('MyClass');
Важно заметить, что контроллеры всегда запрашиваются из IoC контейнера. Поэтому вы можете свободно делать typehint для зависимостей ваших контроллеров, а Laravel постарается внедрить их.
23. Окружения
Одно окружение может подойти для маленьких проектов. Для других проектов, несколько окружений — жизненно важно! Разработка, тестирование, продакшн. Всё это жизненно важно и каждое окружение требует своих настроек.
Возможно ваше тестовое окружение использует базу данных в памяти для тестирование. Может ваше dev окружение использует другие ключи API. А продакшн окружение использует свои настройки подключения к базе.
К счастью, Laravel снова облегчает нашу работу. Взгляните на файл bootstrap/start.php.
Там находится простая демонстрация настройки local окружения, которое базируется на hostname компьютера.
$env = $app->detectEnvironment(array( 'local' => array('your-machine-name'), ));
В общем, это будет работать. Но предпочтительнее использовать переменные окружения для таких вещей. Не беспокойтесь, это легко сделать в Laravel! Просто передайте функцию в метод detectEnvironment.
$env = $app->detectEnvironment(function() < return getenv('ENV_NAME') ?: 'local'; >);
Теперь, если переменная окружения не задана (а для продакшна Вы её установите), окружение будет иметь значение local.
24. Простая настройка
Laravel опять таки использует очень простой подход к конфигурированию. Создайте в папке app/config папку с названием окружения, и любые файлы конфигурации в этой папке будут иметь приоритет над другими, при условии, что вы находитесь в этом окружении. Например, можно задать другой API ключ для dev окружения.
'your-development-mode-api-key' ];
Конфигурация полностью автоматическая. Просто вызовите метод Config::get(‘billing.api_key’) и Laravel сам определит из какого именно файла, считать это значение.
25. Обучаемость
Когда дело доходит до обучения, Laravel сообщество бесконечно хорошее, несмотря на маленький возраст. В течение чуть более года, были опубликованы полдюжины разных книг, связанные с разработкой на Laravel.