Фасады

Введение

Фасады предоставляют «статический» интерфейс (Foo::bar()) к классам, доступным в сервис-контейнере. Laravel поставляется со множеством фасадов и вы, вероятно, использовали их, даже не подозревая об этом.

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

Примечание: перед погружением в фасады настоятельно рекомендуется как можно детальнее изучить сервис-контейнер Laravel.

Описание

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

Ваш фасад должен определить единственный метод: getFacadeAccessor. Его задача - определить, что вы хотите получить из контейнера. Класс Facade использует магический метод PHP __callStatic() для перенаправления вызовов методов с вашего фасада на полученный объект.

Например, когда вы вызываете Cache::get(), Laravel получает объект CacheManager из сервис-контейнера и вызывает метод get этого класса. Другими словами, фасады Laravel предоставляют удобный синтаксис для использования сервис-контейнера в качестве сервис-локатора (service locator).

Практическое использование

В примере ниже делается обращение к механизму кэширования Laravel. На первый взгляд может показаться, что метод get принадлежит классу Cache.

$value = Cache::get('key');

Однако, если вы посмотрите в исходный код класса Illuminate\Support\Facades\Cache, то увидите, что он не содержит метода get:

class Cache extends Facade {

    /**
     * Получить зарегистрированное имя компонента.
     *
     * @return string
     */
    protected static function getFacadeAccessor() { return 'cache'; }

}

Класс Cache наследует класс Facade и определяет метод getFacadeAccessor(). Как вы помните, его задача - вернуть строковое имя (ключ) привязки объекта в сервис-контейнере.

Когда вы обращаетесь к любому статическому методу фасада Cache, Laravel получает объект cache из сервис-контейнера и вызывает на нём требуемый метод (в этом случае - get).

Таким образом, вызов Cache::get может быть записан так:

$value = $app->make('cache')->get('key');

Импорт фасадов

Помните, если вы используете фасады в контроллерах с указанным пространством имён, вам нужно импортировать классы фасадов. Все фасады находятся в глобальном пространстве имён.

<?php namespace App\Http\Controllers;

use Cache;

class PhotosController extends Controller {

    /**
     * Get all of the application photos.
     *
     * @return Response
     */
    public function index()
    {
        $photos = Cache::get('photos');

        //
    }

}

Создание фасадов

Создать фасад довольно просто. Вам нужны только три вещи:

  1. Биндинг (привязка) в сервис-контейнер.
  2. Класс-фасад.
  3. Настройка для псевдонима фасада.

Посмотрим на следующий пример. Здесь определён класс PaymentGateway\Payment.

namespace PaymentGateway;

class Payment {

    public function process()
    {
        //
    }

}

Нам нужно, чтобы этот класс извлекался из сервис-контейнера, так что давайте добавим для него привязку (binding):

App::bind('payment', function()
{
    return new \PaymentGateway\Payment;
});

Самое лучшее место для регистрации этой связки - новый сервис-провайдер который мы назовём PaymentServiceProvider и в котором мы создадим метод register, содержащий код выше. После этого вы можете настроить Laravel для загрузки этого провайдера в файле config/app.php.

Дальше мы можем написать класс нашего фасада:

use Illuminate\Support\Facades\Facade;

class Payment extends Facade {

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

}

Наконец, по желанию можно добавить псевдоним (alias) для этого фасада в массив aliases файла настроек config/app.php- тогда мы сможем вызывать метод process на классе Payment.

Payment::process();

Об автозагрузке псевдонимов

В некоторых случаях классы в массиве aliases не доступны из-за того, что PHP не загружает неизвестные классы в подсказках типов. Если \ServiceWrapper\ApiTimeoutException имеет псевдоним ApiTimeoutException, то блок catch(ApiTimeoutException $e), помещённый в любое пространство имён, кроме \ServiceWrapper, никогда не «поймает» это исключение, даже если оно было возбуждено внутри него. Аналогичная проблема возникает в классах, которые содержат подсказки типов на неизвестные (неопределённые) классы. Единственное решение - не использовать псевдонимы и вместо них в начале каждого файла писать use для ваших классов.

Фасады для тестирования

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

Facade Class Reference

Ниже представлена таблица соответствий фасадов Laravel и классов, лежащих в их основе.

Фасад Класс Имя в IoC
App Illuminate\Foundation\Application app
Artisan Illuminate\Console\Application artisan
Auth Illuminate\Auth\AuthManager auth
Auth (Instance) Illuminate\Auth\Guard
Blade Illuminate\View\Compilers\BladeCompiler blade.compiler
Bus Illuminate\Contracts\Bus\Dispatcher
Cache Illuminate\Cache\Repository cache
Config Illuminate\Config\Repository config
Cookie Illuminate\Cookie\CookieJar cookie
Crypt Illuminate\Encryption\Encrypter encrypter
DB Illuminate\Database\DatabaseManager db
DB (Instance) Illuminate\Database\Connection
Event Illuminate\Events\Dispatcher events
File Illuminate\Filesystem\Filesystem files
Form Illuminate\Html\FormBuilder form
Hash Illuminate\Hashing\HasherInterface hash
HTML Illuminate\Html\HtmlBuilder html
Input Illuminate\Http\Request request
Lang Illuminate\Translation\Translator translator
Log Illuminate\Log\Writer log
Mail Illuminate\Mail\Mailer mailer
Paginator Illuminate\Pagination\Factory paginator
Paginator (Instance) Illuminate\Pagination\Paginator
Password Illuminate\Auth\Passwords\PasswordBroker auth.reminder
Queue Illuminate\Queue\QueueManager queue
Queue (Instance) Illuminate\Queue\QueueInterface
Queue (Base Class) Illuminate\Queue\Queue
Redirect Illuminate\Routing\Redirector redirect
Redis Illuminate\Redis\Database redis
Request Illuminate\Http\Request request
Response Illuminate\Support\Facades\Response
Route Illuminate\Routing\Router router
Schema Illuminate\Database\Schema\Blueprint
Session Illuminate\Session\SessionManager session
Session (Instance) Illuminate\Session\Store
SSH Illuminate\Remote\RemoteManager remote
SSH (Instance) Illuminate\Remote\Connection
URL Illuminate\Routing\UrlGenerator url
Validator Illuminate\Validation\Factory validator
Validator (Instance) Illuminate\Validation\Validator
View Illuminate\View\Factory view
View (Instance) Illuminate\View\View