Создание собственных PHP хелперов в Laravel проекте
Laravel предоставляет множество отличных хелперов, удобных для работы с массивами, путями к файлам, строками, маршрутами и другими функциями, например, с любимой функцией dd()
.
Также можно создать собственный набор хелперов для приложений Laravel и пакетов PHP, используя Composer для их автоматического импорта.
Ранее уже публиковались статьи о написании хелперов для Laravel проектов от Ian Kumu и Ashley Allen:
Создание файла хелперов в приложении Laravel
Первый сценарий, в котором может возникнуть желание включить свои хелперы, — это контекст приложения Laravel. В зависимости от предпочтений можно организовать расположение файлов хелперов по своему усмотрению, но вот несколько предлагаемых мест:
app/helpers.php
app/Http/helpers.php
Я предпочитаю хранить файлы в app/helpers.php
в корне пространства имён приложения.
Автозагрузка
Чтобы воспользоваться своими PHP хелпером, необходимо загрузить его в программу во время выполнения. В начале моей карьеры нередко можно было встретить подобный код в начале файла:
require_once ROOT . '/helpers.php';
Функции PHP не могут автоматически загружаться. Однако есть гораздо лучшее решение благодаря Composer, чем использование require
или require_once
.
При создании нового проекта Laravel в файле composer.json
отображаются ключи autoload
и autoload-dev
:
"autoload": {
"classmap": [
"database/seeds",
"database/factories"
],
"psr-4": {
"App\\": "app/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
},
Если нужно добавить файлы хелперы, в composer есть ключ files
(представляющий собой массив путей к файлам), который можно задать в autoload
:
"autoload": {
"files": [
"app/helpers.php"
],
"classmap": [
"database/seeds",
"database/factories"
],
"psr-4": {
"App\\": "app/"
}
},
После добавления нового пути в массив files
необходимо сбросить автозагрузку:
composer dump-autoload
Теперь при каждом запросе файл helpers.php
будет автоматически загружаться, поскольку Laravel использует автозагрузку Composer в public/index.php
:
require __DIR__.'/../vendor/autoload.php';
Определение функций
Определение функций в классах хелперов — это самая простая часть, но есть несколько нюансов. Все файлы хелперов Laravel обёрнуты в проверку, чтобы избежать коллизий определений функций:
if (! function_exists('env')) {
function env($key, $default = null) {
// ...
}
}
Это может вызвать затруднения, потому что можно столкнуться с ситуацией, когда используется определение функции, которого вы не ожидали, исходя из того, какая из них была определена первой.
Я предпочитаю использовать проверку function_exists
в своих хелперах для приложений, но если вы определяете хелперы в контексте своего приложения, то можно обойтись без проверки function_exists
.
Пропустив проверку, вы можете столкнуться с коллизиями в любой момент, когда ваши хелперы переопределяют функции, что может быть полезным.
На практике коллизии случаются не так часто, как кажется, и поэтому необходимо убедиться, что имена функций не являются слишком общими. Также можно использовать префиксы в именах функций, чтобы снизить вероятность коллизии с другими зависимостями.
Пример хелпера
Мне нравятся хелперы пути и URL в Rails, предоставляемые при определении ресурсного маршрута. Например, маршрут ресурса photos
будет содержать такие хелперы маршрута, как new_photo_path
, edit_photo_path
и т. д.
При использовании маршрутизации ресурсов в Laravel мне нравится добавлять несколько хелперов, упрощающих определение маршрутов в шаблонах. В своей реализации мне нравится использовать хелпер URL, которой можно передать модель Eloquent и получить в ответ маршрут ресурса, используя определённые конвенции, например:
create_route($model);
edit_route($model);
show_route($model);
destroy_route($model);
Так можно определить show_route
в файле app/helpers.php
(остальные будут выглядеть аналогично):
if (! function_exists('show_route')) {
function show_route($model, $resource = null)
{
$resource = $resource ?? plural_from_model($model);
return route("{$resource}.show", $model);
}
}
if (! function_exists('plural_from_model')) {
function plural_from_model($model)
{
$plural = Str::plural(class_basename($model));
return Str::kebab($plural);
}
}
Функция plural_from_model()
— это функция, используемая хелперами маршрута для определения имени ресурса маршрута на основе предпочтительного для меня соглашения об именовании, представляющего собой множественное число модели в kebab-case.
Например, вот пример имени ресурса, полученного из модели:
$model = new App\LineItem;
plural_from_model($model);
// => line-items
plural_from_model(new App\User);
// => users
Используя это соглашение, можно определить маршрут ресурса в файле routes/web.php
следующим образом:
Route::resource('line-items', 'LineItemsController');
Route::resource('users', 'UsersController');
А затем в blade-шаблонах можно сделать следующее:
<a href="{{ show_route($lineItem) }}">
{{ $lineItem->name }}
</a>
В результате сгенерируется что-то вроде следующего HTML-фрагмента:
<a href="http://localhost/line-items/1">
Line Item #1
</a>
Пакеты
Ваши пакеты Composer также могут использовать файл хелперов для любых хелперов, которые вы хотите сделать доступными для проектов, использующих ваш пакет.
Аналогичный подход применяется и в файле composer.json
пакета, определяя ключ files
с массивом ваших хелперов.
Обязательно оборачивайте свои хелперы в проверку function_exists()
, чтобы проекты, использующие ваш код, не сломались из-за коллизий именования.
Необходимо выбирать подходящие имена функций, уникальные для вашего пакета, а также использовать короткий префикс, если опасаетесь, что имя функции будет слишком общим.
Узнайте больше
Ознакомьтесь с документацией Composer по автозагрузке, чтобы узнать больше о подключении файлов и общую информацию о классах автозагрузки.
Другие статьи по написанию хелперов: