Вступление

Контракты Laravel - это набор интерфейсов, которые определяют основные сервисы, предоставляемые платформой. Например, контракт определяет методы, необходимые для постановки в очередь, а контракт определяет методы, необходимые для отправки электронной почты.Illuminate\Contracts\Queue\QueueIlluminate\Contracts\Mail\Mailer

Каждый контракт имеет соответствующую реализацию, предусмотренную рамками. Например, Laravel предоставляет реализацию очереди с различными драйверами и реализацию почтовой программы, основанную на SwiftMailer .

Все контракты Laravel живут в своем собственном репозитории GitHub . Это обеспечивает быструю контрольную точку для всех доступных контрактов, а также отдельный, отсоединенный пакет, который может использоваться разработчиками пакетов.

 

Контракты Vs. Фасады

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

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

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

 

Когда использовать контракты

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

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

 

Слабая связь

Сначала давайте рассмотрим некоторый код, тесно связанный с реализацией кеша. Учтите следующее:

<?php

namespace App\Orders;

class Repository
{
    /**
     * The cache instance.
     */
    protected $cache;

    /**
     * Create a new repository instance.
     *
     * @param  \SomePackage\Cache\Memcached  $cache
     * @return void
     */
    public function __construct(\SomePackage\Cache\Memcached $cache)
    {
        $this->cache = $cache;
    }

    /**
     * Retrieve an Order by ID.
     *
     * @param  int  $id
     * @return Order
     */
    public function find($id)
    {
        if ($this->cache->has($id))    {
            //
        }
    }
}

В этом классе код тесно связан с данной реализацией кеша. Он тесно связан, потому что мы зависим от конкретного класса Cache от поставщика пакетов. Если API этого пакета изменится, наш код также должен измениться.

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

Вместо этого мы можем улучшить наш код, полагаясь на простой, независимый от поставщика интерфейс:

<?php

namespace App\Orders;

use Illuminate\Contracts\Cache\Repository as Cache;

class Repository
{
    /**
     * The cache instance.
     */
    protected $cache;

    /**
     * Create a new repository instance.
     *
     * @param  Cache  $cache
     * @return void
     */
    public function __construct(Cache $cache)
    {
        $this->cache = $cache;
    }
}

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

 

Простота

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

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

 

Как использовать контракты

Итак, как вы получаете реализацию контракта? Это на самом деле довольно просто.

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

Например, взгляните на слушателя этого события:

<?php

namespace App\Listeners;

use App\User;
use App\Events\OrderWasPlaced;
use Illuminate\Contracts\Redis\Factory;

class CacheOrderInformation
{
    /**
     * The Redis factory implementation.
     */
    protected $redis;

    /**
     * Create a new event handler instance.
     *
     * @param  Factory  $redis
     * @return void
     */
    public function __construct(Factory $redis)
    {
        $this->redis = $redis;
    }

    /**
     * Handle the event.
     *
     * @param  OrderWasPlaced  $event
     * @return void
     */
    public function handle(OrderWasPlaced $event)
    {
        //
    }
}

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

 

Ссылка на контракт

В этой таблице приведены краткие ссылки на все контракты Laravel и их эквивалентные фасады:

Contract References Facade
Illuminate\Contracts\Auth\Access\Authorizable   
Illuminate\Contracts\Auth\Access\Gate Gate
Illuminate\Contracts\Auth\Authenticatable   
Illuminate\Contracts\Auth\CanResetPassword  
Illuminate\Contracts\Auth\Factory Auth
Illuminate\Contracts\Auth\Guard Auth::guard()
Illuminate\Contracts\Auth\PasswordBroker Password::broker()
Illuminate\Contracts\Auth\PasswordBrokerFactory Password
Illuminate\Contracts\Auth\StatefulGuard  
Illuminate\Contracts\Auth\SupportsBasicAuth  
Illuminate\Contracts\Auth\UserProvider  
Illuminate\Contracts\Bus\Dispatcher Bus
Illuminate\Contracts\Bus\QueueingDispatcher Bus::dispatchToQueue()
Illuminate\Contracts\Broadcasting\Factory Broadcast
Illuminate\Contracts\Broadcasting\Broadcaster Broadcast::connection()
Illuminate\Contracts\Broadcasting\ShouldBroadcast  
Illuminate\Contracts\Broadcasting\ShouldBroadcastNow  
Illuminate\Contracts\Cache\Factory Cache
Illuminate\Contracts\Cache\Lock  
Illuminate\Contracts\Cache\LockProvider  
Illuminate\Contracts\Cache\Repository Cache::driver()
Illuminate\Contracts\Cache\Store  
Illuminate\Contracts\Config\Repository Config
Illuminate\Contracts\Console\Application  
Illuminate\Contracts\Console\Kernel Artisan
Illuminate\Contracts\Container\Container App
Illuminate\Contracts\Cookie\Factory Cookie
Illuminate\Contracts\Cookie\QueueingFactory Cookie::queue()
Illuminate\Contracts\Database\ModelIdentifier  
Illuminate\Contracts\Debug\ExceptionHandler  
Illuminate\Contracts\Encryption\Encrypter Crypt
Illuminate\Contracts\Events\Dispatcher Event
Illuminate\Contracts\Filesystem\Cloud Storage::cloud()
Illuminate\Contracts\Filesystem\Factory Storage
Illuminate\Contracts\Filesystem\Filesystem Storage::disk()
Illuminate\Contracts\Foundation\Application App
Illuminate\Contracts\Hashing\Hasher Hash
Illuminate\Contracts\Http\Kernel  
Illuminate\Contracts\Mail\MailQueue Mail::queue()
Illuminate\Contracts\Mail\Mailable  
Illuminate\Contracts\Mail\Mailer Mail
Illuminate\Contracts\Notifications\Dispatcher Notification
Illuminate\Contracts\Notifications\Factory Notification
Illuminate\Contracts\Pagination\LengthAwarePaginator  
Illuminate\Contracts\Pagination\Paginator  
Illuminate\Contracts\Pipeline\Hub  
Illuminate\Contracts\Pipeline\Pipeline  
Illuminate\Contracts\Queue\EntityResolver  
Illuminate\Contracts\Queue\Factory Queue
Illuminate\Contracts\Queue\Job  
Illuminate\Contracts\Queue\Monitor Queue
Illuminate\Contracts\Queue\Queue Queue::connection()
Illuminate\Contracts\Queue\QueueableCollection  
Illuminate\Contracts\Queue\QueueableEntity  
Illuminate\Contracts\Queue\ShouldQueue  
Illuminate\Contracts\Redis\Factory Redis
Illuminate\Contracts\Routing\BindingRegistrar Route
Illuminate\Contracts\Routing\Registrar Route
Illuminate\Contracts\Routing\ResponseFactory Response
Illuminate\Contracts\Routing\UrlGenerator URL
Illuminate\Contracts\Routing\UrlRoutable  
Illuminate\Contracts\Session\Session Session::driver()
Illuminate\Contracts\Support\Arrayable  
Illuminate\Contracts\Support\Htmlable  
Illuminate\Contracts\Support\Jsonable  
Illuminate\Contracts\Support\MessageBag  
Illuminate\Contracts\Support\MessageProvider  
Illuminate\Contracts\Support\Renderable  
Illuminate\Contracts\Support\Responsable  
Illuminate\Contracts\Translation\Loader  
Illuminate\Contracts\Translation\Translator Lang
Illuminate\Contracts\Validation\Factory Validator
Illuminate\Contracts\Validation\ImplicitRule  
Illuminate\Contracts\Validation\Rule  
Illuminate\Contracts\Validation\ValidatesWhenResolved  
Illuminate\Contracts\Validation\Validator Validator::make()
Illuminate\Contracts\View\Engine  
Illuminate\Contracts\View\Factory View
Illuminate\Contracts\View\View View::make()