├── .gitignore ├── README.md ├── autoload.php ├── phpunit.xml ├── src ├── test.php ├── wilddogInterface.php ├── wilddogLib.php └── wilddogStub.php └── test ├── phpunit.xml ├── wilddogStubTest.php └── wilddogTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | .project 2 | .buildpath 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Wilddog PHP Client 2 | 3 | 基于 [Wilddog REST API](https://z.wilddog.com/rest/quickstart). 4 | 5 | ### 示例 6 | ```php 7 | const DEFAULT_URL = 'https://testing.wilddogio.com/'; 8 | const DEFAULT_TOKEN = 'xVUeUTLjTye5cS4ugiG6C5BStV0deHgfsCi6SG6W'; 9 | const DEFAULT_PATH = '/wilddog/example'; 10 | 11 | $wilddog = new \Wilddog\WilddogLib(DEFAULT_URL, DEFAULT_TOKEN); 12 | 13 | // --- storing an array --- 14 | $test = array( 15 | "foo" => "bar", 16 | "i_love" => "lamp", 17 | "id" => 42 18 | ); 19 | $dateTime = new DateTime(); 20 | $wilddog->set(DEFAULT_PATH . '/' . $dateTime->format('c'), $test); 21 | 22 | // --- storing a string --- 23 | $wilddog->set(DEFAULT_PATH . '/name/contact001', "John Doe"); 24 | 25 | // --- reading the stored string --- 26 | $name = $wilddog->get(DEFAULT_PATH . '/name/contact001'); 27 | ``` 28 | 29 | ### Token生成 30 | Token用于标识用户身份,结合 [规则表达式](https://z.wilddog.com/rule/quickstart) 做数据读写权限的控制。可以使用超级密钥本身做为token,这样的终端将获得管理员权限,读写数据操作不受规则表达式的限制。也可以使用超级密钥进行签名,自行生成标准jwt格式的token。 31 | 32 | token格式的文档参见:[https://z.wilddog.com/rule/guide/4](https://z.wilddog.com/rule/guide/4)。 33 | 34 | php版token生成工具:[wilddog-token-generator-php](https://github.com/WildDogTeam/wilddog-token-generator-php)。 35 | 36 | 37 | ### API列表 38 | ```php 39 | 40 | // -- Wilddog API 41 | //注意: 所有数据API操作需要判断返回是否成功 42 | $wilddog->set($path, $value); // 存储数据 43 | $value = $wilddog->get($path); // 读取数据 44 | $wilddog->delete($path); // 删除数据 45 | $wilddog->update($path, $data); // 更新数据 46 | $wilddog->push($path, $data); // push数据 47 | 48 | // -- Wilddog PHP Library API 49 | $wilddog->setToken($token); // 设置用户token 50 | $wilddog->setBaseURI($uri); // 设置uri路径 51 | $wilddog->setTimeOut($seconds); // 设置超时时间 52 | ``` 53 | 54 | 详细的Rest API接口描述,请参考 [Wilddog REST API 文档](https://z.wilddog.com/rest/quickstart). 55 | 56 | ### Wilddog PHP Stub 57 | Wilddog PHP Stub使得我们在集成phpunit做单元测试的时候,无需真正和Wilddog云端交互,它相当于一个mock。 58 | 59 | 要使用wilddogStub进行测试,需要让wilddog引用对象作为参数被传递进去,以便于在测试的时候可以很方便的替换为wilddogStub。 60 | 61 | 例如,如果代码是这样的: 62 | 63 | ```php 64 | public function setWilddogValue($path, $value) { 65 | $wilddog = new Wilddog('https://testing.wilddogio.com', 'xVUeUTLjTye5cS4ugiG6C5BStV0deHgfsCi6SG6W'); 66 | $wilddog->set($path, $value); 67 | } 68 | ``` 69 | 70 | 可以改为这样: 71 | 72 | ```php 73 | public function setWilddogValue($path, $value, $wilddog) { 74 | $result = $wilddog->set($path, $value) 75 | if ($result == null && $value != null) { 76 | //若为null 则需要判断是否出现了异常 77 | //只有set的$value为null时 set($path,$value)返回null 78 | //其他情况为请求异常 需要用户进行判断重试 79 | } 80 | } 81 | ``` 82 | 83 | 进行phpunit单元测试: 84 | 85 | ```php 86 | /lib/wilddogInterface.php'; 88 | require_once '/lib/wilddogStub.php'; 89 | 90 | class MyClass extends PHPUnit_Framework_TestCase 91 | { 92 | public function testSetWilddogValue() { 93 | $myClass = new MyClass(); 94 | $wilddogStub = new WilddogStub($uri, $token); 95 | $myClass->setWilddogValue($path, $value, $wilddogStub); 96 | } 97 | } 98 | ?> 99 | ``` 100 | 101 | ### 单元测试 102 | 单元测试代码在/test目录下。测试运行方式如下: 103 | 104 | ```bash 105 | $ phpunit test/wilddogTest.php 106 | ``` 107 | 108 | ```bash 109 | $ phpunit test/wilddogStubTest.php 110 | ``` 111 | 112 | ### License 113 | MIT 114 | http://wilddog.mit-license.org/ -------------------------------------------------------------------------------- /autoload.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | test/*Test.php 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/test.php: -------------------------------------------------------------------------------- 1 | "bar", 13 | "i_love" => "lamp", 14 | "id" => 42 15 | ); 16 | $dateTime = new DateTime(); 17 | $wilddog->set(DEFAULT_PATH . '/' . $dateTime->format('c'), $test); 18 | 19 | // --- storing a string --- 20 | $wilddog->set(DEFAULT_PATH . '/name/contact001', "John Doe"); 21 | 22 | // --- reading the stored string --- 23 | $name = $wilddog->get(DEFAULT_PATH . '/name/contact001'); 24 | echo $name; 25 | 26 | $test = array( 27 | "update" => "update", 28 | "id" => 45 29 | ); 30 | $wilddog->update(DEFAULT_PATH, $test); 31 | 32 | $wilddog->push(DEFAULT_PATH, $test); 33 | 34 | ?> -------------------------------------------------------------------------------- /src/wilddogInterface.php: -------------------------------------------------------------------------------- 1 | setBaseURI($baseURI); 27 | $this->setTimeOut(10); 28 | $this->setToken($token); 29 | } 30 | 31 | /** 32 | * Sets Token 33 | * 34 | * @param string $token Token 35 | * 36 | * @return void 37 | */ 38 | public function setToken($token) 39 | { 40 | $this->_token = $token; 41 | } 42 | 43 | /** 44 | * Sets Base URI, ex: https://.wilddogio.com/path 45 | * 46 | * @param string $baseURI Base URI 47 | * 48 | * @return void 49 | */ 50 | public function setBaseURI($baseURI) 51 | { 52 | $baseURI .= (substr($baseURI, -1) == '/' ? '' : '/'); 53 | $this->_baseURI = $baseURI; 54 | } 55 | 56 | /** 57 | * Returns with the normalized JSON absolute path 58 | * 59 | * @param string $path to data 60 | * @return string 61 | */ 62 | private function _getJsonPath($path) 63 | { 64 | $url = $this->_baseURI; 65 | $path = ltrim($path, '/'); 66 | $auth = ($this->_token == '') ? '' : '?auth=' . $this->_token; 67 | return $url . $path . '.json' . $auth; 68 | } 69 | 70 | /** 71 | * Sets REST call timeout in seconds 72 | * 73 | * @param integer $seconds Seconds to timeout 74 | * 75 | * @return void 76 | */ 77 | public function setTimeOut($seconds) 78 | { 79 | $this->_timeout = $seconds; 80 | } 81 | 82 | /** 83 | * Writing data into Wilddog with a PUT request 84 | * HTTP 200: Ok 85 | * 86 | * @param string $path Path 87 | * @param mixed $data Data 88 | * 89 | * @return array Response 90 | */ 91 | public function set($path, $data) 92 | { 93 | return $this->_writeData($path, $data, 'PUT'); 94 | } 95 | 96 | /** 97 | * Pushing data into Wilddog with a POST request 98 | * HTTP 200: Ok 99 | * 100 | * @param string $path Path 101 | * @param mixed $data Data 102 | * 103 | * @return array Response 104 | */ 105 | public function push($path, $data) 106 | { 107 | return $this->_writeData($path, $data, 'POST'); 108 | } 109 | 110 | /** 111 | * Updating data into Wilddog with a PATH request 112 | * HTTP 200: Ok 113 | * 114 | * @param string $path Path 115 | * @param mixed $data Data 116 | * 117 | * @return array Response 118 | */ 119 | public function update($path, $data) 120 | { 121 | return $this->_writeData($path, $data, 'PATCH'); 122 | } 123 | 124 | /** 125 | * Reading data from Wilddog 126 | * HTTP 200: Ok 127 | * 128 | * @param string $path Path 129 | * 130 | * @return array Response 131 | */ 132 | public function get($path) 133 | { 134 | try { 135 | $ch = $this->_getCurlHandler($path, 'GET'); 136 | $return = curl_exec($ch); 137 | curl_close($ch); 138 | } catch (Exception $e) { 139 | $return = null; 140 | } 141 | return $return; 142 | } 143 | 144 | /** 145 | * Deletes data from Wilddog 146 | * HTTP 204: Ok 147 | * 148 | * @param string $path Path 149 | * 150 | * @return array Response 151 | */ 152 | public function delete($path) 153 | { 154 | try { 155 | $ch = $this->_getCurlHandler($path, 'DELETE'); 156 | $return = curl_exec($ch); 157 | curl_close($ch); 158 | } catch (Exception $e) { 159 | $return = null; 160 | } 161 | return $return; 162 | } 163 | 164 | /** 165 | * Returns with Initialized CURL Handler 166 | * 167 | * @param string $mode Mode 168 | * 169 | * @return resource Curl Handler 170 | */ 171 | private function _getCurlHandler($path, $mode) 172 | { 173 | $url = $this->_getJsonPath($path); 174 | $ch = curl_init(); 175 | curl_setopt($ch, CURLOPT_URL, $url); 176 | curl_setopt($ch, CURLOPT_TIMEOUT, $this->_timeout); 177 | curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->_timeout); 178 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 179 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 180 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $mode); 181 | return $ch; 182 | } 183 | 184 | private function _writeData($path, $data, $method = 'PUT') 185 | { 186 | $jsonData = json_encode($data); 187 | $header = array( 188 | 'Content-Type: application/json', 189 | 'Content-Length: ' . strlen($jsonData) 190 | ); 191 | try { 192 | $ch = $this->_getCurlHandler($path, $method); 193 | curl_setopt($ch, CURLOPT_HTTPHEADER, $header); 194 | curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonData); 195 | $return = curl_exec($ch); 196 | 197 | curl_close($ch); 198 | } catch (Exception $e) { 199 | $return = null; 200 | } 201 | return $return; 202 | } 203 | } -------------------------------------------------------------------------------- /src/wilddogStub.php: -------------------------------------------------------------------------------- 1 | setBaseURI($baseURI); 32 | $this->setTimeOut(10); 33 | $this->setToken($token); 34 | } 35 | 36 | /** 37 | * @param $token 38 | * @return null 39 | */ 40 | public function setToken($token) 41 | { 42 | $this->_token = $token; 43 | } 44 | 45 | /** 46 | * @param $baseURI 47 | * @return null 48 | */ 49 | public function setBaseURI($baseURI) 50 | { 51 | $baseURI .= (substr($baseURI, -1) == '/' ? '' : '/'); 52 | $this->_baseURI = $baseURI; 53 | } 54 | 55 | /** 56 | * @param $seconds 57 | * @return null 58 | */ 59 | public function setTimeOut($seconds) 60 | { 61 | $this->_timeout = $seconds; 62 | } 63 | 64 | /** 65 | * @param $path 66 | * @param $data 67 | * @return null 68 | */ 69 | 70 | public function set($path, $data) 71 | { 72 | return $this->_getSetResponse($data); 73 | } 74 | 75 | /** 76 | * @param $path 77 | * @param $data 78 | * @return null 79 | */ 80 | public function push($path, $data) 81 | { 82 | return $this->set($path, $data); 83 | } 84 | 85 | /** 86 | * @param $path 87 | * @param $data 88 | * @return null 89 | */ 90 | public function update($path, $data) 91 | { 92 | return $this->set($path, $data); 93 | } 94 | 95 | /** 96 | * @param $path 97 | * @return null 98 | */ 99 | public function get($path) 100 | { 101 | return $this->_getGetResponse(); 102 | } 103 | 104 | /** 105 | * @param $path 106 | * @return null 107 | */ 108 | public function delete($path) 109 | { 110 | return $this->_getDeleteResponse(); 111 | } 112 | 113 | /** 114 | * @param $expectedResponse 115 | */ 116 | public function setResponse($expectedResponse) 117 | { 118 | $this->_response = $expectedResponse; 119 | } 120 | 121 | /** 122 | * @uses $this->_baseURI 123 | * @return Error 124 | */ 125 | private function _isBaseURIValid() { 126 | $error = preg_match('/^https:\/\//', $this->_baseURI); 127 | return new Error(($error == 0 ? true : false), 'Wilddog does not support non-ssl traffic. Please try your request again over https.'); 128 | } 129 | 130 | /** 131 | * @param $data 132 | * @return Error 133 | */ 134 | private function _isDataValid($data) { 135 | if ($data == "" || $data == null) { 136 | return new Error(true, "Missing data; Perhaps you forgot to send the data."); 137 | } 138 | $error = json_decode($data); 139 | return new Error(($error ? false : true), "Invalid data; couldn't parse JSON object, array, or value. Perhaps you're using invalid characters in your key names."); 140 | } 141 | 142 | /** 143 | * @param $data 144 | * @return null 145 | */ 146 | private function _getSetResponse($data) 147 | { 148 | $validBaseUriObject = $this->_isBaseURIValid(); 149 | if ($validBaseUriObject->error) { 150 | return $validBaseUriObject->message; 151 | } 152 | $validDataObject = $this->_isDataValid($data); 153 | if ($validDataObject->error) { 154 | return $validDataObject->message; 155 | } 156 | return $this->_response; 157 | } 158 | 159 | /** 160 | * @return null 161 | */ 162 | private function _getGetResponse() 163 | { 164 | $validBaseUriObject = $this->_isBaseURIValid(); 165 | if ($validBaseUriObject->error) { 166 | return $validBaseUriObject->message; 167 | } 168 | return $this->_response; 169 | } 170 | 171 | /** 172 | * @return null 173 | */ 174 | private function _getDeleteResponse() { return $this->_getGetResponse(); } 175 | } 176 | 177 | class Error { 178 | function __construct($error, $message) 179 | { 180 | $this->error = $error; 181 | $this->message = $message; 182 | } 183 | } -------------------------------------------------------------------------------- /test/phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | . 5 | 6 | 7 | -------------------------------------------------------------------------------- /test/wilddogStubTest.php: -------------------------------------------------------------------------------- 1 | _wilddogStub = new WilddogStub(self::DEFAULT_URL, self::DEFAULT_TOKEN); 22 | } 23 | public function testBaseURIInitializationOnInstantiation() 24 | { 25 | $this->assertEquals(self::DEFAULT_TOKEN, $this->_wilddogStub->_token); 26 | } 27 | public function testSetBaseURI() 28 | { 29 | $actualResponse = $this->_wilddogStub->setBaseURI(self::UPDATED_URI); 30 | $this->assertEquals(null, $actualResponse); 31 | $this->assertEquals(self::UPDATED_URI, $this->_wilddogStub->_baseURI); 32 | } 33 | public function testTokenInitializationOnInstantiation() 34 | { 35 | $this->assertEquals(self::DEFAULT_TOKEN, $this->_wilddogStub->_token); 36 | } 37 | public function testSetToken() 38 | { 39 | $actualResponse = $this->_wilddogStub->setToken(self::UPDATED_TOKEN); 40 | $this->assertEquals(null, $actualResponse); 41 | $this->assertEquals(self::UPDATED_TOKEN, $this->_wilddogStub->_token); 42 | } 43 | public function testTimeoutInitializationOnInstantiation() 44 | { 45 | $this->assertEquals(self::DEFAULT_TIMEOUT, $this->_wilddogStub->_timeout); 46 | } 47 | public function testSetTimeout() 48 | { 49 | $actualResponse = $this->_wilddogStub->setTimeout(self::UPDATED_TIMEOUT); 50 | $this->assertEquals(null, $actualResponse); 51 | $this->assertEquals(self::UPDATED_TIMEOUT, $this->_wilddogStub->_timeout); 52 | } 53 | public function testSet() 54 | { 55 | $this->_wilddogStub->setResponse(self::DEFAULT_DATA); 56 | $actualResponse = $this->_wilddogStub->set(self::DEFAULT_PATH, self::DEFAULT_DATA); 57 | $this->assertEquals(self::DEFAULT_DATA, $actualResponse); 58 | } 59 | public function testPush() 60 | { 61 | $this->_wilddogStub->setResponse(self::DEFAULT_PUSH_DATA); 62 | $actualResponse = $this->_wilddogStub->push(self::DEFAULT_PATH, self::DEFAULT_DATA); 63 | $this->assertEquals(self::DEFAULT_PUSH_DATA, $actualResponse); 64 | } 65 | public function testUpdate() 66 | { 67 | $this->_wilddogStub->setResponse(self::DEFAULT_DATA); 68 | $actualResponse = $this->_wilddogStub->update(self::DEFAULT_PATH, self::DEFAULT_DATA); 69 | $this->assertEquals(self::DEFAULT_DATA, $actualResponse); 70 | } 71 | public function testDelete() 72 | { 73 | $actualResponse = $this->_wilddogStub->delete(self::DEFAULT_PATH, self::DEFAULT_DATA); 74 | $this->assertEquals(null, $actualResponse); 75 | } 76 | public function testInvalidBaseUri() 77 | { 78 | $wilddog = new WilddogStub(self::INSECURE_URL); 79 | $response = $wilddog->set(self::DEFAULT_PATH, self::DEFAULT_DATA); 80 | $this->assertEquals($this->_getErrorMessages('INSECURE_URL'), $response); 81 | } 82 | public function testInvalidData() 83 | { 84 | $response = $this->_wilddogStub->set(self::DEFAULT_PATH, self::INVALID_DATA); 85 | $this->assertEquals($this->_getErrorMessages('INVALID_JSON'), $response); 86 | } 87 | public function testMissingData() 88 | { 89 | $response = $this->_wilddogStub->set(self::DEFAULT_PATH, self::MISSING_DATA); 90 | $this->assertEquals($this->_getErrorMessages('NO_DATA'), $response); 91 | } 92 | public function testNullData() 93 | { 94 | $response = $this->_wilddogStub->set(self::DEFAULT_PATH, self::NULL_DATA); 95 | $this->assertEquals($this->_getErrorMessages('NO_DATA'), $response); 96 | } 97 | private function _getErrorMessages($errorCode) { 98 | $errorMessages = Array( 99 | 'INSECURE_URL' => 'Wilddog does not support non-ssl traffic. Please try your request again over https.', 100 | 'INVALID_JSON' => 'Invalid data; couldn\'t parse JSON object, array, or value. Perhaps you\'re using invalid characters in your key names.', 101 | 'NO_DATA' => 'Missing data; Perhaps you forgot to send the data.' 102 | ); 103 | return $errorMessages[$errorCode]; 104 | } 105 | } -------------------------------------------------------------------------------- /test/wilddogTest.php: -------------------------------------------------------------------------------- 1 | 'Pick the milk', 9 | 'priority' => 1 10 | ); 11 | protected $_todoBeer = array( 12 | 'name' => 'Pick the beer', 13 | 'priority' => 2 14 | ); 15 | protected $_todoLEGO = array( 16 | 'name' => 'Pick the LEGO', 17 | 'priority' => 3 18 | ); 19 | // --- set up your own database here 20 | const DEFAULT_URL = 'https://testing.wilddogio.com/'; 21 | const DEFAULT_TOKEN = 'xVUeUTLjTye5cS4ugiG6C5BStV0deHgfsCi6SG6W'; 22 | const DEFAULT_TODO_PATH = '/sample/todo'; 23 | const DELETE_PATH = '/sample'; 24 | const DEFAULT_SET_RESPONSE = '{"name":"Pick the milk","priority":1}'; 25 | const DEFAULT_UPDATE_RESPONSE = '{"name":"Pick the beer","priority":2}'; 26 | const DEFAULT_PUSH_RESPONSE = '{"name":"Pick the LEGO","priority":3}'; 27 | const DEFAULT_DELETE_RESPONSE = 'null'; 28 | const DEFAULT_URI_ERROR = 'You must provide a baseURI variable.'; 29 | public function setUp() 30 | { 31 | $this->_wilddog = new WilddogLib(self::DEFAULT_URL, self::DEFAULT_TOKEN); 32 | } 33 | public function testNoBaseURI() 34 | { 35 | $errorMessage = null; 36 | try { 37 | new WilddogLib(); 38 | } catch (Exception $e) { 39 | $errorMessage = $e->getMessage(); 40 | } 41 | $this->assertEquals(self::DEFAULT_URI_ERROR, $errorMessage); 42 | } 43 | public function testSet() 44 | { 45 | $response = $this->_wilddog->set(self::DEFAULT_TODO_PATH, $this->_todoMilk); 46 | $this->assertEquals(self::DEFAULT_SET_RESPONSE, $response); 47 | } 48 | public function testGetAfterSet() 49 | { 50 | $response = $this->_wilddog->get(self::DEFAULT_TODO_PATH); 51 | $this->assertEquals(self::DEFAULT_SET_RESPONSE, $response); 52 | } 53 | public function testUpdate() 54 | { 55 | $response = $this->_wilddog->update(self::DEFAULT_TODO_PATH, $this->_todoBeer); 56 | $this->assertEquals(self::DEFAULT_UPDATE_RESPONSE, $response); 57 | } 58 | public function testGetAfterUpdate() 59 | { 60 | $response = $this->_wilddog->get(self::DEFAULT_TODO_PATH); 61 | $this->assertEquals(self::DEFAULT_UPDATE_RESPONSE, $response); 62 | } 63 | public function testPush() 64 | { 65 | $response = $this->_wilddog->push(self::DEFAULT_TODO_PATH, $this->_todoLEGO); 66 | $this->assertRegExp('/{"name"\s?:\s?".*?}/', $response); 67 | return $this->parsePushResponse($response); 68 | } 69 | /** 70 | * @depends testPush 71 | */ 72 | public function testGetAfterPush($responseName) 73 | { 74 | $response = $this->_wilddog->get(self::DEFAULT_TODO_PATH . '/' . $responseName); 75 | $this->assertEquals(self::DEFAULT_PUSH_RESPONSE, $response); 76 | } 77 | public function testDelete() 78 | { 79 | $response = $this->_wilddog->delete(self::DELETE_PATH); 80 | $this->assertEquals(self::DEFAULT_DELETE_RESPONSE, $response); 81 | } 82 | public function testGetAfterDELETE() 83 | { 84 | $response = $this->_wilddog->get(self::DEFAULT_TODO_PATH); 85 | $this->assertEquals(self::DEFAULT_DELETE_RESPONSE, $response); 86 | } 87 | private function parsePushResponse($response) { 88 | $responseObj = json_decode($response); 89 | return $responseObj->name; 90 | } 91 | } --------------------------------------------------------------------------------