Amplie o Laravel com nossos próprios componentes

Tarefa


Adicione um sistema de alerta aos usuários por meio de mensagens SMS com a opção de escolher um provedor.

Decisão


A melhor solução, na minha opinião, é adicionar seu próprio componente.
Um componente é um bloco de programa com um conjunto claramente definido de ações (contrato) que pode resolver as tarefas atribuídas a ele por meio de vários drivers. Por exemplo, o componente interno Cache pode usar o controlador: file, memcachedou redis.

Ao construir nosso componente, aplicaremos o princípio de design de Bridge, o mesmo princípio no qual os componentes do Laravel são construídos.

Então vamos começar.

Drivers


Como diz um dos postulados: programa de acordo com a interface e não com a implementação.

Vamos começar com isso, mas no contexto do componente é mais preciso usar o termo contrato. Um contrato é essencialmente um conjunto de interfaces para descrever a funcionalidade de um componente.

interface SmsContract
{
    public function send();
}

Em seguida, adicione os drivers que executam o contrato. Retiramos a lógica geral em uma classe abstrata.

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();
}

E descreveremos diretamente a lógica de envio em cada classe de driver.

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)
        ]);
    }
}

Gerenciamento de componentes


Para selecionar e configurar drivers, adicione uma classe SmsManagerherdada da classe 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']
        );
    }

}

Agora basta especificar os parâmetros necessários no arquivo de configuração e a classe informará SmsManager nosso componente através de qual driver enviar mensagens SMS.

Fachada


Para acessar a funcionalidade do componente de qualquer lugar do aplicativo, adicione uma fachada .
Primeiro, crie a própria classe de fachada:

use Illuminate\Support\Facades\Facade;

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

Em seguida, associamos a classe SmsManager à fachada usando o provedor de serviços e registramos um alias.

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'];
    }
}

Por fim, registre nosso provedor de serviços junto com os outros provedores no arquivo de configuração ( app/config/app.php).

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

Inscrição


Quando uma fachada é criada para o nosso componente e os parâmetros são especificados no arquivo de configuração, para enviar uma mensagem SMS, basta adicionar o seguinte código:

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

Ou, se você precisar especificar explicitamente o driver:

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

Conclusão


Nosso componente é construído com base no princípio de projetar uma ponte, isto é, implementação e abstração são separadas de forma que possam ser alteradas independentemente. Podemos gerenciar drivers através da classe SmsManager, enquanto o próprio código do aplicativo permanece inalterado.
A fachada fornece acesso fácil à funcionalidade do nosso componente.

Essa abordagem ao design de componentes fornece simplicidade e flexibilidade em seu uso.

Referências


Componente Socialite do Laravel para autenticação através de várias redes sociais

All Articles