GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#68)
by
unknown
12:42
created

AbstractList::cleanData()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
dl 0
loc 14
ccs 0
cts 0
cp 0
rs 9.7998
c 0
b 0
f 0
cc 4
nc 2
nop 1
crap 20
1
<?php
2
3
namespace SimaLand\API;
4
5
use GuzzleHttp\Psr7\Response;
6
use SimaLand\API\Rest\Client;
7
use SimaLand\API\Rest\Request;
8
use SimaLand\API\Rest\ResponseException;
9
use GuzzleHttp\Exception\RequestException;
10
11
/**
12
 * Абстрактный класс для загрузки данных сущности.
13
 *
14
 * Класс реализует интерфейс Iterator.
15
 *
16
 * @property $getParams GET параметры запроса.
17
 */
18
abstract class AbstractList extends BaseObject implements \Iterator
19
{
20
    /**
21
     * Кол-во потоков.
22
     *
23
     * @var int
24
     */
25
    public $countThreads = 5;
26
27
    /**
28
     * GET параметр отвечающий за поток.
29
     *
30
     * @var string
31
     */
32
    public $keyThreads = 'page';
33
34
    /**
35
     * Ключ альтернативной пагинации.
36
     *
37
     * @var string
38
     */
39
    public $keyAlternativePagination = 'id-greater-than';
40
41
    /**
42
     * Использовать альтернативную пагинацию.
43
     *
44
     * @var bool
45
     */
46
    public $useAlternativePagination = false;
47
48
    /**
49
     * GET параметры запроса.
50
     *
51
     * @var array
52
     */
53
    protected $_getParams = [];
54
55
    /**
56
     * Кол-во повторов обращение к ресурсу при ошибках.
57
     *
58
     * @var int
59
     */
60
    public $repeatTimeout = 30;
61
62
    /**
63
     * Время в секундак до следующего обращения к ресурсу.
64
     *
65
     * @var int
66
     */
67
    public $repeatCount = 30;
68
69
70
    /**
71
     * SimaLand кдиент для запросов.
72
     *
73
     * @var \SimaLand\API\Rest\Client
74
     */
75
    private $client;
76
77
    /**
78
     * Список запросов.
79
     *
80
     * @var Request[]
81
     */
82
    private $requests = [];
83
84
    /**
85
     * Список данных полученные по API.
86
     *
87
     * @var array
88
     */
89
    private $values = [];
90
91
    /**
92
     * Ключ текущей записи.
93
     *
94
     * @var int
95
     */
96
    private $key;
97
98
    /**
99
     * Текущая запись.
100
     *
101
     * @var mixed
102
     */
103
    private $current;
104
105
    /**
106
     * Массив полей, которые пользователь хочет получить из API.
107
     *
108
     * @var array
109 84
     */
110
    public $fields = [];
111 84
112 84
    /**
113 84
     * @param Client $client
114
     * @param array $options
115
     */
116
    public function __construct(Client $client, array $options = [])
117
    {
118
        $this->client = $client;
119
        parent::__construct($options);
120
    }
121
122
    /**
123
     * Получить наименование сущности.
124
     *
125
     * @return string
126
     */
127
    abstract public function getEntity();
128 6
129
    /**
130 6
     * Добавить get параметры.
131 6
     *
132
     * @param array $params
133
     * @return AbstractList
134
     */
135
    public function addGetParams(array $params)
136
    {
137
        $this->setGetParams(array_merge($this->_getParams, $params));
138
        return $this;
139
    }
140 30
141
    /**
142 30
     * Назначить следующую страницу запросу.
143 18
     *
144 6
     * @param Request $request
145 12
     * @param Record|null $record
146
     */
147 30
    public function assignPage(Request &$request, Record $record = null)
148
    {
149
        if ($this->useAlternativePagination) {
150
            $this->assignAlternativePage($request, $record);
151
        } else {
152
            $this->assignDefaultPage($request);
153
        }
154 12
    }
155
156 12
    /**
157 12
     * Назначить следующую страницу запросу, используя стандартную пагинацию.
158 3
     *
159 1
     * @param Request $request
160 12
     */
161 12
    protected function assignDefaultPage(Request &$request)
162 4
    {
163 12
        $currentPage = 1;
164 12
        if (!is_array($request->getParams)) {
165
            $request->getParams = (array)$request->getParams;
166
        }
167
        if (isset($request->getParams[$this->keyThreads])) {
168
            $currentPage = (int)$request->getParams[$this->keyThreads];
169
        }
170
        $request->getParams[$this->keyThreads] = $currentPage + $this->countThreads;
171
    }
172 18
173
    /**
174 18
     * Назначить следующую страницу запросу, используют альтернативную пагинацию.
175 18
     *
176 18
     * @param Request $request
177 6
     * @param Record|null $record
178 18
     */
179
    protected function assignAlternativePage(Request &$request, Record $record = null)
180
    {
181 18
        $lastId = 0;
182 18
        if ($record && $record->data) {
183
            $lastId = (int)$record->data['id'];
184
        }
185
        if (!is_array($request->getParams)) {
186
            $request->getParams = (array)$request->getParams;
187
        }
188
        $request->getParams[$this->keyAlternativePagination] = $lastId;
189
    }
190 30
191
    /**
192 30
     * Назначить номер потока для запроса.
193 21
     *
194 7
     * @param Request $request
195 9
     * @param int $number
196
     */
197 30
    public function assignThreadsNumber(Request &$request, $number = 0)
198
    {
199
        if ("id-mf" == $this->keyThreads) {
200
            $this->assignMfThreadsNumber($request, $number);
201
        } else {
202
            $this->assignDefaultThreadsNumber($request, $number);
203
        }
204
    }
205 9
206
    /**
207 9
     * Назначить по умолчанию номер потока для запроса.
208 3
     *
209 1
     * @param Request $request
210 9
     * @param int $number
211 9
     */
212 3
    public function assignDefaultThreadsNumber(Request &$request, $number = 0)
213 9
    {
214 9
        if (!is_array($request->getParams)) {
215
            $request->getParams = (array)$request->getParams;
216
        }
217
        if (!isset($request->getParams[$this->keyThreads])) {
218
            $request->getParams[$this->keyThreads] = 1;
219
        }
220
        $request->getParams[$this->keyThreads] += $number;
221
    }
222 21
223
    /**
224 21
     * Назначить альтернативный номер потока для запроса.
225 6
     *
226 2
     * @param Request $request
227 21
     * @param int $number
228 21
     */
229
    public function assignMfThreadsNumber(Request &$request, $number = 0)
230
    {
231
        if (!is_array($request->getParams)) {
232
            $request->getParams = (array)$request->getParams;
233
        }
234
        $request->getParams[$this->keyThreads] = "{$this->countThreads},$number";
235 24
    }
236
237 24
    /**
238
     * Наименование ключа содержащего набора данных сущности.
239
     *
240
     * @return string
241
     */
242
    public function getCollectionKey()
243
    {
244
        return 'items';
245 24
    }
246
247 24
    /**
248
     * Наименование ключа содержащего мета данные.
249
     *
250
     * @return string
251
     */
252
    public function getMetaKey()
253
    {
254
        return '_meta';
255
    }
256 48
257
    /**
258 48
     * Палучить набор данных сущности.
259
     *
260
     * @return Response[]
261
     * @throws \Exception
262
     */
263
    public function get()
264
    {
265
        return $this->client->batchQuery($this->getRequests());
266
    }
267 30
268
    /**
269 30
     * Установить запросы к API.
270 30
     *
271 30
     * @param Request[] $requests
272 3
     * @throws \Exception
273
     */
274 27
    public function setRequests(array $requests)
275 9
    {
276 27
        $this->requests = [];
277
        foreach ($requests as $request) {
278
            if (!$request instanceof Request) {
279
                throw new \Exception('Request must be implement "\SimaLand\API\Rest\Request"');
280
            }
281
            $this->requests[] = $request;
282
        }
283 51
    }
284
285 51
    /**
286 51
     * Получить запросы к API.
287 51
     *
288 15
     * @return array|Rest\Request[]
289 15
     */
290 15
    public function getRequests()
291 15
    {
292 5
        if (empty($this->requests)) {
293 15
            $requests = [];
294 5
            if (!is_null($this->keyThreads) && $this->countThreads > 1) {
295 5
                for ($i = 0; $i < $this->countThreads; $i++) {
296 36
                    $requests[$i] = new Request([
297 36
                        'entity' => $this->getEntity(),
298 36
                        'getParams' => $this->_getParams,
299 12
                    ]);
300
                    $this->assignThreadsNumber($requests[$i], $i);
301 51
                }
302 17
            } else {
303 51
                $requests[] = new Request([
304
                    'entity' => $this->getEntity(),
305
                    'getParams' => $this->_getParams,
306
                ]);
307
            }
308
            $this->requests = $requests;
309 21
        }
310
        return $this->requests;
311 21
    }
312
313
    /**
314
     * @inheritdoc
315
     */
316
    public function current()
317 42
    {
318
        return $this->current;
319 42
    }
320 42
321 8
    /**
322 24
     * @inheritdoc
323 24
     */
324
    public function next()
325
    {
326
        if (empty($this->values)) {
327
            $this->getData();
328 15
        }
329
        $this->current = array_shift($this->values);
330 15
    }
331
332
    /**
333
     * @inheritdoc
334
     */
335
    public function key()
336 21
    {
337
        return $this->key++;
338 21
    }
339
340
    /**
341
     * @inheritdoc
342
     */
343
    public function valid()
344 33
    {
345
        return !empty($this->current);
346 33
    }
347 33
348 33
    /**
349 33
     * @inheritdoc
350 21
     */
351
    public function rewind()
352
    {
353
        $this->values = [];
354
        $this->current = null;
355
        $this->key = 0;
356
        $this->next();
357
    }
358 39
359
    /**
360 39
     * Обработка ответов от API.
361 39
     *
362 39
     * @param Response[] $responses
363 33
     * @throws ResponseException
364
     */
365 8
    private function processingResponses(array $responses)
366 24
    {
367
        foreach ($responses as $response) {
368
            $statusCode = $response->getStatusCode();
369
            if (($statusCode < 200 || $statusCode >= 300) && $statusCode != 404) {
370
                throw new ResponseException($response);
371
            }
372
        }
373
    }
374 42
375
    /**
376 42
     * Получение ответов от API
377 42
     *
378 42
     * @return \GuzzleHttp\Psr7\Response[]
379
     * @throws \Exception
380 42
     */
381 42
    private function getResponses()
382 6
    {
383 6
        $i = 0;
384 6
        $responses = [];
385 6
        $logger = $this->getLogger();
386 2
        do {
387
            $e = null;
388 42
            if ($i > 0) {
389 39
                $logger->info("Wait time {$this->repeatTimeout} second to the next request");
390 30
                sleep($this->repeatTimeout);
391
                $attempt = $i + 1;
392 24
                $logger->info("Attempt {$attempt} of {$this->repeatCount}");
393 24
            }
394 8
            try {
395 21
                $responses = $this->get();
396 7
                $this->processingResponses($responses);
397 3
            } catch (\Exception $e) {
398
                if (
399
                    ($e instanceof RequestException) ||
400 39
                    ($e instanceof ResponseException)
401 39
                ) {
402 39
                    $logger->warning($e->getMessage(), ['code' => $e->getCode()]);
403 18
                } else {
404 18
                    throw $e;
405
                }
406 24
            }
407
            $i++;
408
        } while ($i <= $this->repeatCount && !is_null($e));
409
        if ($e) {
410
            $logger->error($e->getMessage(), ['code' => $e->getCode()]);
411
            throw new Exception($e->getMessage(), $e->getCode(), $e);
412
        }
413
        return $responses;
414
    }
415 24
416
    /**
417 24
     * Получить тело ответа от API.
418
     *
419 24
     * @param Response $response
420 24
     * @return bool
421 8
     */
422 18
    private function getBody(Response $response)
423
    {
424 24
        $body = json_decode($response->getBody(), true);
425
        if (
426
            !$body ||
427
            ($body && !isset($body[$this->getCollectionKey()]))
428
        ) {
429
            return false;
430
        }
431
        return $body;
432 42
    }
433
434 42
    /**
435 24
     * Получить набор данных от API.
436 24
     *
437 24
     * @throws Exception
438 24
     */
439 24
    private function getData()
440 24
    {
441 24
        $responses = $this->getResponses();
442 18
        $collectionKey = $this->getCollectionKey();
443 18
        $metaKey = $this->getMetaKey();
444
        $requests = $this->getRequests();
445 24
        $record = null;
446 21
        foreach ($responses as $key => $response) {
447 21
            $body = $this->getBody($response);
448 21
            if (!$body) {
449 7
                unset($requests[$key]);
450 21
                continue;
451 8
            }
452 24
            foreach ($body[$collectionKey] as $item) {
453 23
                $record = new Record([
454 7
                    'data' => $this->cleanData($item),
455 8
                    'meta' => isset($body[$metaKey]) ? $body[$metaKey] : null,
456 24
                ]);
457 24
                $this->values[] = $record;
458
            }
459
            if (!is_null($record)) {
460
                $this->assignPage($requests[$key], $record);
461
            }
462
        }
463
        $this->setRequests($requests);
464 27
    }
465
466 27
    /**
467 18
     * Установить GET параметры запроса.
468 15
     *
469 5
     * @param array $value
470 18
     */
471 18
    public function setGetParams(array $value)
472 18
    {
473 18
        if ($this->useAlternativePagination) {
474 3
            if (!isset($value[$this->keyAlternativePagination])) {
475 1
                $value[$this->keyAlternativePagination] = 0;
476 6
            }
477 27
            $r = new \ReflectionClass(__CLASS__);
478 27
            $defaultProperties = $r->getDefaultProperties();
479
            $valueKeyThreads = $defaultProperties['keyThreads'];
480
            if (isset($value[$valueKeyThreads])) {
481
                unset($value[$valueKeyThreads]);
482
            }
483
        }
484
        $this->_getParams = $value;
485 21
    }
486
487 21
    /**
488
     * Получить GET параметры запроса.
489
     *
490
     * @return array
491
     */
492
    public function getGetParams()
493
    {
494
        return $this->_getParams;
495
    }
496
497
    /**
498
     * Получить только те данные из ответа,
499
     * которые указаны в свойсте fields объекта сущности,
500
     * если аттрибуты не указаны в свойсте fields,
501
     * то метод вернет все аттрибуты из ответа
502
     *
503
     * @param array $item
504
     * @return array
505
     */
506
    private function cleanData($item)
507
    {
508
        if (!empty($this->fields)) {
509
            $cleanItem = [];
510
            foreach ($this->fields as $value) {
511
                if (in_array($value, array_keys($item))) {
512
                    $cleanItem[$value] = $item[$value];
513
                }
514
            }
515
        } else {
516
            $cleanItem = $item;
517
        }
518
        return $cleanItem;
519
    }
520
}
521