Étendez Laravel avec nos propres composants

Tâche


Ajoutez un système d'alerte aux utilisateurs via des SMS avec la possibilité de choisir un fournisseur.

Décision


La meilleure solution, à mon avis, est d'ajouter votre propre composant.
Un composant est un bloc de programme avec un ensemble d'actions (contrat) bien défini qui peut résoudre les tâches qui lui sont assignées via différents pilotes. Par exemple, le composant intégré dans Cache peut utiliser le pilote: file, memcachedou redis.

Lors de la construction de notre composant, nous appliquerons le principe de conception Bridge, le même principe sur lequel les composants Laravel sont construits.

Alors, commençons.

Conducteurs


Comme le dit l'un des postulats: programmez en fonction de l'interface, et non de l'implémentation.

Nous allons commencer par cela, mais dans le contexte du composant, il est plus précis d'utiliser le terme contrat. Un contrat est essentiellement un ensemble d'interfaces pour décrire la fonctionnalité d'un composant.

interface SmsContract
{
    public function send();
}

Ensuite, ajoutez les pilotes qui exécutent le contrat. Nous sortons la logique générale dans une classe abstraite.

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

Et nous décrirons directement la logique d'envoi dans chaque classe de pilote.

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

Gestion des composants


Pour sélectionner et configurer des pilotes, ajoutez une classe SmsManagerhéritée de la 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']
        );
    }

}

Il suffit maintenant de spécifier les paramètres nécessaires dans le fichier de configuration et la classe indiquera à SmsManager notre composant via quel pilote envoyer des SMS.

Façade


Pour accéder aux fonctionnalités du composant depuis n'importe où dans l'application, ajoutez une façade .
Tout d'abord, créez la classe de façade elle-même:

use Illuminate\Support\Facades\Facade;

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

Ensuite, nous associons la classe SmsManager à la façade à l'aide du fournisseur de services et enregistrons 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'];
    }
}

Enfin, enregistrez notre fournisseur de services avec les autres fournisseurs dans le fichier de configuration ( app/config/app.php).

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

Application


Lorsqu'une façade est créée pour notre composant et que les paramètres sont spécifiés dans le fichier de configuration, pour envoyer un SMS, ajoutez simplement le code suivant:

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

Ou, si vous devez spécifier explicitement le pilote:

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

Conclusion


Notre composant est construit sur le principe de la conception du pont, c'est-à-dire que la mise en œuvre et l'abstraction sont séparées de manière à pouvoir être modifiées indépendamment. Nous pouvons gérer les pilotes via la classe SmsManager, tandis que le code d'application lui-même reste inchangé.
La façade offre un accès facile aux fonctionnalités de notre composant.

Cette approche de la conception des composants offre simplicité et flexibilité dans leur utilisation.

Références


Composant Laravel Socialite pour l'authentification via divers réseaux sociaux

All Articles