1 | <?php |
||||||
2 | |||||||
3 | namespace Uon; |
||||||
4 | |||||||
5 | use GuzzleHttp\Client as HttpClient; |
||||||
6 | use GuzzleHttp\Exception\GuzzleException; |
||||||
7 | use GuzzleHttp\RequestOptions; |
||||||
8 | use Psr\Http\Message\ResponseInterface; |
||||||
9 | use Uon\Exceptions\UonEmptyResponseException; |
||||||
10 | use Uon\Exceptions\UonHttpClientException; |
||||||
11 | use Uon\Exceptions\UonTooManyRequests; |
||||||
12 | use Uon\Interfaces\ClientInterface; |
||||||
13 | use function str_replace; |
||||||
14 | use function strtoupper; |
||||||
15 | use function ucwords; |
||||||
16 | |||||||
17 | /** |
||||||
18 | * @author Paul Rock <[email protected]> |
||||||
19 | * @link http://drteam.rocks |
||||||
20 | * @license MIT |
||||||
21 | * @package Uon |
||||||
22 | * |
||||||
23 | * @property \Uon\Endpoints\Avia $avia Aero transfer |
||||||
24 | * @property \Uon\Endpoints\Bcard $bcard Bonus cards |
||||||
25 | * @property \Uon\Endpoints\CallHistory $callHistory History of calls |
||||||
26 | * @property \Uon\Endpoints\Cash $cash Money operations |
||||||
27 | * @property \Uon\Endpoints\Catalog $catalog Catalog of products |
||||||
28 | * @property \Uon\Endpoints\Chat $chat For work with chat messages |
||||||
29 | * @property \Uon\Endpoints\Cities $cities Cities of countries |
||||||
30 | * @property \Uon\Endpoints\Countries $countries Work with countries |
||||||
31 | * @property \Uon\Endpoints\Currencies $currencies Work with currencies |
||||||
32 | * @property \Uon\Endpoints\ExtendedFields $extendedFields For manipulation with extended fields |
||||||
33 | * @property \Uon\Endpoints\Hotels $hotels Hotels methods |
||||||
34 | * @property \Uon\Endpoints\Leads $leads Details about clients |
||||||
35 | * @property \Uon\Endpoints\Mails $mails For work with emails |
||||||
36 | * @property \Uon\Endpoints\Managers $managers Get access to list of managers (sale operators) |
||||||
37 | * @property \Uon\Endpoints\Misc $misc Optional single methods |
||||||
38 | * @property \Uon\Endpoints\Notifications $notifications For creating new notifications for managers |
||||||
39 | * @property \Uon\Endpoints\Nutrition $nutrition Some methods about eat |
||||||
40 | * @property \Uon\Endpoints\Offices $offices Get access to list of all offices |
||||||
41 | * @property \Uon\Endpoints\Payments $payments Payment methods |
||||||
42 | * @property \Uon\Endpoints\ReasonsDeny $reasonsDeny List of all deny reasons |
||||||
43 | * @property \Uon\Endpoints\Reminders $reminders Work with reminders |
||||||
44 | * @property \Uon\Endpoints\Requests $requests New requests from people |
||||||
45 | * @property \Uon\Endpoints\Services $services All available services |
||||||
46 | * @property \Uon\Endpoints\Sources $sources All available sources |
||||||
47 | * @property \Uon\Endpoints\Statuses $statuses Request statuses |
||||||
48 | * @property \Uon\Endpoints\Suppliers $suppliers External companies |
||||||
49 | * @property \Uon\Endpoints\Users $users For work with users |
||||||
50 | * @property \Uon\Endpoints\Visa $visa For work with visa statuses |
||||||
51 | * @property \Uon\Endpoints\Webhooks $webhooks Webhooks management |
||||||
52 | */ |
||||||
53 | class Client implements ClientInterface |
||||||
54 | { |
||||||
55 | /** |
||||||
56 | * @var string |
||||||
57 | */ |
||||||
58 | protected $namespace = __NAMESPACE__ . '\\Endpoints'; |
||||||
59 | |||||||
60 | /** |
||||||
61 | * Initial state of some variables |
||||||
62 | * |
||||||
63 | * @var null|\GuzzleHttp\Client |
||||||
64 | */ |
||||||
65 | public $client; |
||||||
66 | |||||||
67 | /** |
||||||
68 | * Object of main config |
||||||
69 | * |
||||||
70 | * @var \Uon\Config |
||||||
71 | 2 | */ |
|||||
72 | public $config; |
||||||
73 | |||||||
74 | 2 | /** |
|||||
75 | * Type of query |
||||||
76 | * |
||||||
77 | 2 | * @var string |
|||||
78 | */ |
||||||
79 | protected $type; |
||||||
80 | |||||||
81 | /** |
||||||
82 | 2 | * Endpoint of query |
|||||
83 | * |
||||||
84 | * @var string |
||||||
85 | */ |
||||||
86 | protected $endpoint; |
||||||
87 | 2 | ||||||
88 | /** |
||||||
89 | * Parameters of query |
||||||
90 | * |
||||||
91 | * @var array |
||||||
92 | 2 | */ |
|||||
93 | protected $params = []; |
||||||
94 | |||||||
95 | 2 | /** |
|||||
96 | 2 | * @var array |
|||||
97 | */ |
||||||
98 | protected static $variables = []; |
||||||
99 | |||||||
100 | /** |
||||||
101 | * API constructor. |
||||||
102 | * |
||||||
103 | * @param array|\Uon\Config $config |
||||||
104 | * @param bool $init |
||||||
105 | * |
||||||
106 | * @throws \ErrorException |
||||||
107 | 61 | */ |
|||||
108 | public function __construct($config, bool $init = true) |
||||||
109 | 61 | { |
|||||
110 | if (!$config instanceof Config) { |
||||||
111 | $config = new Config($config); |
||||||
112 | 61 | } |
|||||
113 | 61 | ||||||
114 | 61 | // Save config into local variable |
|||||
115 | $this->config = $config; |
||||||
116 | |||||||
117 | 61 | // Init if need |
|||||
118 | if ($init) { |
||||||
119 | $this->client = $this->initClient($config->guzzle()); |
||||||
120 | 61 | } |
|||||
121 | 60 | } |
|||||
122 | |||||||
123 | /** |
||||||
124 | * Get current client instance |
||||||
125 | 1 | * |
|||||
126 | 1 | * @return null|\GuzzleHttp\Client |
|||||
127 | */ |
||||||
128 | public function getClient(): ?HttpClient |
||||||
129 | 1 | { |
|||||
130 | return $this->client; |
||||||
131 | } |
||||||
132 | |||||||
133 | /** |
||||||
134 | * Store the client object |
||||||
135 | * |
||||||
136 | * @param array $configs |
||||||
137 | * |
||||||
138 | * @return \GuzzleHttp\Client |
||||||
139 | */ |
||||||
140 | public function initClient(array $configs = []): HttpClient |
||||||
141 | 61 | { |
|||||
142 | return new HttpClient($configs); |
||||||
143 | } |
||||||
144 | 61 | ||||||
145 | /** |
||||||
146 | * Convert underscore_strings to camelCase (medial capitals). |
||||||
147 | 61 | * |
|||||
148 | * @param string $str |
||||||
149 | * |
||||||
150 | * @return string |
||||||
151 | 61 | */ |
|||||
152 | private function snakeToPascal(string $str): string |
||||||
153 | { |
||||||
154 | // Remove underscores, capitalize words, squash, lowercase first. |
||||||
155 | 61 | return str_replace(' ', '', ucwords(str_replace('_', ' ', $str))); |
|||||
156 | 61 | } |
|||||
157 | 1 | ||||||
158 | 60 | /** |
|||||
159 | 60 | * Magic method required for call of another classes |
|||||
160 | 60 | * |
|||||
161 | 61 | * @param string $name |
|||||
162 | * |
||||||
163 | * @return bool|object |
||||||
164 | */ |
||||||
165 | public function __get(string $name) |
||||||
166 | { |
||||||
167 | if (isset(self::$variables[$name])) { |
||||||
168 | return self::$variables[$name]; |
||||||
169 | } |
||||||
170 | |||||||
171 | // Set class name as namespace |
||||||
172 | $class = $this->namespace . '\\' . $this->snakeToPascal($name); |
||||||
173 | |||||||
174 | // Try to create object by name |
||||||
175 | return new $class($this->config); |
||||||
176 | } |
||||||
177 | |||||||
178 | /** |
||||||
179 | * Check if class is exist in folder |
||||||
180 | * |
||||||
181 | * @param string $name |
||||||
182 | * |
||||||
183 | * @return bool |
||||||
184 | */ |
||||||
185 | public function __isset(string $name): bool |
||||||
186 | { |
||||||
187 | return isset(self::$variables[$name]); |
||||||
188 | } |
||||||
189 | |||||||
190 | /** |
||||||
191 | * Ordinary dummy setter, it should be ignored (added to PSR reasons) |
||||||
192 | * |
||||||
193 | * @param string $name |
||||||
194 | * @param mixed $value |
||||||
195 | */ |
||||||
196 | public function __set(string $name, $value) |
||||||
197 | { |
||||||
198 | self::$variables[$name] = $value; |
||||||
199 | } |
||||||
200 | |||||||
201 | /** |
||||||
202 | * Request executor with timeout and repeat tries |
||||||
203 | * |
||||||
204 | * @param string $type Request method |
||||||
205 | * @param string $url endpoint url |
||||||
206 | * @param array $params List of parameters |
||||||
207 | * |
||||||
208 | * @return \Psr\Http\Message\ResponseInterface|null |
||||||
209 | * |
||||||
210 | * @throws \Uon\Exceptions\UonTooManyRequests |
||||||
211 | * @throws \Uon\Exceptions\UonParameterNotSetException |
||||||
212 | * @throws \Uon\Exceptions\UonHttpClientException |
||||||
213 | */ |
||||||
214 | private function repeatRequest(string $type, string $url, array $params = []): ?ResponseInterface |
||||||
215 | { |
||||||
216 | $type = strtoupper($type); |
||||||
217 | |||||||
218 | for ($i = 1; $i <= $this->config->get('tries'); $i++) { |
||||||
219 | |||||||
220 | $requestEndpoint = |
||||||
221 | $this->config->get('base_uri') . '/' |
||||||
222 | . $this->config->get('token') . '/' |
||||||
223 | . $url . '.' . $this->config->get('format'); |
||||||
224 | |||||||
225 | if ($this->config->get('verbose')) { |
||||||
226 | var_dump('[' . $type . '] endpoint:' . $requestEndpoint . ' parameters:' . json_encode($params)); |
||||||
0 ignored issues
–
show
Security
Debugging Code
introduced
by
![]() |
|||||||
227 | } |
||||||
228 | |||||||
229 | try { |
||||||
230 | |||||||
231 | if (empty($params)) { |
||||||
232 | // Execute the request to server |
||||||
233 | $result = $this->client->request($type, $requestEndpoint); |
||||||
0 ignored issues
–
show
The method
request() does not exist on null .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||||||
234 | } else { |
||||||
235 | // Execute the request to server |
||||||
236 | $result = $this->client->request($type, $requestEndpoint, [RequestOptions::FORM_PARAMS => $params]); |
||||||
237 | } |
||||||
238 | |||||||
239 | // Check the code status |
||||||
240 | $code = $result->getStatusCode(); |
||||||
241 | |||||||
242 | // If success response from server |
||||||
243 | if ($code === 200 || $code === 201) { |
||||||
244 | return $result; |
||||||
245 | } |
||||||
246 | |||||||
247 | // If not "too many requests", then probably some bug on remote or our side |
||||||
248 | if ($code !== 429) { |
||||||
249 | throw new UonTooManyRequests(); |
||||||
250 | } |
||||||
251 | |||||||
252 | } catch (GuzzleException $exception) { |
||||||
253 | throw new UonHttpClientException($exception); |
||||||
254 | } |
||||||
255 | |||||||
256 | // Waiting in seconds |
||||||
257 | sleep($this->config->get('seconds')); |
||||||
0 ignored issues
–
show
It seems like
$this->config->get('seconds') can also be of type boolean and null and string ; however, parameter $seconds of sleep() does only seem to accept integer , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
258 | } |
||||||
259 | |||||||
260 | // Return false if loop is done but no answer from server |
||||||
261 | return null; |
||||||
262 | } |
||||||
263 | |||||||
264 | /** |
||||||
265 | * Execute request and return response |
||||||
266 | * |
||||||
267 | * @return null|object Array with data or NULL if error |
||||||
268 | * |
||||||
269 | * @throws \Uon\Exceptions\UonEmptyResponseException |
||||||
270 | * @throws \Uon\Exceptions\UonTooManyRequests |
||||||
271 | * @throws \Uon\Exceptions\UonHttpClientException |
||||||
272 | */ |
||||||
273 | public function exec() |
||||||
274 | { |
||||||
275 | return $this->doRequest($this->type, $this->endpoint, $this->params); |
||||||
276 | } |
||||||
277 | |||||||
278 | /** |
||||||
279 | * Execute query and return RAW response from remote API |
||||||
280 | * |
||||||
281 | * @return null|\Psr\Http\Message\ResponseInterface RAW response or NULL if error |
||||||
282 | * |
||||||
283 | * @throws \Uon\Exceptions\UonEmptyResponseException |
||||||
284 | * @throws \Uon\Exceptions\UonTooManyRequests |
||||||
285 | * @throws \Uon\Exceptions\UonHttpClientException |
||||||
286 | */ |
||||||
287 | public function raw(): ?ResponseInterface |
||||||
288 | { |
||||||
289 | return $this->doRequest($this->type, $this->endpoint, $this->params, true); |
||||||
290 | } |
||||||
291 | |||||||
292 | /** |
||||||
293 | * Make the request and analyze the result |
||||||
294 | * |
||||||
295 | * @param string $type Request method |
||||||
296 | * @param string $requestEndpoint Api request endpoint |
||||||
297 | * @param mixed $params List of parameters |
||||||
298 | * @param bool $raw Return data in raw format |
||||||
299 | * |
||||||
300 | * @return null|object|ResponseInterface Array with data, RAW response or NULL if error |
||||||
301 | * |
||||||
302 | * @throws \Uon\Exceptions\UonEmptyResponseException If empty response received from U-On |
||||||
303 | * @throws \Uon\Exceptions\UonTooManyRequests If amount or repeats is more than allowed |
||||||
304 | * @throws \Uon\Exceptions\UonHttpClientException If http exception occurred |
||||||
305 | */ |
||||||
306 | private function doRequest(string $type, string $requestEndpoint, array $params = [], bool $raw = false) |
||||||
307 | { |
||||||
308 | // Execute the request to server |
||||||
309 | $result = $this->repeatRequest($type, $requestEndpoint, $params); |
||||||
310 | |||||||
311 | // If debug then return Guzzle object |
||||||
312 | if ($this->config->get('debug') === true) { |
||||||
313 | return $result; |
||||||
314 | } |
||||||
315 | |||||||
316 | if (null === $result) { |
||||||
317 | throw new UonEmptyResponseException(); |
||||||
318 | } |
||||||
319 | |||||||
320 | // Return RAW result if required |
||||||
321 | if ($raw) { |
||||||
322 | return $result; |
||||||
323 | } |
||||||
324 | |||||||
325 | return json_decode($result->getBody(), false); |
||||||
326 | } |
||||||
327 | |||||||
328 | /** |
||||||
329 | * @since 2.0 |
||||||
330 | * |
||||||
331 | * @return null|object|\Uon\Interfaces\ClientInterface |
||||||
332 | * |
||||||
333 | * @throws \Uon\Exceptions\UonEmptyResponseException |
||||||
334 | * @throws \Uon\Exceptions\UonHttpClientException |
||||||
335 | * @throws \Uon\Exceptions\UonTooManyRequests |
||||||
336 | */ |
||||||
337 | protected function done() |
||||||
338 | { |
||||||
339 | return $this->config->get('auto_exec') ? $this->exec() : $this; |
||||||
340 | } |
||||||
341 | } |
||||||
342 |