Как создавать фасады в Laravel

Источник: «Learn how to create custom Facades in Laravel»
Если фасады в Laravel сбивают с толку, присоединяйтесь и узнайте, как определить сервис, стоящий за любым фасадом, встречающимся во фреймворке.

Фасады Laravel — это фантастическая функция фреймворка Laravel, обеспечивающая удобный доступ к сервисам через простой интерфейс. Когда только начинал изучать Laravel, меня смущала одна вещь — метод доступа к фасаду.

Поняв, что фасады — это удобный способ доступа к базовым сервисам в сервис контейнере Laravel, можно легко отследить сервис, стоящий за любым фасадом. Каждый фасад предоставляет метод getFacadeAccessor(), указывающий на имя зарегистрированного сервиса.

Вот пример аксессора фасада для фасада DB:

// Illuminate\Support\Facades\DB;

protected static function getFacadeAccessor()
{
return 'db';
}

Таким образом, строка 'db' указывает на сервис в контейнере, используемый фасадом для разрешения.

Некоторые фасады могут обращаться к классу менеджера, который затем будет динамически передавать методы базовому макросу или классу подключения к базе данных:

public function __call($method, $parameters)
{
if (static::hasMacro($method)) {
return $this->macroCall($method, $parameters);
}

return $this->connection()->$method(...$parameters);
}

При вызове без соединения DatabaseManager будет использовать соединение по умолчанию и вызывать методы на этом соединении.

Рекомендую прочитать о том, как работают фасады, в документации Laravel, где также есть список ссылок на фасады, доступные во фреймворке.

Создание собственных фасадов в Laravel

Зачем вообще создавать фасад в приложении, если вы не создаёте плагин или не работаете с фреймворком Laravel напрямую? Некоторые разработчики предпочитают использовать инъекцию зависимостей только для сервисов, определённых в коде приложения, и это нормально. Однако я считаю удобным определять фасады для часто используемых сервисов либо через хелперы, либо через пространство имён App\Facades. Мне нравится гибкость Laravel, и в то же время я могу установить соглашения, позволяющие продуктивно работать в незнакомой кодовой базе.

Чтобы создать фасад в коде приложения, рекомендую использовать команду make:class для генерации фасада, что можно сделать следующим образом:

php artisan make:class App/Facades/Example

Допустим, вы определили сервис в сервис провайдере приложения с названием App\ExampleService; затем можно создать фасад для него после генерации класса:

namespace App\Facades;

use Illuminate\Support\Facades\Facade;

class Example extends Facade
{
public static function getFacadeAccessor()
{
return 'example_service';
}
}

С таким же успехом можно было бы сделать аксессор фасада строкой полностью определённого класса, если бы не был определён псевдоним или строка определения в сервис провайдере:

public static function getFacadeAccessor()
{
return \App\ExampleService::class;
}

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

use App\Facades\Example;

Example::shouldReceive('getLatestPosts')
->with($after_date)
->andReturn($test_posts);

Если не используется фасад, Laravel предоставляет другие удобные методы имитации, такие как partialMock(), позволяющие удобно поменять сервис на имитацию в тесте. С сервисом это можно сделать прямо в тесте, например, так:

$mock = $this->partialMock(MyApiService::class, function (MockInterface $mock) {
$mock->shouldReceive('getLatestPosts')
->with($after_date)
->andReturn($test_posts);
});

Вы сами решаете, какого подхода придерживаться, но если в приложении активно используется сервис, подумайте о создании фасада, чтобы обеспечить удобство использования сервиса без потери возможностей, предоставляемых инъекцией зависимостей.

Дополнительные материалы

Предыдущая Статья

Оптимизация производительности Laravel с утилитой Benchmark

Следующая Статья

Упрощение валидации форм в Laravel Livewire с атрибутом #[Validate]