Extienda Laravel con nuestros propios componentes.

Tarea


Agregue un sistema de alerta a los usuarios a través de mensajes SMS con la opción de elegir un proveedor.

Decisión


La mejor solución, en mi opinión, es agregar su propio componente.
Un componente es un bloque de programa con un conjunto bien definido de acciones (contrato) que puede resolver las tareas que se le asignan a través de varios controladores. Por ejemplo, el componente integrado Cache puede utilizar el controlador: file, memcachedo redis.

Al construir nuestro componente, aplicaremos el principio de diseño de Bridge, el mismo principio sobre el cual se construyen los componentes de Laravel.

Entonces empecemos.

Conductores


Como dice uno de los postulados: programa de acuerdo con la interfaz, y no con la implementación.

Comenzaremos con él, pero en el contexto del componente es más preciso usar el término contrato. Un contrato es esencialmente un conjunto de interfaces para describir la funcionalidad de un componente.

interface SmsContract
{
    public function send();
}

A continuación, agregue los controladores que ejecutan el contrato. Sacamos la lógica general en una clase abstracta.

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

Y describiremos directamente la lógica de envío en cada clase de controlador.

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

Gestión de componentes


Para seleccionar y configurar controladores, agregue una clase SmsManagerheredada de la clase 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']
        );
    }

}

Ahora es suficiente especificar los parámetros necesarios en el archivo de configuración y la clase SmsManager le dirá a nuestro componente a través de qué controlador enviar mensajes SMS.

Fachada


Para acceder a la funcionalidad del componente desde cualquier lugar de la aplicación, agregue una fachada .
Primero, cree la clase de fachada en sí:

use Illuminate\Support\Facades\Facade;

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

A continuación, asociamos la clase SmsManager con la fachada utilizando el proveedor de servicios y registramos un 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'];
    }
}

Y, por último, registre nuestro proveedor de servicios junto con los otros proveedores en el archivo de configuración ( app/config/app.php).

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

Solicitud


Cuando se crea una fachada para nuestro componente y los parámetros se especifican en el archivo de configuración, para enviar un mensaje SMS, simplemente agregue el siguiente código:

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

O, si necesita especificar explícitamente el controlador:

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

Conclusión


Nuestro componente se basa en el principio de diseñar un puente, es decir, la implementación y la abstracción se separan de tal manera que se pueden cambiar de forma independiente. Podemos administrar los controladores a través de la clase SmsManager, mientras que el código de la aplicación permanece sin cambios.
La fachada proporciona un fácil acceso a la funcionalidad de nuestro componente.

Este enfoque para el diseño de componentes proporciona simplicidad y flexibilidad en su uso.

Referencias


Componente Laravel Socialite para autenticación a través de varias redes sociales

All Articles