From 655c8148a3a4835de664c05689e5121dddb8573b Mon Sep 17 00:00:00 2001
From: overtrue
Date: Thu, 9 Mar 2017 21:27:47 +0800
Subject: [PATCH] Init commit.
---
.editorconfig | 20 +++
.gitattributes | 11 ++
.gitignore | 8 ++
.php_cs | 23 ++++
README.md | 17 +++
composer.json | 30 +++++
phpunit.xml.dist | 22 +++
src/Contracts/GatewayInterface.php | 20 +++
src/EasySms.php | 208 +++++++++++++++++++++++++++++
src/Gateways/LogGateway.php | 25 ++++
src/Gateways/YunPianGateway.php | 25 ++++
src/Support/Config.php | 143 ++++++++++++++++++++
tests/EasySmsTest.php | 79 +++++++++++
tests/Support/ConfigTest.php | 61 +++++++++
tests/TestCase.php | 20 +++
15 files changed, 712 insertions(+)
create mode 100644 .editorconfig
create mode 100644 .gitattributes
create mode 100644 .gitignore
create mode 100644 .php_cs
create mode 100644 README.md
create mode 100644 composer.json
create mode 100644 phpunit.xml.dist
create mode 100644 src/Contracts/GatewayInterface.php
create mode 100644 src/EasySms.php
create mode 100644 src/Gateways/LogGateway.php
create mode 100644 src/Gateways/YunPianGateway.php
create mode 100644 src/Support/Config.php
create mode 100644 tests/EasySmsTest.php
create mode 100644 tests/Support/ConfigTest.php
create mode 100644 tests/TestCase.php
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..df55cd7
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,20 @@
+root = true
+
+[*]
+indent_style = space
+indent_size = 4
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = false
+
+[*.{vue,js,scss}]
+charset = utf-8
+indent_style = space
+indent_size = 2
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.md]
+trim_trailing_whitespace = false
\ No newline at end of file
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..9af3157
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,11 @@
+* text=auto
+
+/tests export-ignore
+.gitattributes export-ignore
+.gitignore export-ignore
+.scrutinizer.yml export-ignore
+.travis.yml export-ignore
+phpunit.php export-ignore
+phpunit.xml.dist export-ignore
+phpunit.xml export-ignore
+.php_cs export-ignore
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b335fba
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+*.DS_Store
+/vendor
+/coverage
+sftp-config.json
+composer.lock
+.subsplit
+.php_cs.cache
+.idea
diff --git a/.php_cs b/.php_cs
new file mode 100644
index 0000000..744301b
--- /dev/null
+++ b/.php_cs
@@ -0,0 +1,23 @@
+
+This source file is subject to the MIT license that is bundled
+with this source code in the file LICENSE.
+EOF;
+Symfony\CS\Fixer\Contrib\HeaderCommentFixer::setHeader($header);
+return Symfony\CS\Config\Config::create()
+ // use default SYMFONY_LEVEL and extra fixers:
+ ->fixers(array(
+ 'header_comment',
+ 'short_array_syntax',
+ 'ordered_use',
+ 'php_unit_construct',
+ 'php_unit_strict',
+ ))
+ ->finder(
+ Symfony\CS\Finder\DefaultFinder::create()
+ ->exclude('vendor')
+ ->in(__DIR__)
+ )
+;
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..9417f5b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,17 @@
+# Easy-sms
+
+The easiest way to send short message.
+
+# Usage
+
+```php
+use Overtrue\EasySms\EasySms;
+
+$config = [...];
+$easySms = new EasySms($config);
+$easySms->gateway('Log')->send(1888888888, 'hello world!');
+```
+
+# License
+
+MIT
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..82a003e
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,30 @@
+{
+ "name": "overtrue/easy-sms",
+ "description": "The easiest way to send short message.",
+ "type": "library",
+ "require": {
+ "guzzlehttp/guzzle": "^6.2",
+ "php": ">=5.5"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0",
+ "mockery/mockery": "^0.9.9"
+ },
+ "autoload": {
+ "psr-4": {
+ "Overtrue\\EasySms\\": "src"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Overtrue\\EasySms\\Tests\\": "tests"
+ }
+ },
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "overtrue",
+ "email": "i@overtrue.me"
+ }
+ ]
+}
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
new file mode 100644
index 0000000..264baab
--- /dev/null
+++ b/phpunit.xml.dist
@@ -0,0 +1,22 @@
+
+
+
+
+ ./tests/
+
+
+
+
+ src/
+
+
+
diff --git a/src/Contracts/GatewayInterface.php b/src/Contracts/GatewayInterface.php
new file mode 100644
index 0000000..9f1aef4
--- /dev/null
+++ b/src/Contracts/GatewayInterface.php
@@ -0,0 +1,20 @@
+config = new Config($config);
+
+ if (!empty($config['default'])) {
+ $this->setDefaultGateway($config['default']);
+ }
+ }
+
+ /**
+ * Create a gateway.
+ *
+ * @param string $name
+ *
+ * @return \Overtrue\EasySms\Contracts\GatewayInterface
+ */
+ public function gateway($name = null)
+ {
+ $name = $name ?: $this->getDefaultGateway();
+
+ if (!isset($this->gateways[$name])) {
+ $this->gateways[$name] = $this->createGateway($name);
+ }
+
+ return $this->gateways[$name];
+ }
+
+ /**
+ * Register a custom driver creator Closure.
+ *
+ * @param string $name
+ * @param \Closure $callback
+ *
+ * @return $this
+ */
+ public function extend($name, Closure $callback)
+ {
+ $this->customCreators[$name] = $callback;
+
+ return $this;
+ }
+
+ /**
+ * Get default gateway name.
+ *
+ * @return string
+ *
+ * @throws if no default gateway configured.
+ */
+ public function getDefaultGateway()
+ {
+ if (empty($this->defaultGateway)) {
+ throw new RuntimeException('No default gateway configured.');
+ }
+
+ return $this->defaultGateway;
+ }
+
+ /**
+ * Set default gateway name.
+ *
+ * @param string $name
+ *
+ * @return $this
+ */
+ public function setDefaultGateway($name)
+ {
+ $this->defaultGateway = $name;
+
+ return $this;
+ }
+
+ /**
+ * Create a new driver instance.
+ *
+ * @param string $name
+ * @throws \InvalidArgumentException
+ *
+ * @return mixed
+ */
+ protected function createGateway($name)
+ {
+ if (isset($this->customCreators[$name])) {
+ $gateway = $this->callCustomCreator($name);
+ } else {
+ $name = $this->formatGatewayClassName($name);
+ $gateway = $this->makeGateway($name, $this->config->get($name, []));
+ }
+
+ if (!($gateway instanceof GatewayInterface)) {
+ throw new InvalidArgumentException(sprintf('Gateway "%s" not inherited from %s.', $name, GatewayInterface::class));
+ }
+
+ return $gateway;
+ }
+
+ /**
+ * Make gateway instance.
+ *
+ * @param string $gateway
+ * @param array $config
+ *
+ * @return \Overtrue\EasySms\Contracts\GatewayInterface
+ */
+ protected function makeGateway($gateway, $config)
+ {
+ if (!class_exists($gateway)) {
+ throw new InvalidArgumentException(sprintf('Gateway "%s" not exists.', $gateway));
+ }
+
+ return new $gateway($config);
+ }
+
+ /**
+ * Format gateway name.
+ *
+ * @param string $name
+ *
+ * @return string
+ */
+ protected function formatGatewayClassName($name)
+ {
+ if (class_exists($name)) {
+ return $name;
+ }
+
+ $name = $this->camelCase($name);
+
+ return __NAMESPACE__."\\Gateways\\{$name}Gateway";
+ }
+
+ /**
+ * Call a custom gateway creator.
+ *
+ * @param string gateway
+ *
+ * @return mixed
+ */
+ protected function callCustomCreator($gateway)
+ {
+ return call_user_func($this->customCreators[$gateway], $this->config->get($gateway, []));
+ }
+
+ /**
+ * Convert string to camel case.
+ *
+ * @param string $name
+ *
+ * @return string
+ */
+ protected function camelCase($name)
+ {
+ return str_replace(' ', '', ucwords(str_replace(['-', '_'], ' ', $name)));
+ }
+
+ /**
+ * 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);
+ }
+}
\ No newline at end of file
diff --git a/src/Gateways/LogGateway.php b/src/Gateways/LogGateway.php
new file mode 100644
index 0000000..ae1e295
--- /dev/null
+++ b/src/Gateways/LogGateway.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\Support;
+
+use ArrayAccess;
+use InvalidArgumentException;
+
+/**
+ * Class Config.
+ */
+class Config implements ArrayAccess
+{
+ /**
+ * @var array
+ */
+ protected $config;
+
+ /**
+ * Config constructor.
+ *
+ * @param array $config
+ */
+ public function __construct(array $config)
+ {
+ $this->config = $config;
+ }
+
+ /**
+ * Get an item from an array using "dot" notation.
+ *
+ * @param string $key
+ * @param mixed $default
+ *
+ * @return mixed
+ */
+ public function get($key, $default = null)
+ {
+ $config = $this->config;
+
+ if (is_null($key)) {
+ return null;
+ }
+
+ if (isset($config[$key])) {
+ return $config[$key];
+ }
+ foreach (explode('.', $key) as $segment) {
+ if (!is_array($config) || !array_key_exists($segment, $config)) {
+ return $default;
+ }
+ $config = $config[$segment];
+ }
+
+ return $config;
+ }
+
+ /**
+ * Whether a offset exists.
+ *
+ * @link http://php.net/manual/en/arrayaccess.offsetexists.php
+ *
+ * @param mixed $offset
+ * An offset to check for.
+ *
+ *
+ * @return bool true on success or false on failure.
+ *
+ *
+ * The return value will be casted to boolean if non-boolean was returned
+ *
+ * @since 5.0.0
+ */
+ public function offsetExists($offset)
+ {
+ return array_key_exists($offset, $this->config);
+ }
+
+ /**
+ * Offset to retrieve.
+ *
+ * @link http://php.net/manual/en/arrayaccess.offsetget.php
+ *
+ * @param mixed $offset
+ * The offset to retrieve.
+ *
+ *
+ * @return mixed Can return all value types
+ *
+ * @since 5.0.0
+ */
+ public function offsetGet($offset)
+ {
+ return $this->get($offset);
+ }
+
+ /**
+ * Offset to set.
+ *
+ * @link http://php.net/manual/en/arrayaccess.offsetset.php
+ *
+ * @param mixed $offset
+ * The offset to assign the value to.
+ *
+ * @param mixed $value
+ * The value to set.
+ *
+ *
+ * @since 5.0.0
+ */
+ public function offsetSet($offset, $value)
+ {
+ if (isset($this->config[$offset])) {
+ $this->config[$offset] = $value;
+ }
+ }
+
+ /**
+ * Offset to unset.
+ *
+ * @link http://php.net/manual/en/arrayaccess.offsetunset.php
+ *
+ * @param mixed $offset
+ * The offset to unset.
+ *
+ *
+ * @since 5.0.0
+ */
+ public function offsetUnset($offset)
+ {
+ if (isset($this->config[$offset])) {
+ unset($this->config[$offset]);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/EasySmsTest.php b/tests/EasySmsTest.php
new file mode 100644
index 0000000..8b26ffe
--- /dev/null
+++ b/tests/EasySmsTest.php
@@ -0,0 +1,79 @@
+assertInstanceOf(GatewayInterface::class, $easySms->gateway('Log'));
+
+ // invalid gateway
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('Gateway "Overtrue\EasySms\Gateways\NotExistsGatewayNameGateway" not exists.');
+
+ $easySms->gateway('NotExistsGatewayName');
+ }
+
+ public function testGatewayWithoutDefaultSetting()
+ {
+ $easySms = new EasySms([]);
+
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessage('No default gateway configured.');
+
+ $easySms->gateway();
+ }
+
+ public function testGatewayWithDefaultSetting()
+ {
+ $easySms = new EasySms(['default' => DummyGatewayForTest::class]);
+ $this->assertSame(DummyGatewayForTest::class, $easySms->getDefaultGateway());
+ $this->assertInstanceOf(DummyGatewayForTest::class, $easySms->gateway());
+
+ // invalid gateway
+ $easySms->setDefaultGateway(DummyInvalidGatewayForTest::class);
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage(
+ sprintf('Gateway "%s" not inherited from %s.',
+ DummyInvalidGatewayForTest::class,
+ GatewayInterface::class)
+ );
+ $easySms->gateway();
+ }
+
+ public function testExtend()
+ {
+ $easySms = new EasySms([]);
+ $easySms->extend('foo', function() {
+ return new DummyGatewayForTest();
+ });
+
+ $this->assertInstanceOf(DummyGatewayForTest::class, $easySms->gateway('foo'));
+ }
+
+ public function testMagicCall()
+ {
+ $easySms = new EasySms(['default' => DummyGatewayForTest::class]);
+
+ $this->assertSame('send-result', $easySms->send('mock-number', 'hello'));
+ }
+}
+
+class DummyGatewayForTest implements GatewayInterface {
+ public function send()
+ {
+ return 'send-result';
+ }
+}
+
+class DummyInvalidGatewayForTest {
+ // nothing
+}
diff --git a/tests/Support/ConfigTest.php b/tests/Support/ConfigTest.php
new file mode 100644
index 0000000..93159aa
--- /dev/null
+++ b/tests/Support/ConfigTest.php
@@ -0,0 +1,61 @@
+ 'bar',
+ 'bar' => [
+ 'screen_name' => 'somebody',
+ 'profile' => [
+ 'id' => 9999,
+ 'name' => 'overtrue',
+ ]
+ ],
+ 'numbers' => [
+ [
+ 'id' => 1,
+ 'number' => 1
+ ],
+ [
+ 'id' => 2,
+ 'number' => 2
+ ],
+ ],
+ ]);
+
+ $this->assertTrue(isset($config['foo']));
+
+ $this->assertSame('bar', $config['foo']);
+ $this->assertSame('bar', $config->get('foo'));
+ $this->assertNull($config->get(null));
+
+ $this->assertSame(9999, $config->get('bar.profile.id'));
+ $this->assertSame('overtrue', $config->get('bar.profile.name'));
+
+ $this->assertSame(1, $config->get('numbers.0.id'));
+ $this->assertSame(1, $config->get('numbers.0.number'));
+
+ $this->assertSame(2, $config->get('numbers.1.id'));
+ $this->assertSame(2, $config->get('numbers.1.number'));
+
+ $config['foo'] = 'new-bar';
+ $this->assertSame('new-bar', $config['foo']);
+
+ unset($config['foo']);
+ $this->assertNull($config['foo']);
+ }
+}
diff --git a/tests/TestCase.php b/tests/TestCase.php
new file mode 100644
index 0000000..66abdc9
--- /dev/null
+++ b/tests/TestCase.php
@@ -0,0 +1,20 @@
+addToAssertionCount($container->mockery_getExpectationCount());
+ }
+
+ Mockery::close();
+ }
+}
\ No newline at end of file