Как стать автором
Обновить

Расширяем Laravel за счет собственных компонентов

Время на прочтение3 мин
Количество просмотров3.9K

Задача


Добавить в приложение систему оповещения пользователей через СМС-сообщения с возможностью выбора провайдера.

Решение


Оптимальным решением, на мой взгляд, является добавление собственного компонента.
Компонент — это блок программы с четко определенным набором действий (контрактом), способный решать возложенные на него задачи посредством различных драйверов. Так, например, встроенный компонент Cache может использовать драйвера: file, memcached или redis.

При построении нашего компонента, мы применим принцип проектирования Мост, тот же принцип, на котором построены компоненты Laravel.

Итак, приступим.

Драйвера


Как гласит один из постулатов: программируйте в соответствии с интерфейсом, а не с реализацией.

С него и начнем, но в контексте компонента точнее использовать термин контракт. Контракт, по сути, набор интерфейсов для описания функционала компонента.

interface SmsContract
{
    public function send();
}

Далее добавим драйвера, исполняющие контракт. Общую логику вынесем в абстрактный класс.

abstract class Driver implements SmsContract
{
    protected $message;

    protected $recipient;

    public function to($phoneNumber)
    {
        $this->recipient = $phoneNumber;
    }

    public function content($message)
    {
        $this->message = $message;
    }

    abstract public function send();
}

А непосредственно логику отправки опишем в каждом классе драйвера.

class SmsRuDriver extends Driver
{
    protected $client;

    protected $from;

    public function __construct(SmsRuClient $smsRuClient, $from)
    {
        $this->client = $smsRuClient;
        $this->from = $from;
    }

    public function send()
    {
        return $this->client->sendSms([
            'type' => 'text',
            'from' => $this->from,
            'to' => $this->recipient,
            'text' => trim($this->message)
        ]);
    }
}

class SmartSenderDriver extends Driver
{
    protected $client;

    protected $from;

    public function __construct(SmartSenderClient $smartSenderClient, $from)
    {
        $this->client = $smartSenderClient;
        $this->from = $from;
    }

    public function send()
    {
        return $this->client->message()->send([
            'type' => 'text',
            'from' => $this->from,
            'to' => $this->recipient,
            'text' => trim($this->message)
        ]);
    }
}

Управление Компонентом


Для выбора и настройки драйверов добавим класс SmsManager, унаследованный от класса Manager.

use Illuminate\Support\Manager;

class SmsManager extends Manager
{
    public function setDriver($name = null)
    {
        return $this->driver($name);
    }

    public function createSmsRuDriver(): SmsContract
    {
        return new SmsRuDriver(
            $this->createSmsRuClient(),
            $this->app['config']['sms.sms_ru.from']
        );
    }

    public function createSmartSenderDriver(): SmsContract
    {
        return new SmartSenderDriver(
            $this->createSmartSenderClient(),
            $this->app['config']['sms.smart_sender.from']
        );
    }

    public function getDefaultDriver()
    {
        return $this->app['config']['sms.default'];
    }

    protected function createSmsRuClient()
    {
        return new SmsRuClient(
            $this->app['config']['sms.sms_ru.key'],
            $this->app['config']['sms.sms_ru.secret']
        );
    }

    protected function createSmartSenderClient()
    {
        return new SmartSenderClient(
            $this->app['config']['sms.smart_sender.key'],
            $this->app['config']['sms.smart_sender.secret']
        );
    }

}

Теперь достаточно указать нужные параметры в файле конфигурации и класс SmsManager укажет нашему компоненту через какой драйвер отправлять СМС-сообщения.

Фасад


Для доступа к функционалу компонента из любой точки приложения добавим фасад.
Сначала создаем сам класс фасада:

use Illuminate\Support\Facades\Facade;

class Sms extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'sms';
    }
}

Далее связываем класс SmsManager с фасадом с помощью сервис-провайдера и регистрируем псевдоним.

class SmsServiceProvider extends ServiceProvider
{
    protected $defer = true;
    
    public function register()
    {
        $this->app->singleton('sms', function ($app) {
            return new SmsManager($app);
        });
    }
    
    public function provides()
    {
        return ['sms'];
    }
}

И последнее, регистрируем наш сервис-провайдер вместе с остальными провайдерами в файле конфигурации (app/config/app.php).

'providers' => [
    ...
    App\Providers\SmsServiceProvider::class,
],    

Применение


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

Sms::to($phone)->content('Beware! He`s not who he is')->send();

Или, если необходимо явно указать драйвер:

Sms::setDriver('sms_ru')->to($phone)->content('why don`t you answer me?')->send();

Вывод


Наш компонент построен по принципу проектирования Мост, то есть реализация и абстракция разделены таким образом, что могут изменяться независимо. Мы можем управлять драйверами через класс SmsManager, при этом сам код применения остается без изменений.
Фасад обеспечивает простой доступ к функционалу нашего компонента.

Такой подход к проектированию компонентов обеспечивает простоту и гибкость их использования.

Ссылки


Laravel Socialite компонент для аутентификации через различные соц.сети
Теги:
Хабы:
+8
Комментарии5

Публикации

Изменить настройки темы

Истории

Работа

PHP программист
155 вакансий

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн