From ec8326d02acab6959a8b3de665e3195c8867d7c7 Mon Sep 17 00:00:00 2001 From: overtrue Date: Sat, 29 Apr 2017 21:10:57 +0800 Subject: [PATCH] :sparkles: Add strategy support. --- README.md | 17 ++-- src/Contracts/StrategyInterface.php | 25 ++++++ src/EasySms.php | 93 ++++++++++----------- src/Exceptions/InvalidArgumentException.php | 17 ++++ src/Messenger.php | 73 ++++++++++++++-- src/Strategies/RadomStrategy.php | 32 +++++++ tests/EasySmsTest.php | 10 ++- 7 files changed, 206 insertions(+), 61 deletions(-) create mode 100644 src/Contracts/StrategyInterface.php create mode 100644 src/Exceptions/InvalidArgumentException.php create mode 100644 src/Strategies/RadomStrategy.php diff --git a/README.md b/README.md index 95bcdb8..afd15a4 100644 --- a/README.md +++ b/README.md @@ -29,15 +29,22 @@ $ composer require "overtrue/easy-sms" use Overtrue\EasySms\EasySms; $config = [ - 'default' => 'error-log', - 'shuffle_gateways' => true, - 'enabled_gateways' => ['yunpian', 'alidayu'], + 'timeout' => 5.0, + 'default' => [ + 'strategy' => \Overtrue\EasySms\Strategies\RandomStrategy::class, + 'gateways' => [ + 'yunpian', 'alidayu', + ], + ], 'gateways' => [ - 'error-log' => [ + 'errorlog' => [ 'file' => '/tmp/easy-sms.log', ], 'yunpian' => [ - 'api_key' => '824f0ff2f71cab52936a13ede3xxxxx', + 'api_key' => '824f0ff2f71cab52936axxxxxxxxxx', + ], + alidayu => [ + //... ], ], ]; diff --git a/src/Contracts/StrategyInterface.php b/src/Contracts/StrategyInterface.php new file mode 100644 index 0000000..273be4d --- /dev/null +++ b/src/Contracts/StrategyInterface.php @@ -0,0 +1,25 @@ + + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\EasySms\Contracts; + +/** + * Interface StrategyInterface. + */ +interface StrategyInterface +{ + /** + * Apply the strategy and return result. + * + * @param array $gateways + * + * @return array + */ + public function apply(array $gateways); +} diff --git a/src/EasySms.php b/src/EasySms.php index 80ee555..828fe7b 100644 --- a/src/EasySms.php +++ b/src/EasySms.php @@ -10,9 +10,9 @@ namespace Overtrue\EasySms; use Closure; -use InvalidArgumentException; use Overtrue\EasySms\Contracts\GatewayInterface; -use Overtrue\EasySms\Contracts\MessageInterface; +use Overtrue\EasySms\Contracts\StrategyInterface; +use Overtrue\EasySms\Exceptions\InvalidArgumentException; use Overtrue\EasySms\Support\Config; use RuntimeException; @@ -46,6 +46,11 @@ class EasySms */ protected $messenger; + /** + * @var array + */ + protected $strategies = []; + /** * Constructor. * @@ -65,14 +70,15 @@ public function __construct(array $config) * * @param string|array $to * @param \Overtrue\EasySms\Contracts\MessageInterface $message + * @param array $gateways * * @return array */ - public function send($to, $message) + public function send($to, $message, array $gateways = []) { $messenger = $this->getMessenger(); - return $messenger->send($to, $message, $this->getMessageGateways($message)); + return $messenger->send($to, $message, $gateways); } /** @@ -93,6 +99,34 @@ public function gateway($name = null) return $this->gateways[$name]; } + /** + * Get a strategy instance. + * + * @param string|null $strategy + * + * @return StrategyInterface + */ + public function strategy($strategy = null) + { + if (is_null($strategy)) { + $strategy = $this->config->get('default.strategy'); + } + + if (!class_exists($strategy)) { + $strategy = __NAMESPACE__.'\Strategies\\'.ucfirst($strategy); + } + + if (!class_exists($strategy)) { + throw new InvalidArgumentException("Unsupported strategy \"{$strategy}\""); + } + + if (!($this->strategies[$strategy] instanceof StrategyInterface)) { + $this->strategies[$strategy] = new $strategy($this); + } + + return $this->strategies[$strategy]; + } + /** * Register a custom driver creator Closure. * @@ -108,6 +142,14 @@ public function extend($name, Closure $callback) return $this; } + /** + * @return \Overtrue\EasySms\Support\Config + */ + public function getConfig() + { + return $this->config; + } + /** * Get default gateway name. * @@ -146,36 +188,6 @@ public function getMessenger() return $this->messenger ?: $this->messenger = new Messenger($this); } - /** - * @param \Overtrue\EasySms\Contracts\MessageInterface $message - * - * @return array - */ - protected function getMessageGateways(MessageInterface $message) - { - $gateways = []; - - foreach ($message->getGateways() as $gateway => $setting) { - if (is_integer($gateway) && is_string($setting)) { - $gateway = $setting; - $setting = []; - } - $globalSetting = $this->config->get("gateways.{$gateway}", []); - - if (is_string($gateway) && !empty($globalSetting)) { - $gateways[$gateway] = array_merge($globalSetting, (array) $setting); - } - } - - if ($this->config->get('shuffle_gateways')) { - uasort($gateways, function () { - return mt_rand() - mt_rand(); - }); - } - - return $gateways; - } - /** * Create a new driver instance. * @@ -247,17 +259,4 @@ protected function callCustomCreator($gateway) { return call_user_func($this->customCreators[$gateway], $this->config->get($gateway, [])); } - - /** - * Dynamically call the default gateway instance. - * - * @param string $method - * @param array $parameters - * - * @return mixed - */ - public function __call($method, $parameters) - { - return call_user_func_array([$this->gateway(), $method], $parameters); - } } diff --git a/src/Exceptions/InvalidArgumentException.php b/src/Exceptions/InvalidArgumentException.php new file mode 100644 index 0000000..4378d43 --- /dev/null +++ b/src/Exceptions/InvalidArgumentException.php @@ -0,0 +1,17 @@ + + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\EasySms\Exceptions; + +/** + * Class InvalidArgumentException. + */ +class InvalidArgumentException extends \InvalidArgumentException +{ +} diff --git a/src/Messenger.php b/src/Messenger.php index ec9a63a..eb5e446 100644 --- a/src/Messenger.php +++ b/src/Messenger.php @@ -10,13 +10,30 @@ namespace Overtrue\EasySms; use Overtrue\EasySms\Contracts\MessageInterface; -use Overtrue\EasySms\Support\Config; /** * Class Messenger. */ class Messenger { + const STATUS_SUCCESS = 'success'; + const STATUS_ERRED = 'erred'; + + /** + * @var \Overtrue\EasySms\EasySms + */ + protected $easySms; + + /** + * Messenger constructor. + * + * @param \Overtrue\EasySms\EasySms $easySms + */ + public function __construct(EasySms $easySms) + { + $this->easySms = $easySms; + } + /** * Send a message. * @@ -29,20 +46,62 @@ class Messenger public function send($to, MessageInterface $message, array $gateways = []) { if (!($message instanceof MessageInterface)) { - $message = new Message(['content' => $message, 'template' => $message]); + $message = new Message([ + 'content' => $message, + 'template' => $message, + ]); } - $result = []; + $results = []; - foreach ($gateways as $gateway => $config) { + if (empty($gateways)) { + $gateways = $message->getGateways(); + } + + $gateways = $this->formatGateways($gateways); + $strategyAppliedGateways = $this->easySms->strategy()->apply($gateways); + + foreach ($strategyAppliedGateways as $gateway) { try { - $result[$gateway] = $this->gateway($gateway)->send($to, $message, new Config($config)); + $result[$gateway] = [ + 'status' => self::STATUS_SUCCESS, + 'result' => $this->easySms->gateway($gateway)->send($to, $message, new Config($gateways[$gateway])), + ]; } catch (GatewayErrorException $e) { - $result[$gateway] = $e; + $result[$gateway] = [ + 'status' => self::STATUS_ERRED, + 'exception' => $e, + ]; continue; } } - return false; + return $results; + } + + /** + * @param array $gateways + * + * @return array + */ + protected function formatGateways(array $gateways) + { + $formatted = []; + $config = $this->easySms->getConfig(); + + foreach ($gateways as $gateway => $setting) { + if (is_integer($gateway) && is_string($setting)) { + $gateway = $setting; + $setting = []; + } + + $globalSetting = $config->get("gateways.{$gateway}", []); + + if (is_string($gateway) && !empty($globalSetting) && is_array($setting)) { + $formatted[$gateway] = array_merge($globalSetting, $setting); + } + } + + return $formatted; } } diff --git a/src/Strategies/RadomStrategy.php b/src/Strategies/RadomStrategy.php new file mode 100644 index 0000000..b546028 --- /dev/null +++ b/src/Strategies/RadomStrategy.php @@ -0,0 +1,32 @@ + + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\EasySms\Strategies; + +use Overtrue\EasySms\Contracts\StrategyInterface; + +/** + * Class RandomStrategy. + */ +class RandomStrategy implements StrategyInterface +{ + /** + * @param array $gateways + * + * @return array + */ + public function apply(array $gateways) + { + uasort($gateways, function () { + return mt_rand() - mt_rand(); + }); + + return $gateways; + } +} diff --git a/tests/EasySmsTest.php b/tests/EasySmsTest.php index b9ac97a..cf4a5b5 100644 --- a/tests/EasySmsTest.php +++ b/tests/EasySmsTest.php @@ -73,14 +73,20 @@ public function testExtend() public function testSend() { $message = new Message(['content' => 'hello']); - $config = new Config(); $easySms = \Mockery::mock(EasySms::class.'[getMessenger]', [['default' => DummyGatewayForTest::class]]); $messenger = \Mockery::mock(Messenger::class); $messenger->shouldReceive('send')->with('mock-number', $message, [])->andReturn('send-result'); $easySms->shouldReceive('getMessenger')->andReturn($messenger); - $this->assertSame('send-result', $easySms->send('mock-number', $message, $config)); + $this->assertSame('send-result', $easySms->send('mock-number', $message, [])); + } + + public function testGetMessenger() + { + $easySms = new EasySms([]); + + $this->assertInstanceOf(Messenger::class, $easySms->getMessenger()); } }