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
Push — master ( 1f3339...c4c48f )
by
unknown
10s
created

AbstractList::assignAlternativePage()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4.128

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 8
cts 10
cp 0.8
rs 9.2
c 0
b 0
f 0
cc 4
eloc 7
nc 4
nop 2
crap 4.128
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 Object 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
     * @param Client $client
107
     * @param array $options
108
     */
109 81
    public function __construct(Client $client, array $options = [])
110
    {
111 81
        $this->client = $client;
112 81
        parent::__construct($options);
113 81
    }
114
115
    /**
116
     * Получить наименование сущности.
117
     *
118
     * @return string
119
     */
120
    abstract public function getEntity();
121
122
    /**
123
     * Добавить get параметры.
124
     *
125
     * @param array $params
126
     * @return AbstractList
127
     */
128 6
    public function addGetParams(array $params)
129
    {
130 6
        $this->setGetParams(array_merge($this->_getParams, $params));
131 6
        return $this;
132
    }
133
134
    /**
135
     * Назначить следующую страницу запросу.
136
     *
137
     * @param Request $request
138
     * @param Record|null $record
139
     */
140 30
    public function assignPage(Request &$request, Record $record = null)
141
    {
142 30
        if ($this->useAlternativePagination) {
143 18
            $this->assignAlternativePage($request, $record);
144 18
        } else {
145 12
            $this->assignDefaultPage($request);
146
        }
147 30
    }
148
149
    /**
150
     * Назначить следующую страницу запросу, используя стандартную пагинацию.
151
     *
152
     * @param Request $request
153
     */
154 12
    protected function assignDefaultPage(Request &$request)
155
    {
156 12
        $currentPage = 1;
157 12
        if (!is_array($request->getParams)) {
158 3
            $request->getParams = (array)$request->getParams;
159 3
        }
160 12
        if (isset($request->getParams[$this->keyThreads])) {
161 12
            $currentPage = (int)$request->getParams[$this->keyThreads];
162 12
        }
163 12
        $request->getParams[$this->keyThreads] = $currentPage + $this->countThreads;
164 12
    }
165
166
    /**
167
     * Назначить следующую страницу запросу, используют альтернативную пагинацию.
168
     *
169
     * @param Request $request
170
     * @param Record|null $record
171
     */
172 18
    protected function assignAlternativePage(Request &$request, Record $record = null)
173
    {
174 18
        $lastId = 0;
175 18
        if ($record && $record->data) {
176 18
            $lastId = (int)$record->data['id'];
177 18
        }
178 18
        if (!is_array($request->getParams)) {
179
            $request->getParams = (array)$request->getParams;
180
        }
181 18
        $request->getParams[$this->keyAlternativePagination] = $lastId;
182 18
    }
183
184
    /**
185
     * Назначить номер потока для запроса.
186
     *
187
     * @param Request $request
188
     * @param int $number
189
     */
190 30
    public function assignThreadsNumber(Request &$request, $number = 0)
191
    {
192 30
        if ("id-mf" == $this->keyThreads) {
193 21
            $this->assignMfThreadsNumber($request, $number);
194 21
        } else {
195 9
            $this->assignDefaultThreadsNumber($request, $number);
196
        }
197 30
    }
198
199
    /**
200
     * Назначить по умолчанию номер потока для запроса.
201
     *
202
     * @param Request $request
203
     * @param int $number
204
     */
205 9
    public function assignDefaultThreadsNumber(Request &$request, $number = 0)
206
    {
207 9
        if (!is_array($request->getParams)) {
208 3
            $request->getParams = (array)$request->getParams;
209 3
        }
210 9
        if (!isset($request->getParams[$this->keyThreads])) {
211 9
            $request->getParams[$this->keyThreads] = 1;
212 9
        }
213 9
        $request->getParams[$this->keyThreads] += $number;
214 9
    }
215
216
    /**
217
     * Назначить альтернативный номер потока для запроса.
218
     *
219
     * @param Request $request
220
     * @param int $number
221
     */
222 21
    public function assignMfThreadsNumber(Request &$request, $number = 0)
223
    {
224 21
        if (!is_array($request->getParams)) {
225 6
            $request->getParams = (array)$request->getParams;
226 6
        }
227 21
        $request->getParams[$this->keyThreads] = "{$this->countThreads},$number";
228 21
    }
229
230
    /**
231
     * Наименование ключа содержащего набора данных сущности.
232
     *
233
     * @return string
234
     */
235 24
    public function getCollectionKey()
236
    {
237 24
        return 'items';
238
    }
239
240
    /**
241
     * Наименование ключа содержащего мета данные.
242
     *
243
     * @return string
244
     */
245 24
    public function getMetaKey()
246
    {
247 24
        return '_meta';
248
    }
249
250
    /**
251
     * Палучить набор данных сущности.
252
     *
253
     * @return Response[]
254
     * @throws \Exception
255
     */
256 48
    public function get()
257
    {
258 48
        return $this->client->batchQuery($this->getRequests());
259
    }
260
261
    /**
262
     * Установить запросы к API.
263
     *
264
     * @param Request[] $requests
265
     * @throws \Exception
266
     */
267 30
    public function setRequests(array $requests)
268
    {
269 30
        $this->requests = [];
270 30
        foreach ($requests as $request) {
271 30
            if (!$request instanceof Request) {
272 3
                throw new \Exception('Request must be implement "\SimaLand\API\Rest\Request"');
273
            }
274 27
            $this->requests[] = $request;
275 27
        }
276 27
    }
277
278
    /**
279
     * Получить запросы к API.
280
     *
281
     * @return array|Rest\Request[]
282
     */
283 51
    public function getRequests()
284
    {
285 51
        if (empty($this->requests)) {
286 51
            $requests = [];
287 51
            if (!is_null($this->keyThreads) && $this->countThreads > 1) {
288 15
                for ($i = 0; $i < $this->countThreads; $i++) {
289 15
                    $requests[$i] = new Request([
290 15
                        'entity' => $this->getEntity(),
291 15
                        'getParams' => $this->_getParams,
292 15
                    ]);
293 15
                    $this->assignThreadsNumber($requests[$i], $i);
294 15
                }
295 15
            } else {
296 36
                $requests[] = new Request([
297 36
                    'entity' => $this->getEntity(),
298 36
                    'getParams' => $this->_getParams,
299 36
                ]);
300
            }
301 51
            $this->requests = $requests;
302 51
        }
303 51
        return $this->requests;
304
    }
305
306
    /**
307
     * @inheritdoc
308
     */
309 21
    public function current()
310
    {
311 21
        return $this->current;
312
    }
313
314
    /**
315
     * @inheritdoc
316
     */
317 42
    public function next()
318
    {
319 42
        if (empty($this->values)) {
320 42
            $this->getData();
321 24
        }
322 24
        $this->current = array_shift($this->values);
323 24
    }
324
325
    /**
326
     * @inheritdoc
327
     */
328 15
    public function key()
329
    {
330 15
        return $this->key++;
331
    }
332
333
    /**
334
     * @inheritdoc
335
     */
336 21
    public function valid()
337
    {
338 21
        return !empty($this->current);
339
    }
340
341
    /**
342
     * @inheritdoc
343
     */
344 33
    public function rewind()
345
    {
346 33
        $this->values = [];
347 33
        $this->current = null;
348 33
        $this->key = 0;
349 33
        $this->next();
350 21
    }
351
352
    /**
353
     * Обработка ответов от API.
354
     *
355
     * @param Response[] $responses
356
     * @throws ResponseException
357
     */
358 39
    private function processingResponses(array $responses)
359
    {
360 39
        foreach ($responses as $response) {
361 39
            $statusCode = $response->getStatusCode();
362 39
            if (($statusCode < 200 || $statusCode >= 300) && $statusCode != 404) {
363 21
                throw new ResponseException($response);
364
            }
365 24
        }
366 24
    }
367
368
    /**
369
     * Получение ответов от API
370
     *
371
     * @return \GuzzleHttp\Psr7\Response[]
372
     * @throws \Exception
373
     */
374 42
    private function getResponses()
375
    {
376 42
        $i = 0;
377 42
        $responses = [];
378 42
        $logger = $this->getLogger();
379
        do {
380 42
            $e = null;
381 42
            if ($i > 0) {
382 6
                $logger->info("Wait time {$this->repeatTimeout} second to the next request");
383 6
                sleep($this->repeatTimeout);
384 6
                $attempt = $i + 1;
385 6
                $logger->info("Attempt {$attempt} of {$this->repeatCount}");
386 6
            }
387
            try {
388 42
                $responses = $this->get();
389 39
                $this->processingResponses($responses);
390 42
            } catch (\Exception $e) {
391
                if (
392 24
                    ($e instanceof RequestException) ||
393 24
                    ($e instanceof ResponseException)
394 24
                ) {
395 21
                    $logger->warning($e->getMessage(), ['code' => $e->getCode()]);
396 21
                } else {
397 3
                    throw $e;
398
                }
399
            }
400 39
            $i++;
401 39
        } while ($i <= $this->repeatCount && !is_null($e));
402 39
        if ($e) {
403 18
            $logger->error($e->getMessage(), ['code' => $e->getCode()]);
404 18
            throw new Exception($e->getMessage(), $e->getCode(), $e);
405
        }
406 24
        return $responses;
407
    }
408
409
    /**
410
     * Получить тело ответа от API.
411
     *
412
     * @param Response $response
413
     * @return bool
414
     */
415 24
    private function getBody(Response $response)
416
    {
417 24
        $body = json_decode($response->getBody(), true);
418
        if (
419 24
            !$body ||
420 24
            ($body && !isset($body[$this->getCollectionKey()]))
421 24
        ) {
422 18
            return false;
423
        }
424 24
        return $body;
425
    }
426
427
    /**
428
     * Получить набор данных от API.
429
     *
430
     * @throws Exception
431
     */
432 42
    private function getData()
433
    {
434 42
        $responses = $this->getResponses();
435 24
        $collectionKey = $this->getCollectionKey();
436 24
        $metaKey = $this->getMetaKey();
437 24
        $requests = $this->getRequests();
438 24
        $record = null;
439 24
        foreach ($responses as $key => $response) {
440 24
            $body = $this->getBody($response);
441 24
            if (!$body) {
442 18
                unset($requests[$key]);
443 18
                continue;
444
            }
445 24
            foreach ($body[$collectionKey] as $item) {
446 21
                $record = new Record([
447 21
                    'data' => $item,
448 21
                    'meta' => isset($body[$metaKey]) ? $body[$metaKey] : null,
449 21
                ]);
450 21
                $this->values[] = $record;
451 24
            }
452 24
            if (!is_null($record)) {
453 21
                $this->assignPage($requests[$key], $record);
454 21
            }
455 24
        }
456 24
        $this->setRequests($requests);
457 24
    }
458
459
    /**
460
     * Установить GET параметры запроса.
461
     *
462
     * @param array $value
463
     */
464 24
    public function setGetParams(array $value)
465
    {
466 24
        if (!isset($value[$this->keyAlternativePagination]) && $this->useAlternativePagination) {
467 12
            $value[$this->keyAlternativePagination] = 0;
468 12
        }
469 24
        $this->_getParams = $value;
470 24
    }
471
472
    /**
473
     * Получить GET параметры запроса.
474
     *
475
     * @return array
476
     */
477 18
    public function getGetParams()
478
    {
479 18
        return $this->_getParams;
480
    }
481
}
482