Unetway

Laravel - Facades

Вступление

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

Все фасады Laravel определены в пространстве имен. Таким образом, мы можем легко получить доступ к фасаду следующим образом:Illuminate\Support\Facades

use Illuminate\Support\Facades\Cache;

Route::get('/cache', function () {
    return Cache::get('key');
});

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

 

Когда использовать фасады

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

Тем не менее, следует соблюдать осторожность при использовании фасадов. Основная опасность фасадов - ползучесть класса. Поскольку фасады настолько просты в использовании и не требуют инъекций, может быть легко позволить вашим классам продолжать расти и использовать множество фасадов в одном классе. Используя внедрение зависимостей, этот потенциал смягчается визуальной обратной связью, которую дает большой конструктор, что ваш класс становится слишком большим. Поэтому при использовании фасадов обращайте особое внимание на размер вашего класса, чтобы сфера его ответственности оставалась узкой.

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

 

Фасады Vs. Внедрение зависимости

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

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

use Illuminate\Support\Facades\Cache;

Route::get('/cache', function () {
    return Cache::get('key');
});

Мы можем написать следующий тест, чтобы убедиться, что метод был вызван с ожидаемым аргументом:Cache::get

use Illuminate\Support\Facades\Cache;

/**
 * A basic functional test example.
 *
 * @return void
 */
public function testBasicExample()
{
    Cache::shouldReceive('get')
         ->with('key')
         ->andReturn('value');

    $this->visit('/cache')
         ->see('value');
}

 

Фасады Vs. Вспомогательные функции

В дополнение к фасадам, Laravel включает в себя множество «вспомогательных» функций, которые могут выполнять общие задачи, такие как генерация представлений, запуск событий, диспетчеризация заданий или отправка HTTP-ответов. Многие из этих вспомогательных функций выполняют ту же функцию, что и соответствующий фасад. Например, этот вызов фасада и вспомогательный вызов эквивалентны:

return View::make('profile');

return view('profile');

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

Route::get('/cache', function () {
    return cache('key');
});

Под капотом cacheпомощник собирается вызвать getметод для класса, лежащего в основе Cacheфасада. Итак, хотя мы используем вспомогательную функцию, мы можем написать следующий тест, чтобы убедиться, что метод был вызван с ожидаемым аргументом:

use Illuminate\Support\Facades\Cache;

/**
 * A basic functional test example.
 *
 * @return void
 */
public function testBasicExample()
{
    Cache::shouldReceive('get')
         ->with('key')
         ->andReturn('value');

    $this->visit('/cache')
         ->see('value');
}

 

Как работают фасады

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

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

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Cache;

class UserController extends Controller
{
    /**
     * Show the profile for the given user.
     *
     * @param  int  $id
     * @return Response
     */
    public function showProfile($id)
    {
        $user = Cache::get('user:'.$id);

        return view('profile', ['user' => $user]);
    }
}

Обратите внимание, что в верхней части файла мы «импортируем» Cacheфасад. Этот фасад служит прокси для доступа к базовой реализации интерфейса. Любые звонки, которые мы делаем с помощью фасада, будут переданы в базовый экземпляр службы кэширования Laravel.Illuminate\Contracts\Cache\Factory

Если мы посмотрим на этот класс, вы увидите, что нет статического метода :Illuminate\Support\Facades\Cacheget

class Cache extends Facade
{
    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor() { return 'cache'; }
}

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

 

Фасады в реальном времени

Используя фасады в реальном времени, вы можете рассматривать любой класс в вашем приложении, как если бы это был фасад. Чтобы проиллюстрировать, как это можно использовать, давайте рассмотрим альтернативу. Например, предположим, что в нашей Podcastмодели есть publishметод. Однако, чтобы опубликовать подкаст, нам нужно добавить Publisherэкземпляр:

<?php

namespace App;

use App\Contracts\Publisher;
use Illuminate\Database\Eloquent\Model;

class Podcast extends Model
{
    /**
     * Publish the podcast.
     *
     * @param  Publisher  $publisher
     * @return void
     */
    public function publish(Publisher $publisher)
    {
        $this->update(['publishing' => now()]);

        $publisher->publish($this);
    }
}

Внедрение реализации издателя в метод позволяет нам легко тестировать метод изолированно, так как мы можем издеваться над внедренным издателем. Однако это требует, чтобы мы всегда передавали экземпляр издателя каждый раз, когда мы вызываем publishметод. Используя фасады в реальном времени, мы можем поддерживать ту же тестируемость, не требуя явной передачи Publisherэкземпляра. Чтобы создать фасад в реальном времени, добавьте префикс пространства имен импортируемого класса Facades:

<?php

namespace App;

use Facades\App\Contracts\Publisher;
use Illuminate\Database\Eloquent\Model;

class Podcast extends Model
{
    /**
     * Publish the podcast.
     *
     * @return void
     */
    public function publish()
    {
        $this->update(['publishing' => now()]);

        Publisher::publish($this);
    }
}

При использовании фасада в реальном времени реализация издателя будет разрешена из контейнера службы с использованием той части интерфейса или имени класса, которая появляется после Facadesпрефикса. При тестировании мы можем использовать встроенные в Laravel помощники по тестированию фасада, чтобы смоделировать вызов этого метода:

<?php

namespace Tests\Feature;

use App\Podcast;
use Tests\TestCase;
use Facades\App\Contracts\Publisher;
use Illuminate\Foundation\Testing\RefreshDatabase;

class PodcastTest extends TestCase
{
    use RefreshDatabase;

    /**
     * A test example.
     *
     * @return void
     */
    public function test_podcast_can_be_published()
    {
        $podcast = factory(Podcast::class)->create();

        Publisher::shouldReceive('publish')->once()->with($podcast);

        $podcast->publish();
    }
}

 

Ссылка на класс фасадов

Ниже вы найдете каждый фасад и его базовый класс. Это полезный инструмент для быстрого поиска документации API для данного корневого каталога фасада. Службы контейнера привязкиключа также включены , где это применимо.

Facade Class Service Container Binding
App Illuminate\Foundation\Application app
Artisan Illuminate\Contracts\Console\Kernel artisan
Auth Illuminate\Auth\AuthManager auth
Auth (Instance) Illuminate\Contracts\Auth\Guard auth.driver
Blade Illuminate\View\Compilers\BladeCompiler blade.compiler
Broadcast Illuminate\Contracts\Broadcasting\Factory  
Broadcast (Instance) Illuminate\Contracts\Broadcasting\Broadcaster  
Bus Illuminate\Contracts\Bus\Dispatcher  
Cache Illuminate\Cache\CacheManager cache
Cache (Instance) Illuminate\Cache\Repository cache.store
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 db.connection
Event Illuminate\Events\Dispatcher events
File Illuminate\Filesystem\Filesystem files
Gate Illuminate\Contracts\Auth\Access\Gate  
Hash Illuminate\Contracts\Hashing\Hasher hash
Lang Illuminate\Translation\Translator translator
Log Illuminate\Log\LogManager log
Mail Illuminate\Mail\Mailer mailer
Notification Illuminate\Notifications\ChannelManager  
Password Illuminate\Auth\Passwords\PasswordBrokerManager auth.password
Password (Instance) Illuminate\Auth\Passwords\PasswordBroker auth.password.broker
Queue Illuminate\Queue\QueueManager queue
Queue (Instance) Illuminate\Contracts\Queue\Queue queue.connection
Queue (Base Class) Illuminate\Queue\Queue  
Redirect Illuminate\Routing\Redirector redirect
Redis Illuminate\Redis\RedisManager redis
Redis (Instance) Illuminate\Redis\Connections\Connection redis.connection
Request Illuminate\Http\Request request
Response Illuminate\Contracts\Routing\ResponseFactory  
Response (Instance) Illuminate\Http\Response  
Route Illuminate\Routing\Router router
Schema Illuminate\Database\Schema\Builder  
Session Illuminate\Session\SessionManager session
Session (Instance) Illuminate\Session\Store session.store
Storage Illuminate\Filesystem\FilesystemManager filesystem
Storage (Instance) Illuminate\Contracts\Filesystem\Filesystem filesystem.disk
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