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)); |
||||
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
|
|||||
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 |
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.