用我们自己的组件扩展Laravel

任务


通过SMS消息向用户添加警报系统,并可以选择提供商。

决断


我认为最好的解决方案是添加自己的组件。
组件是具有明确定义的一组动作(合同)的程序块,可以解决通过各种驱动程序分配给它的任务。例如,内置的组件Cache 可以使用驱动程序:filememcachedredis

在构建组件时,我们将应用设计桥梁的原理,即与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)
        ]);
    }
}

组件管理


要选择和配置驱动程序,请添加从class 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 告诉我们的组件通过哪个驱动程序发送SMS消息。

正面


要从应用程序中的任何位置访问组件的功能,请添加Facade
首先,创建外观类本身:

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消息,只需添加以下代码:

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

结论


我们的组件基于设计Bridge的原理构建,也就是说,实现和抽象是分开的,以便可以独立更改它们。我们可以通过class管理驱动程序SmsManager,而应用程序代码本身保持不变。
通过外观可以轻松访问组件的功能。

这种组件设计方法在使用中提供了简单性和灵活性。

参考文献


Laravel Socialite组件,用于通过各种社交网络进行身份验证

All Articles