├── travis.php.ini ├── tests ├── bootstrap.php ├── FakePostmen.php └── Postmen.php ├── .travis.yml ├── examples ├── credentials.php ├── cancel_labels_create.php ├── labels_retrieve.php ├── rates_retrieve.php ├── manifests_create.php ├── manifests_retrieve.php ├── cancel_labels_retrieve.php ├── proxy.php ├── response.php ├── error.php ├── rates_create.php └── labels_create.php ├── composer.json ├── src └── Postmen │ ├── PostmenException.php │ └── Postmen.php └── README.md /travis.php.ini: -------------------------------------------------------------------------------- 1 | extension=runkit.so 2 | runkit.internal_override=1 3 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | before_install: 2 | - pecl install runkit 3 | - phpenv config-add travis.php.ini 4 | - composer self-update 5 | - composer install 6 | language: php 7 | php: 8 | - 5.3 9 | - 5.4 10 | - 5.5 11 | - 5.6 12 | script: phpunit --bootstrap tests/bootstrap.php tests/Postmen.php 13 | 14 | -------------------------------------------------------------------------------- /tests/FakePostmen.php: -------------------------------------------------------------------------------- 1 | $method, 10 | 'path' => $path, 11 | 'parameters' => $config, 12 | 'curl' => $this->buildCurlParams($method, $path, $config) 13 | ); 14 | return $call; 15 | } 16 | } 17 | 18 | ?> 19 | -------------------------------------------------------------------------------- /examples/credentials.php: -------------------------------------------------------------------------------- 1 | 20 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "postmen/sdk-php", 3 | "description": "PHP for Postmen API. This extension helps developers to integrate with Postmen easily.", 4 | "minimum-stability": "stable", 5 | "license": "MIT", 6 | "authors": [], 7 | "require": {}, 8 | "version": "1.0.0", 9 | "require-dev": { 10 | "phpunit/phpunit": "3.7.*", 11 | "tcz/phpunit-mockfunction": "v1.0.0" 12 | }, 13 | "autoload": { 14 | "psr-0": { 15 | "Postmen": "src/" 16 | } 17 | } 18 | } 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Postmen/PostmenException.php: -------------------------------------------------------------------------------- 1 | retryable = $retryable; 19 | $this->details = $details; 20 | parent::__construct($message, $code, $previous); 21 | } 22 | 23 | public function isRetryable() { 24 | return $this->retryable; 25 | } 26 | 27 | public function getDetails() { 28 | return $this->details; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /examples/cancel_labels_create.php: -------------------------------------------------------------------------------- 1 | array ( 15 | 'id' => $label 16 | ) 17 | ); 18 | 19 | 20 | try { 21 | $api = new Postmen($key, $region); 22 | $result = $api->create('cancel-labels', $payload); 23 | echo "RESULT:\n"; 24 | print_r($result); 25 | } catch (exception $e) { 26 | echo "ERROR:\n"; 27 | echo $e->getCode() . "\n"; // error code 28 | echo $e->getMessage() . "\n"; // error message 29 | print_r($e->getDetails()); // error details 30 | } 31 | ?> 32 | -------------------------------------------------------------------------------- /examples/labels_retrieve.php: -------------------------------------------------------------------------------- 1 | get('labels'); 17 | // get a particular label 18 | $result_particular = $api->get('labels', $label); 19 | echo "RESULT:\n"; 20 | print_r($result_all); 21 | print_r($result_particular); 22 | } catch (exception $e) { 23 | echo "ERROR:\n"; 24 | echo $e->getCode() . "\n"; // error code 25 | echo $e->getMessage() . "\n"; // error message 26 | print_r($e->getDetails()); // error details 27 | } 28 | ?> 29 | -------------------------------------------------------------------------------- /examples/rates_retrieve.php: -------------------------------------------------------------------------------- 1 | get('rates'); 17 | // retrieve a particular rate 18 | $result_particular = $api->get('rates', $rate); 19 | echo "RESULT:\n"; 20 | print_r($result_all); 21 | print_r($result_particular); 22 | } catch (exception $e) { 23 | echo "ERROR:\n"; 24 | echo $e->getCode() . "\n"; // error code 25 | echo $e->getMessage() . "\n"; // error message 26 | print_r($e->getDetails()); // error details 27 | } 28 | ?> 29 | -------------------------------------------------------------------------------- /examples/manifests_create.php: -------------------------------------------------------------------------------- 1 | 15 | array ( 16 | 'id' => $shipper, 17 | ), 18 | 'async' => false 19 | ); 20 | 21 | try { 22 | $api = new Postmen($key, $region); 23 | $result = $api->create('manifests', $payload); 24 | echo "RESULT:\n"; 25 | print_r($result); 26 | } catch (exception $e) { 27 | echo "ERROR:\n"; 28 | echo $e->getCode() . "\n"; // error code 29 | echo $e->getMessage() . "\n"; // error message 30 | print_r($e->getDetails()); // error details 31 | } 32 | ?> 33 | -------------------------------------------------------------------------------- /examples/manifests_retrieve.php: -------------------------------------------------------------------------------- 1 | get('manifests'); 17 | // retrieve a particular manifest 18 | $result_particular = $api->get('manifests', $manifest); 19 | echo "RESULT:\n"; 20 | print_r($result_all); 21 | print_r($result_particular); 22 | } catch (exception $e) { 23 | echo "ERROR:\n"; 24 | echo $e->getCode() . "\n"; // error code 25 | echo $e->getMessage() . "\n"; // error message 26 | print_r($e->getDetails()); // error details 27 | } 28 | ?> 29 | -------------------------------------------------------------------------------- /examples/cancel_labels_retrieve.php: -------------------------------------------------------------------------------- 1 | get('cancel-labels'); 17 | // get a particular cancelled label 18 | $result_particular = $api->get('cancel-labels', $label); 19 | echo "RESULT:\n"; 20 | print_r($result_all); 21 | print_r($result_particular); 22 | } catch (exception $e) { 23 | echo "ERROR:\n"; 24 | echo $e->getCode() . "\n"; // error code 25 | echo $e->getMessage() . "\n"; // error message 26 | print_r($e->getDetails()); // error details 27 | } 28 | ?> 29 | 30 | -------------------------------------------------------------------------------- /examples/proxy.php: -------------------------------------------------------------------------------- 1 | "proxyserver.com", // required 8 | "port" => 9999, // optional 9 | "username" => "user", // optional 10 | "password" => "pass" // optional 11 | ); 12 | 13 | try { 14 | // putting proxy in the constructor sets 15 | // it by default for all calls 16 | $api = new Postmen($key, $region, array('proxy' => $proxy)); 17 | // putting the proxy object in a call 18 | // will make it be used only once, this 19 | // can also be used to disable it for purpose 20 | // of a single call 21 | $result = $api->get('labels', NULL, NULL, array('proxy' => $proxy)); 22 | echo "RESULT:\n"; 23 | print_r($result); 24 | } catch (exception $e) { 25 | echo "ERROR:\n"; 26 | echo $e->getCode() . "\n"; // error code 27 | echo $e->getMessage() . "\n"; // error message 28 | print_r($e->getDetails()); // error details 29 | } 30 | ?> 31 | -------------------------------------------------------------------------------- /examples/response.php: -------------------------------------------------------------------------------- 1 | get('labels', NULL, NULL, array('raw' => true)); 10 | // get a std object 11 | $output_object = $api->get('labels'); 12 | // to get an array it requires to initiate 13 | // handler object with that option 14 | $array_api = new Postmen($key, $region, array('array' => true)); 15 | $output_array = $array_api->get('labels'); 16 | echo "RESULT:\n"; 17 | echo "raw json output:\n"; 18 | echo $output_json . "\n\n"; 19 | echo "std object output:\n"; 20 | print_r($output_object); 21 | echo "\narray object output\n"; 22 | print_r($output_array); 23 | } catch (exception $e) { 24 | echo "ERROR:\n"; 25 | echo $e->getCode() . "\n"; // error code 26 | echo $e->getMessage() . "\n"; // error message 27 | print_r($e->getDetails()); // error details 28 | } 29 | ?> 30 | -------------------------------------------------------------------------------- /examples/error.php: -------------------------------------------------------------------------------- 1 | get('labels'); 16 | } catch (exception $e) { 17 | echo "ERROR:\n"; 18 | echo $e->getCode() . "\n"; // error code 19 | echo $e->getMessage() . "\n"; // error message 20 | print_r($e->getDetails()); // error details 21 | } 22 | 23 | // we also can enable the safe mode, 24 | // this way try{}catch(){} is no 25 | // longer required 26 | 27 | echo "using safe mode\n"; 28 | $api = new Postmen('THIS IS NOT A VALID API KEY', $region); 29 | $result = $api->get('labels', NULL, NULL, array('safe' => true)); 30 | if (!$result) { 31 | $e = $api->getError(); 32 | echo "ERROR:\n"; 33 | echo $e->getCode() . "\n"; // error code 34 | echo $e->getMessage() . "\n"; // error message 35 | print_r($e->getDetails()); // error details 36 | } 37 | ?> 38 | -------------------------------------------------------------------------------- /examples/rates_create.php: -------------------------------------------------------------------------------- 1 | 'PS4', 15 | 'origin_country' => 'JPN', 16 | 'quantity' => 2, 17 | 'price' => array ( 18 | 'amount' => 50, 19 | 'currency' => 'JPY', 20 | ), 21 | 'weight' => array ( 22 | 'value' => 0.59999999999999998, 23 | 'unit' => 'kg', 24 | ), 25 | 'sku' => 'PS4-2015', 26 | ); 27 | $sender = array ( 28 | 'contact_name' => 'Yin Ting Wong', 29 | 'street1' => 'Flat A, 30/F, Block 17 Laguna Verde', 30 | 'city' => 'Hung Hom', 31 | 'state' => 'Kowloon', 32 | 'country' => 'HKG', 33 | 'phone' => '96679797', 34 | 'email' => 'test@test.test', 35 | 'type' => 'residential', 36 | ); 37 | $receiver = array ( 38 | 'contact_name' => 'Mike Carunchia', 39 | 'street1' => '9504 W Smith ST', 40 | 'city' => 'Yorktown', 41 | 'state' => 'Indiana', 42 | 'postal_code' => '47396', 43 | 'country' => 'USA', 44 | 'phone' => '7657168649', 45 | 'email' => 'test@test.test', 46 | 'type' => 'residential', 47 | ); 48 | $payload = array ( 49 | 'async' => false, 50 | 'shipper_accounts' => array ( 51 | 0 => array ( 52 | 'id' => $shipper, 53 | ), 54 | ), 55 | 'shipment' => array ( 56 | 'parcels' => array ( 57 | 0 => array ( 58 | 'box_type' => 'custom', 59 | 'weight' => array ( 60 | 'value' => 0.5, 61 | 'unit' => 'kg', 62 | ), 63 | 'dimension' => array ( 64 | 'width' => 20, 65 | 'height' => 10, 66 | 'depth' => 10, 67 | 'unit' => 'cm', 68 | ), 69 | 'items' => array ( 70 | 0 => $item 71 | ), 72 | ), 73 | ), 74 | 'ship_from' => $sender, 75 | 'ship_to' => $receiver, 76 | ), 77 | 'is_document' => false 78 | ); 79 | 80 | try { 81 | $api = new Postmen($key, $region); 82 | $result = $api->create('rates', $payload); 83 | echo "RESULT:\n"; 84 | print_r($result); 85 | } catch (exception $e) { 86 | echo "ERROR:\n"; 87 | echo $e->getCode() . "\n"; // error code 88 | echo $e->getMessage() . "\n"; // error message 89 | print_r($e->getDetails()); // error details 90 | } 91 | ?> 92 | -------------------------------------------------------------------------------- /examples/labels_create.php: -------------------------------------------------------------------------------- 1 | 'info about the parcel', 15 | 'box_type' => 'custom', 16 | 'weight' => array ( 17 | 'value' => 1.5, 18 | 'unit' => 'kg', 19 | ), 20 | 'dimension' => array ( 21 | 'width' => 20, 22 | 'height' => 30, 23 | 'depth' => 40, 24 | 'unit' => 'cm', 25 | ), 26 | 'items' => array ( 27 | 0 => array ( 28 | 'description' => 'Food Bar', 29 | 'origin_country' => 'USA', 30 | 'quantity' => 2, 31 | 'price' => array ( 32 | 'amount' => 50, 33 | 'currency' => 'USD', 34 | ), 35 | 'weight' => array ( 36 | 'value' => 0.6, 37 | 'unit' => 'kg', 38 | ), 39 | ), 40 | ), 41 | ); 42 | 43 | $sender = array ( 44 | 'contact_name' => 'your name', 45 | 'company_name' => 'name of your company', 46 | 'street1' => 'your address', 47 | 'street2' => null, 48 | 'street3' => null, 49 | 'city' => 'your city', 50 | 'state' => 'your state', 51 | 'postal_code' => 'your postal code', 52 | 'country' => 'HKG', 53 | 'phone' => '1-403-504-5496', 54 | 'fax' => '1-403-504-5497', 55 | 'tax_id' => null, 56 | 'email' => 'test@test.com', 57 | 'type' => 'business' 58 | ); 59 | 60 | $receiver = array ( 61 | 'contact_name' => 'Rick McLeod (RM Consulting)', 62 | 'street1' => '71 Terrace Crescent NE', 63 | 'street2' => 'This is the second streeet', 64 | 'city' => 'Medicine Hat', 65 | 'state' => 'Alberta', 66 | 'postal_code' => 'T1C1Z9', 67 | 'country' => 'CAN', 68 | 'phone' => '1-403-504-5496', 69 | 'email' => 'test@test.test', 70 | 'type' => 'residential' 71 | ); 72 | 73 | $payload = array ( 74 | 'is_document' => false, 75 | 'return_shipment' => false, 76 | 'paper_size' => 'default', 77 | 'service_type' => 'hong-kong-post_air_parcel', 78 | 'customs' => array ( 79 | 'billing' => array ( 80 | 'paid_by' => 'shipper', 81 | 'method' => array ( 82 | 'account_number' => '950000002', 83 | 'type' => 'account', 84 | ), 85 | ), 86 | 'purpose' => 'gift' 87 | ), 88 | 'shipper_account' => 89 | array ( 90 | 'id' => $shipper, 91 | ), 92 | 'shipment' => array ( 93 | 'parcels' => array ( 94 | 0 => $parcel 95 | ), 96 | 'ship_from' => $sender, 97 | 'ship_to' => $receiver 98 | ), 99 | ); 100 | 101 | try { 102 | $api = new Postmen($key, $region); 103 | $result = $api->create('labels', $payload); 104 | echo "RESULT:\n"; 105 | print_r($result); 106 | } catch (exception $e) { 107 | echo "ERROR:\n"; 108 | echo $e->getCode() . "\n"; // error code 109 | echo $e->getMessage() . "\n"; // error message 110 | print_r($e->getDetails()); // error details 111 | } 112 | ?> 113 | -------------------------------------------------------------------------------- /src/Postmen/Postmen.php: -------------------------------------------------------------------------------- 1 | _version = "1.0.0"; 38 | $this->_api_key = $api_key; 39 | $this->_config = array(); 40 | $this->_config['endpoint'] = "https://$region-api.postmen.com"; 41 | $this->_config['retry'] = true; 42 | $this->_config['rate'] = true; 43 | $this->_config['array'] = false; 44 | $this->_config['raw'] = false; 45 | $this->_config['safe'] = false; 46 | $this->_config['proxy'] = array(); 47 | $this->_config = $this->mergeArray($config); 48 | // set attributes concerning ratelimiting and auto-retry 49 | $this->_delay = 1; 50 | $this->_retries = 0; 51 | $this->_max_retries = 5; 52 | $this->_calls_left = NULL; 53 | } 54 | 55 | public function buildCurlParams($method, $path, $config = array()) { 56 | $parameters = $this->mergeArray($config); 57 | if (!isset($parameters['body'])) { 58 | $parameters['body'] = ''; 59 | } else if (!is_string($parameters['body'])) { 60 | if (count($parameters['body']) == 0) { 61 | $parameters['body'] = ''; 62 | } else { 63 | $parameters['body'] = json_encode($parameters['body']); 64 | } 65 | } 66 | $headers = array( 67 | "content-type: application/json", 68 | "postmen-api-key: $this->_api_key", 69 | "x-postmen-agent: php-sdk-$this->_version" 70 | ); 71 | $query = NULL; 72 | if (isset($parameters['query'])) { 73 | $query = $parameters['query']; 74 | } 75 | $url = $this->generateURL($parameters['endpoint'], $path, $method, $query); 76 | $curl_params = array( 77 | CURLOPT_RETURNTRANSFER => true, 78 | CURLOPT_URL => $url, 79 | CURLOPT_CUSTOMREQUEST => $method, 80 | CURLOPT_HTTPHEADER => $headers, 81 | CURLOPT_HEADER => true 82 | ); 83 | $proxy = $parameters['proxy']; 84 | if (count($proxy) > 0) { 85 | $curl_params[CURLOPT_PROXY] = $proxy['host']; 86 | if (isset($proxy['username'])) { 87 | $auth = $proxy['username'] . ':' . $proxy['password']; 88 | $curl_params[CURLOPT_PROXYUSERPWD] = $auth; 89 | } 90 | if (isset($proxy['port'])) { 91 | $curl_params[CURLOPT_PROXYPORT] = $proxy['port']; 92 | } 93 | $curl_params[CURLOPT_FOLLOWLOCATION] = true; 94 | } 95 | if ($method != 'GET') { 96 | $curl_params[CURLOPT_POSTFIELDS] = $parameters['body']; 97 | } 98 | return $curl_params; 99 | } 100 | 101 | public function call($method, $path, $config = array()) { 102 | $this->_retries += 1; 103 | $parameters = $this->mergeArray($config); 104 | if (!isset($method)) { 105 | $method = $parameters['method']; 106 | } else { 107 | $parameters['method'] = $method; 108 | } 109 | if (!isset($path)) { 110 | $path = $parameters['path']; 111 | } else { 112 | $parameters['path'] = $path; 113 | } 114 | $retry = $parameters['retry']; 115 | $raw = $parameters['raw']; 116 | $safe = $parameters['safe']; 117 | $curl = curl_init(); 118 | $curl_params = $this->buildCurlParams($method, $path, $parameters); 119 | curl_setopt_array($curl, $curl_params); 120 | // make call 121 | $response = curl_exec($curl); 122 | $err = curl_error($curl); 123 | $header_size = curl_getinfo($curl, CURLINFO_HEADER_SIZE); 124 | curl_close($curl); 125 | // convert headers string to an array 126 | $response_headers = substr($response, 0, $header_size); 127 | $response_body = substr($response, $header_size); 128 | $response_headers_array = array(); 129 | foreach (explode("\r\n", $response_headers) as $line) { 130 | list($key, $value) = array_pad(explode(': ', $line, 2), 2, null); 131 | $response_headers_array[$key] = $value; 132 | } 133 | $headers_date = $response_headers_array['Date']; 134 | $calls_left = 0; 135 | if (isset($response_headers_array['X-RateLimit-Remaining'])) { 136 | $calls_left = (int)$response_headers_array['X-RateLimit-Remaining']; 137 | } 138 | $reset = 0; 139 | if (isset($response_headers_array['X-RateLimit-Reset'])) { 140 | $reset = (int)(((int)$response_headers_array['X-RateLimit-Reset']) / 1000); 141 | } 142 | // convert headers date to timestamp, please refer to 143 | // https://tools.ietf.org/html/rfc7231#section-7.1.1.1 144 | $date = new \DateTime($headers_date, new \DateTimeZone('GMT')); 145 | $now = (int) $date->format('U'); 146 | // process the response 147 | $parameters['now'] = $now; 148 | $parameters['reset'] = $reset; 149 | if ($err) { 150 | $error = new PostmenException("failed to request: $err" , 100, true, array()); 151 | if ($safe) { 152 | $this->_error = $error; 153 | return undefined; 154 | } else { 155 | throw $error; 156 | } 157 | } 158 | return $this->processCurlResponse($response_body, $parameters); 159 | } 160 | 161 | public function processCurlResponse($response, $parameters) { 162 | $parsed = json_decode($response); 163 | if ($parsed) { 164 | if($parameters['raw']) { 165 | return $response; 166 | } 167 | return $this->handle($parsed, $parameters); 168 | } else { 169 | $err_message = 'Something went wrong on Postmen\'s end'; 170 | $err_code = 500; 171 | $err_retryable = false; 172 | $err_details = array(); 173 | return $this->handleError($err_message, $err_code, $err_retryable, $err_details, $parameters); 174 | } 175 | } 176 | 177 | public function handleError($err_message, $err_code, $err_retryable, $err_details, $parameters) { 178 | $error = new PostmenException($err_message, $err_code, $err_retryable, $err_details); 179 | if ($parameters['safe']) { 180 | $this->_error = $error; 181 | } else { 182 | throw $error; 183 | } 184 | return NULL; 185 | } 186 | 187 | public function handle($parsed, $parameters) { 188 | if ($parsed->meta->code != 200) { 189 | $err_code = 0; 190 | $err_message = 'Postmen server side error occured'; 191 | $err_details = array(); 192 | $err_retryable = false; 193 | if (isset($parsed->meta->code)) { 194 | $err_code = $parsed->meta->code; 195 | } 196 | if (isset($parsed->meta->message)) { 197 | $err_message = $parsed->meta->message; 198 | } 199 | if (isset($parsed->meta->details)) { 200 | $err_details = $parsed->meta->details; 201 | } 202 | if (isset($parsed->meta->retryable)) { 203 | $err_retryable = $parsed->meta->retryable; 204 | } 205 | // apply rate limiting if error 429 occurs 206 | if ($parameters['rate'] && $err_code === 429) { 207 | $delay = $parameters['reset'] - $parameters['now']; 208 | if ($delay > 0) { 209 | sleep($delay); 210 | } 211 | return $this->call(NULL, NULL, $parameters); 212 | } 213 | // apply automatic retry if error is retry-able 214 | if ($parameters['retry'] && $err_retryable) { 215 | $retried = $this->handleRetry($parameters); 216 | if ($retried !== NULL) { 217 | return $retried; 218 | } 219 | } 220 | return $this->handleError($err_message, $err_code, $err_retryable, $err_details, $parameters); 221 | } else { 222 | if ($parameters['array']) { 223 | $parsed_array = json_decode(json_encode($parsed), true); 224 | return $parsed_array['data']; 225 | } else { 226 | return $parsed->data; 227 | } 228 | } 229 | } 230 | 231 | /** takes an associative array $config as argument 232 | * returns merged array with local $this->_config 233 | * values from $config are prioritary 234 | */ 235 | public function mergeArray($config) { 236 | $parameters = $this->_config; 237 | foreach ($config as $key => $value) { 238 | $parameters[$key] = $value; 239 | } 240 | return $parameters; 241 | } 242 | 243 | // allow query as a string 244 | public function generateURL($url, $path, $method, $query) { 245 | if ($method == 'GET') { 246 | if (is_string($query)) { 247 | if (strlen($query) > 0) { 248 | if ($query[0] == '?') { 249 | return $url . $path . $query; 250 | } else { 251 | return $url . $path . '?' . $query; 252 | } 253 | } 254 | } 255 | if (isset($query)) { 256 | $qr = http_build_query($query); 257 | if (strlen($qr) > 0) { 258 | return $url . $path . '?' . $qr; 259 | } 260 | } 261 | } 262 | return $url . $path; 263 | } 264 | 265 | public function handleRetry($parameters) { 266 | if ($this->_retries < $this->_max_retries) { 267 | sleep($this->_delay); 268 | $this->_delay = $this->_delay * 2; 269 | return $this->call(NULL, NULL, $parameters); 270 | } else { 271 | $this->_retries = 0; 272 | $this->_delay = 1; 273 | return NULL; 274 | } 275 | } 276 | 277 | public function callGET($path, $query = array(), $config = array()) { 278 | $config['query'] = $query; 279 | return $this->call('GET', $path, $config); 280 | } 281 | 282 | public function callPOST($path, $body = array(), $config = array()) { 283 | $config['body'] = $body; 284 | return $this->call('POST', $path, $config); 285 | } 286 | 287 | public function callPUT($path, $body = array(), $config = array()) { 288 | $config['body'] = $body; 289 | return $this->call('PUT', $path, $config); 290 | } 291 | 292 | public function callDELETE($path, $body = array(), $config = array()) { 293 | $config['body'] = $body; 294 | return $this->call('DELETE', $path, $config); 295 | } 296 | 297 | public function get($resource, $id = NULL, $query = array(), $config = array()) { 298 | if ($id !== NULL) { 299 | return $this->callGET("/v3/$resource/$id", $query, $config); 300 | } else { 301 | return $this->callGET("/v3/$resource", $query, $config); 302 | } 303 | } 304 | 305 | public function create($resource, $payload, $config = array()) { 306 | if (!is_string($payload)) { 307 | $payload['async'] = false; 308 | } 309 | return $this->callPOST("/v3/$resource", $payload, $config); 310 | } 311 | 312 | public function getError() { 313 | return $this->_error; 314 | } 315 | } 316 | ?> 317 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | PHP SDK for [Postmen API](https://docs.postmen.com/). 3 | For problems and suggestions please open [GitHub issue](https://github.com/postmen/postmen-sdk-php/issues) 4 | 5 | 6 | 7 | **Table of Contents** 8 | 9 | - [Installation](#installation) 10 | - [Requirements](#requirements) 11 | - [Manual installation](#manual-installation) 12 | - [Using Composer](#using-composer) 13 | - [Quick Start](#quick-start) 14 | - [class Postmen](#class-postmen) 15 | - [Postmen($api_key, $region, $config = array())](#postmenapi_key-region-config--array) 16 | - [create($resource, $payload, $config = array())](#createresource-payload-config--array) 17 | - [get($resource, $id = NULL, $query = array(), $config = array())](#getresource-id--null-query--array-config--array) 18 | - [getError()](#geterror) 19 | - [callGET($path, $query = array(), $options = array())](#callgetpath-query--array-options--array) 20 | - [callPOST($path, $body = array(), $options = array())](#callpostpath-body--array-options--array) 21 | - [callPUT($path, $body = array(), $options = array())](#callputpath-body--array-options--array) 22 | - [callDELETE($path, $body = array(), $options = array())](#calldeletepath-body--array-options--array) 23 | - [Error Handling](#error-handling) 24 | - [class PostmenException](#class-postmenexception) 25 | - [Automatic retry on retryable error](#automatic-retry-on-retryable-error) 26 | - [Examples](#examples) 27 | - [Full list](#full-list) 28 | - [How to run](#how-to-run) 29 | - [Navigation table](#navigation-table) 30 | - [Testing](#testing) 31 | - [License](#license) 32 | - [Contributors](#contributors) 33 | 34 | 35 | 36 | ## Installation 37 | 38 | #### Requirements 39 | 40 | PHP version `>= 5.3` is required. For SDK development PHP `5.6` is required (to run automated tests). 41 | 42 | Tested on PHP 5.3, 5.4, 5.5, 5.6. 43 | 44 | #### Manual installation 45 | 46 | - Download the source code. 47 | - Reference API class. 48 | ```php 49 | require('.../path/to/repository/src/Postmen/Postmen.php'); 50 | ``` 51 | 52 | #### Using Composer 53 | 54 | - If you don't have Composer, [download and install](https://getcomposer.org/download/) 55 | - You have 2 options to download the Postmen PHP SDK 56 | 57 | Run the following command to require Postmen PHP SDK 58 | ``` 59 | composer require postmen/sdk-php 60 | ``` 61 | 62 | OR download the sorce code and run 63 | ``` 64 | composer install 65 | ``` 66 | 67 | - Autoload the `postmen-php-sdk` package. 68 | ```php 69 | $loader = require __DIR__ . '/vendor/autoload.php'; 70 | ``` 71 | 72 | ## Quick Start 73 | 74 | In order to get API key and choose a region refer to the [documentation](https://docs.postmen.com/overview.html). 75 | 76 | ```php 77 | use Postmen\Postmen; 78 | 79 | $api_key = 'YOUR_API_KEY'; 80 | $region = 'sandbox'; 81 | 82 | // create Postmen API handler object 83 | 84 | $api = new Postmen($api_key, $region); 85 | 86 | try { 87 | // as an example we request all the labels 88 | 89 | $result = $api->get('labels'); 90 | echo "RESULT:\n"; 91 | print_r($result); 92 | } catch (exception $e) { 93 | // if error occurs we can access all 94 | // the details in following way 95 | 96 | echo "ERROR:\n"; 97 | echo $e->getCode() . "\n"; // error code 98 | echo $e->getMessage() . "\n"; // error message 99 | print_r($e->getDetails()); // details 100 | } 101 | ``` 102 | 103 | ## class Postmen 104 | 105 | #### Postmen($api_key, $region, $config = array()) 106 | 107 | Initiate Postmen SDK object. 108 | In order to get API key and choose a region refer to the [documentation](https://docs.postmen.com/overview.html). 109 | 110 | | Argument | Required | Type | Default | Description | 111 | |--------------------------------|----------------------------------------|---------|-----------|---------------------------------------------------| 112 | | `$api_key` | YES | String | N / A | API key | 113 | | `$region` | NO if `$config['endpoint']` is set | String | N / A | API region (`sandbox`, `production`) | 114 | | `$config` | NO | Array | `array()` | Options | 115 | | `$config['endpoint']` | — | String | N / A | Custom URL API endpoint | 116 | | `$config['retry']` | — | Boolean | `TRUE` | Automatic retry on retryable errors | 117 | | `$config['rate']` | — | Boolean | `TRUE` | Wait before API call if rate limit exceeded or retry on 429 error | 118 | | `$config['safe']` | — | Boolean | `FALSE` | Suppress exceptions on errors, NULL would be returned instead, check [Error Handling](#error-handling) | 119 | | `$config['raw']` | — | Boolean | `FALSE` | To return API response as a raw string | 120 | | `$config['array']` | — | Boolean | `FALSE` | To return API response as an associative array | 121 | | `$config['proxy']` | — | Array | `array()` | Proxy credentials | 122 | | `$config['proxy']['host']` | YES if `$config['proxy']` is not empty | String | N / A | Proxy host | 123 | | `$config['proxy']['port']` | NO | Integer | N / A | Proxy port | 124 | | `$config['proxy']['username']` | NO | String | N / A | Proxy user name | 125 | | `$config['proxy']['password']` | NO | String | N / A | Proxy password | 126 | 127 | #### create($resource, $payload, $config = array()) 128 | 129 | Creates API `$resource` object, returns new object payload as `Array`. 130 | 131 | | Argument | Required | Type | Default | Description | 132 | |-------------|----------|-----------------|-----------|-------------------------------------------------------| 133 | | `$resource` | YES | String | N / A | Postmen API resourse ('rates', 'labels', 'manifests') | 134 | | `$payload` | YES | Array or String | N / A | Payload according to API | 135 | | `$config` | NO | Array | `array()` | Override constructor [config](#postmenapi_key-region-config--array) | 136 | 137 | **API Docs:** 138 | - [POST /rates](https://docs.postmen.com/#rates-calculate-rates) 139 | - [POST /labels](https://docs.postmen.com/#labels-create-a-label) 140 | - [POST /manifests](https://docs.postmen.com/#manifests-create-a-manifest) 141 | - [POST /cancel-labels](https://docs.postmen.com/#cancel-labels-cancel-a-label) 142 | 143 | **Examples:** 144 | - [rates_create.php](https://github.com/postmen/postmen-sdk-php/blob/master/examples/rates_create.php) 145 | - [labels_create.php](https://github.com/postmen/postmen-sdk-php/blob/master/examples/labels_create.php) 146 | - [manifests_create.php](https://github.com/postmen/postmen-sdk-php/blob/master/examples/manifests_create.php) 147 | - [cancel_labels_create.php](https://github.com/postmen/postmen-sdk-php/blob/master/examples/cancel_labels_create.php) 148 | 149 | #### get($resource, $id = NULL, $query = array(), $config = array()) 150 | 151 | Gets API `$resource` objects (list or a single objects). 152 | 153 | | Argument | Required | Type | Default | Description | 154 | |-------------|----------|-----------------|-----------|-------------------------------------------------------| 155 | | `$resource` | YES | String | N / A | Postmen API resourse ('rates', 'labels', 'manifests') | 156 | | `$id` | NO | String | `NULL` | Object ID, if not set 'list all' API method is used | 157 | | `$query` | NO | Array or String | `array()` | Optional parameters for 'list all' API method | 158 | | `$config` | NO | Array | `array()` | Override constructor [config](#postmenapi_key-region-config--array) | 159 | 160 | **API Docs:** 161 | - [GET /rates](https://docs.postmen.com/#rates-list-all-rates) 162 | - [GET /rates/:id](https://docs.postmen.com/#rates-retrieve-rates) 163 | - [GET /labels](https://docs.postmen.com/#labels-list-all-labels) 164 | - [GET /labels/:id](https://docs.postmen.com/#labels-retrieve-a-label) 165 | - [GET /manifests](https://docs.postmen.com/#manifests-list-all-manifests) 166 | - [GET /manifests/:id](https://docs.postmen.com/#manifests-retrieve-a-manifest) 167 | - [GET /cancel-labels](https://docs.postmen.com/#cancel-labels-list-all-cancel-labels) 168 | - [GET /cancel-labels/:id](https://docs.postmen.com/#cancel-labels-retrieve-a-cancel-label) 169 | 170 | **Examples:** 171 | - [rates_retrieve.php](https://github.com/postmen/postmen-sdk-php/blob/master/examples/rates_retrieve.php) 172 | - [labels_retrieve.php](https://github.com/postmen/postmen-sdk-php/blob/master/examples/labels_retrieve.php) 173 | - [manifests_retrieve.php](https://github.com/postmen/postmen-sdk-php/blob/master/examples/manifests_retrieve.php) 174 | - [cancel_labels_retrieve.php](https://github.com/postmen/postmen-sdk-php/blob/master/examples/cancel_labels_retrieve.php) 175 | 176 | #### getError() 177 | 178 | Returns SDK error, [PostmenException type](#class-postmenexception) if `$conifg['safe'] = TRUE;` was set. 179 | 180 | Check [Error Handling](#error-handling) for details. 181 | 182 | #### callGET($path, $query = array(), $options = array()) 183 | 184 | Performs HTTP GET request, returns an `Array` object holding API response. 185 | 186 | | Argument | Required | Type | Default | Description | 187 | |------------|----------|-----------------|-----------|---------------------------------------------------| 188 | | `$path` | YES | String | N / A | URL path (e.g. 'v3/labels' for `https://sandbox-api.postmen.com/v3/labels` ) | 189 | | `$query` | NO | Array or String | `array()` | HTTP GET request query string | 190 | | `$config` | NO | Array | `array()` | Override constructor [config](#postmenapi_key-region-config--array) | 191 | 192 | #### callPOST($path, $body = array(), $options = array()) 193 | #### callPUT($path, $body = array(), $options = array()) 194 | #### callDELETE($path, $body = array(), $options = array()) 195 | 196 | Performs HTTP POST/PUT/DELETE request, returns an `Array` object holding API response. 197 | 198 | | Argument | Required | Type | Default | Description | 199 | |------------|----------|-----------------|-----------|---------------------------------------------------| 200 | | `$path` | YES | String | N / A | URL path (e.g. 'v3/labels' for `https://sandbox-api.postmen.com/v3/labels` ) | 201 | | `$body` | YES | Array or String | N / A | HTTP POST/PUT/DELETE request body | 202 | | `$config` | NO | Array | `array()` | Override constructor [config](#postmenapi_key-region-config--array) | 203 | 204 | ## Error Handling 205 | 206 | Particular error details are listed in the [documentation](https://docs.postmen.com/errors.html). 207 | 208 | All SDK methods may throw an exception described below. 209 | 210 | #### class PostmenException 211 | | Method | Return type | Description | 212 | |---------------|-------------|------------------------------------------------------------------------------| 213 | | getCode() | Integer | Error code | 214 | | isRetryable() | Boolean | Indicates if error is retryable | 215 | | getMessage() | String | Error message (e.g. `The request was invalid or cannot be otherwise served`) | 216 | | getDetails() | Array | Error details (e.g. `Destination country must be RUS or KAZ`) | 217 | 218 | In case of `$conifg['safe'] = TRUE;` SDK would not throw exceptions, [getError()](#geterror) must be used instead. 219 | 220 | Example: [error.php](https://github.com/postmen/postmen-sdk-php/blob/master/examples/error.php) 221 | 222 | #### Automatic retry on retryable error 223 | 224 | If API error is retryable, SDK will wait for delay and retry. Delay starts from 1 second. After each try, delay time is doubled. Maximum number of attempts is 5. 225 | 226 | To disable this option set `$conifg['retry'] = FALSE;` 227 | 228 | ## Examples 229 | 230 | #### Full list 231 | All examples avalible listed in the table below. 232 | 233 | | File | Description | 234 | |--------------------------------------------------------------------------------------------------------------------------|------------------------------------| 235 | | [rates_create.php](https://github.com/postmen/postmen-sdk-php/blob/master/examples/rates_create.php) | `rates` object creation | 236 | | [rates_retrieve.php](https://github.com/postmen/postmen-sdk-php/blob/master/examples/rates_retrieve.php) | `rates` object(s) retrieve | 237 | | [labels_create.php](https://github.com/postmen/postmen-sdk-php/blob/master/examples/labels_create.php) | `labels` object creation | 238 | | [labels_retrieve.php](https://github.com/postmen/postmen-sdk-php/blob/master/examples/labels_retrieve.php) | `labels` object(s) retrieve | 239 | | [manifests_create.php](https://github.com/postmen/postmen-sdk-php/blob/master/examples/manifests_create.php) | `manifests` object creation | 240 | | [manifests_retrieve.php](https://github.com/postmen/postmen-sdk-php/blob/master/examples/manifests_retrieve.php) | `manifests` object(s) retrieve | 241 | | [cancel_labels_create.php](https://github.com/postmen/postmen-sdk-php/blob/master/examples/cancel_labels_create.php) | `cancel-labels` object creation | 242 | | [cancel_labels_retrieve.php](https://github.com/postmen/postmen-sdk-php/blob/master/examples/cancel_labels_retrieve.php) | `cancel-labels` object(s) retrieve | 243 | | [proxy.php](https://github.com/postmen/postmen-sdk-php/blob/master/examples/proxy.php) | Proxy usage | 244 | | [error.php](https://github.com/postmen/postmen-sdk-php/blob/master/examples/error.php) | Avalible ways to catch/get errors | 245 | | [response.php](https://github.com/postmen/postmen-sdk-php/blob/master/examples/response.php) | Avalible output types | 246 | 247 | #### How to run 248 | 249 | Download the source code, go to `examples` directory. 250 | 251 | Put your API key and region to [credentials.php](https://github.com/postmen/postmen-sdk-php/blob/master/examples/credentials.php) 252 | 253 | Check the file you want to run before run. Some require you to set additional variables. 254 | 255 | #### Navigation table 256 | 257 | For each API method SDK provides PHP wrapper. Use the table below to find SDK method and example that match your need. 258 | 259 |
| Model \ Action | 262 |create | 263 |get all | 264 |get by id | 265 |
|---|---|---|---|
| rates | 268 |
269 | .create('rates', $payload, $opt)
270 | |
271 |
272 | .get('rates', NULL, NULL, $opt)
273 | |
274 |
275 | .get('rates', $id, NULL, $opt)
276 | |
277 |
| labels | 280 |
281 | .create('labels', $payload, $opt)
282 | |
283 |
284 | .get('labels', NULL, NULL, $opt)
285 | |
286 |
287 | .get('labels', $id, NULL, $opt)
288 | |
289 |
| manifest | 292 |
293 | .create('manifest', $payload, $opt)
294 | |
295 |
296 | .get('manifest', NULL, NULL, $opt)
297 | |
298 |
299 | .get('manifest', $id, NULL, $opt)
300 | |
301 |
| cancel-labels | 304 |
305 | .create('cancel-labels', $payload, $opt)
306 | |
307 |
308 | .get('cancel-labels', NULL, NULL, $opt)
309 | |
310 |
311 | .get('cancel-labels', $id, NULL, $opt)
312 | |
313 |