Создание классов-хелперов в Laravel

С помощью контрактов и фасадов

Хелперы в Laravel - это функции, которые помогают инкапсулировать какой-то код для расчётов, преобразований и других манипуляций с данными.

Некоторые разработчики любят делать обычные глобальные функции. Лично я - не любитель такого и оформляю это в виде классов.

В этом туториале я расскажу как я обычно делаю классы-хелперы с помощью двух способов - создания фасада и создания контракта (интферфейса).

Дано

Рассмотрим крайне простую ситуацию. У нас есть есть обычный контроллер TestController с методом index, в котором происходит умножение первого значения на второе и вывод результата на экран.

1 2 3 4 5 6 7 8 9 10 11 12 13 14
<?php   namespace App\Http\Controllers;   class TestController extends Controller { public function index() { $val = 2; $times = 5;   return $val * $times; } }

Давайте вынесем этот код в сервисный класс - хелпер.

Шаг 1. Создание контракта

Контракты - это просто интерфейсы, которые разработчики Laravel почему-то так называют.

Создадим новую папку /app/Contracts/Helpers. Внутри этой папке создадим обычный PHP интерфейс с названием MathHelper, где объявим методы, которые должны реализовывать имплементирующие этот интерфейс классы.

В нашем случае будет один метод times():

<?php
 
namespace App\Contracts\Helpers;
 
interface MathHelper
{
    public function times(int $var, int $times): int;
}

Шаг 2. Создание хелпера

Создадим новую папку /app/Helpers. Внутри неё создадим новый класс под таким же названием - MathHelper.

Этот класс должен имплементироваться от ранее созданного контракта и реализовывать его методы:

1 2 3 4 5 6 7 8 9 10 11 12 13
<?php   namespace App\Helpers;   use App\Contracts\Helpers\MathHelper as MathHelperContract;   class MathHelper implements MathHelperContract { public function times(int $val, int $times): int { return $val * $times; } }

Шаг 3. Создание фасада

Фасад как шаблон проектирования и фасад в Laravel - немного отличаются. В первом случае, фасад представляет собой простой интерфейс к сложной системе классов, в Laravel же - это просто обертка для класса, которая позволяет обращаться к его методам статическим способом.

Создадим ещё одну папку /app/Facades/Helpers, в которой создадим фасад под названием Math.

Как написано в документации, фасад должен иметь защищенный статический метод getFacadeAccessor(), который должен возвращать ключ для сервис-контейнера.

В нашем случае мы будем возвращать название контракта:

1 2 3 4 5 6 7 8 9 10 11 12 13 14
<?php   namespace App\Facades\Helpers;   use App\Contracts\Helpers\MathHelper as MathHelperContract; use Illuminate\Support\Facades\Facade;   class Math extends Facade { protected static function getFacadeAccessor() { return MathHelperContract::class; } }

Шаг 4. Привязка контракта к классу-хелперу в контейнере служб

Как я говорил ранее, хелперы не должны иметь состояния, по-этому мы будем использовать паттерн Singleton.

Для привязки контракта к нашему хелперу в контейнере, нужно открыть файл /app/Providers/AppServiceProvider и выполнить ОДНО из двух действий:

  1. Либо объявить публичное свойство класса - массив $singletons, в котором создать новый элемент с ключом в виду названия класса-контракта и значением в виде названия класса-хелпера:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
<?php   namespace App\Providers;   use App\Helpers\MathHelper; use Illuminate\Support\ServiceProvider; use \App\Contracts\Helpers\MathHelper as MathHelperContract;   class AppServiceProvider extends ServiceProvider { public array $singletons = [ MathHelperContract::class => MathHelper::class, ];   /** * Register any application services. * * @return void */ public function register() { // }   /** * Bootstrap any application services. * * @return void */ public function boot() { // } }
  1. Либо же выполнить привязку вручную в методе register():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
<?php   namespace App\Providers;   use App\Helpers\MathHelper; use Illuminate\Support\ServiceProvider; use \App\Contracts\Helpers\MathHelper as MathHelperContract;   class AppServiceProvider extends ServiceProvider { /** * Register any application services. * * @return void */ public function register() { $this->app->singleton(MathHelperContract::class, MathHelper::class); }   /** * Bootstrap any application services. * * @return void */ public function boot() { // } }

Таким образом мы обеспечили себе уверенность в том, что у хелпера будет один экземпляр.

Шаг 5. Регистрация нового алиаса для фасада

Это нужно, чтобы нам не пришлось каждый раз импортировать пространство имен нашего фасада, используя use App\Facades\Helpers\Math.

Для создания нового алиаса, нужно открыть файл /config/app.php и в массиве с ключом aliases добавить вконец новый элемент:

'Math' => \App\Facades\Helpers\Math::class

Вызов методов хелпера

Теперь мы можем использовать хелпер тремя способами:

  1. Используя его алиас:
1 2 3 4 5 6 7 8 9 10 11
<?php   namespace App\Http\Controllers;   class TestController extends Controller { public function index() { return \Math::times(2, 5); } }
  1. Обращаясь к фасаду напрямую:
1 2 3 4 5 6 7 8 9 10 11
<?php   namespace App\Http\Controllers;   class TestController extends Controller { public function index() { return \App\Facades\Helpers\Math::times(2, 5); } }
  1. Используя магию сервис контейнера:
1 2 3 4 5 6 7 8 9 10 11 12 13
<?php   namespace App\Http\Controllers;   use App\Contracts\Helpers\MathHelper;   class TestController extends Controller { public function index(MathHelper $mathHelper) { return $mathHelper->times(2, 5); } }

Обращение к фасаду хелпера, не создавая его

Пока писал этот пост, обнаружил, что есть способ автоматически генерировать фасад нашего хелпера.

Подробнее читайте на этой странице.

Комментарии

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: