Collection   A
last analyzed

Complexity

Total Complexity 28

Size/Duplication

Total Lines 480
Duplicated Lines 5 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 43.66%

Importance

Changes 0
Metric Value
wmc 28
lcom 1
cbo 3
dl 24
loc 480
ccs 31
cts 71
cp 0.4366
rs 10
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 23 4
A setLimit() 12 12 3
A setOffset() 12 12 3
A getFullCount() 0 6 1
A getClient() 0 4 1
A getLimit() 0 4 1
A getOffset() 0 4 1
A getPages() 0 3 1
A load() 0 27 4
A getIterator() 0 4 1
A count() 0 6 1
A getData() 0 6 1
A reset() 0 8 2
A createModel() 0 13 2
A end() 0 8 2

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
 * Class BookCollection
4
 *
5
 * @author       Denis Shestakov <[email protected]>
6
 * @copyright    Copyright (c) 2017, Lan Publishing
7
 * @license      MIT
8
 */
9
10
namespace Lan\Ebs\Sdk\Classes;
11
12
use ArrayObject;
13
use Exception;
14
use Lan\Ebs\Sdk\Client;
15
use Lan\Ebs\Sdk\Collection\ArticleCollection;
16
use Lan\Ebs\Sdk\Collection\IssueCollection;
17
use Lan\Ebs\Sdk\Common;
18
use ReflectionClass;
19
20
/**
21
 * Абстрактный класс для всех коллекций (+ итерируемый)
22
 *
23
 * @package      Lan\Ebs
24
 * @subpackage   Sdk
25
 * @category     Classes
26
 */
27
abstract class Collection extends ArrayObject implements Common
28
{
29
    /**
30
     * Инстанс клиента API
31
     *
32
     * @var Client
33
     */
34
    private $client;
35
36
    /**
37
     * Флаг, сигнализирующий что коллекция загружена
38
     *
39
     * @var int
40
     */
41
    private $loadStatus = 0;
42
43
    /**
44
     * Имена полей, подлежаших получению через API
45
     *
46
     * @var array
47
     */
48
    private $fields = array();
49
50
    /**
51
     * Класс модели
52
     *
53
     * @var Model|string
54
     */
55
    private $class = null;
56
57
    /**
58
     * Лимит получаемых моделей коллекции через API
59
     *
60
     * @var int
61
     */
62
    private $limit = null;
63
64
    /**
65
     * Смещение выборки моделей через API
66
     *
67
     * @var int
68
     */
69
    private $offset = null;
70
71
    /**
72
     * Всего элементов без учета лимита
73
     *
74
     * @var int
75
     */
76
    private $fullCount = null;
77
78
    /**
79
     * Конструктор коллекции
80
     *
81
     * @param Client $client Инстанс клиента
82
     * @param array $fields Поля для выборки
83
     * @param string $class Класс модели
84
     * @param int $limit Лимит выборки
85
     * @param int $offset Смещение выборки
86
     *
87
     * Пример:
88
     * ```php
89
     *      $token = '7c0c2193d27108a509abd8ea84a8750c82b3a520'; // токен для тестового подписчика
90
     *
91
     *      $client = new Client($token); // инициализация клиента
92
     *
93
     *      $bookCollection = new BookCollection($client, [], '\Lan\Ebs\Sdk\Model\Book', 5, 10); // инициализация коллекции книг
94
     * ```
95
     *
96
     * @throws Exception
97
     *
98
     * @see ArticleCollection::__construct
99
     * @see BookCollection::__construct
100
     * @see IssueCollection::__construct
101
     * @see JournalCollection::__construct
102
     * @see UserCollection::__construct
103
     */
104 3
    public function __construct(Client $client, array $fields, $class, $limit, $offset)
105
    {
106 3
        if (!$client) {
107
            throw new Exception('Клиент не инициализирован');
108
        }
109
110 3
        if (!is_array($fields)) {
111
            throw new Exception('Fields for model of collection mast be array');
112
        }
113
114 3
        $reflectionClass = new ReflectionClass($class);
115
116 3
        if (!$reflectionClass->isSubclassOf(Model::class)) {
117
            throw new Exception('Class of model collection not subclass for Model');
118
        }
119
120 3
        $this->client = $client;
121 3
        $this->fields = $fields;
122 3
        $this->class = $class;
123
124 3
        $this->setLimit($limit);
125 3
        $this->setOffset($offset);
126 3
    }
127
128
    /**
129
     * Установка лимита выборки
130
     *
131
     * Установка/изменение лимита выборки коллекции. Вызывет перезагрузку коллекции если значение лимита изменилось
132
     *
133
     * @param int $limit Значение лимита выборки
134
     *
135
     * Пример:
136
     * ```php
137
     *      $token = '7c0c2193d27108a509abd8ea84a8750c82b3a520'; // токен для тестового подписчика
138
     *
139
     *      $client = new Client($token); // инициализация клиента
140
     *
141
     *      $bookCollection = new BookCollection($client, [], '\Lan\Ebs\Sdk\Model\Book', 5, 100); // инициализация коллекции книг
142
     *
143
     *      $bookCollection->setLimit(100); // изменение лимита с 5 до 100
144
     * ```
145
     *
146
     * @return $this
147
     *
148
     * Пример:
149
     * ```php
150
     *      echo $bookCollection->setLimit(100)->count(); // Выведет количество элементов коллекции
151
     * ```
152
     *
153
     * @throws Exception
154
     */
155 3 View Code Duplication
    public function setLimit($limit)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
156
    {
157 3
        $isChanged = $this->limit != $limit;
158
159 3
        $this->limit = $limit;
160
161 3
        if ($isChanged && $this->loadStatus == 200) {
162
            $this->load(true);
163
        }
164
165 3
        return $this;
166
    }
167
168
    /**
169
     * Загрузка коллекции
170
     *
171
     * Загрузка осуществляется только после вызова зависимого метода (ленивая загрузка)
172
     *
173
     * @param bool $force Заново загружать коллекцию даже если она загружена ранее
174
     *
175
     * Пример:
176
     * ```php
177
     *      $token = '7c0c2193d27108a509abd8ea84a8750c82b3a520'; // токен для тестового подписчика
178
     *
179
     *      $client = new Client($token); // инициализация клиента
180
     *
181
     *      $bookCollection = new BookCollection($client, [], '\Lan\Ebs\Sdk\Model\Book', 5, 100); // инициализация коллекции книг
182
     *
183
     *      // Вызова метода загрузки еще небыло.. коллекция пустая
184
     *      $bookCollection->load(); // загрузка коллекции данными
185
     *      // Запрос к API выполнен.. коллекция загружена
186
     * ```
187
     *
188
     * @return $this Вернет текущую коллекцию
189
     *
190
     * Пример:
191
     * ```php
192
     *       echo $bookCollection->load()->count(); // Выведет количество элементов коллекции
193
     * ```
194
     *
195
     * @throws Exception
196
     *
197
     * @see Collection::setLimit()
198
     * @see Collection::setOffset()
199
     * @see Collection::getFullCount()
200
     * @see Collection::getCount()
201
     * @see Collection::getData()
202
     * @see Collection::reset()
203
     * @see Collection::end()
204
     * @see CollectionIterator::rewind()
205
     */
206 3
    public function load($force = false)
207
    {
208 3
        if ($this->loadStatus == 200 && !$force) {
209
            return $this;
210
        }
211
212
        $params = array(
213 3
            'limit' => $this->limit,
214 3
            'offset' => $this->offset
215
        );
216
217 3
        if (!empty($this->fields)) {
218
            $params['fields'] = implode(',', (array)$this->fields);
219
        }
220
221 3
        $response = $this->client->getResponse($this->getUrl(__FUNCTION__), $params);
222
223
        $this->exchangeArray($response['data']);
224
225
        $this->loadStatus = $response['status'];
226
227
        $this->fullCount = $response['count'];
228
229
        unset($response);
230
231
        return $this;
232
    }
233
234
    /**
235
     * Установка смещения выборки
236
     *
237
     * Установка/изменение смещения выборки коллекции. Вызывет перезагрузку коллекции если значение смещения изменилось
238
     *
239
     * @param int $offset Значение смещения выборки
240
     *
241
     * Пример:
242
     * ```php
243
     *      $token = '7c0c2193d27108a509abd8ea84a8750c82b3a520'; // токен для тестового подписчика
244
     *
245
     *      $client = new Client($token); // инициализация клиента
246
     *
247
     *      $bookCollection = new BookCollection($client, [], '\Lan\Ebs\Sdk\Model\Book', 5, 100); // инициализация коллекции книг
248
     *
249
     *      $bookCollection->setOffset(1000); // изменение смещения со 100 до 1000
250
     * ```
251
     *
252
     * @return $this Вернет текущую коллекцию
253
     *
254
     * Пример:
255
     * ```php
256
     *      echo $bookCollection->setOffset(1000)->count(); // Выведет количество элементов коллекции
257
     * ```
258
     *
259
     * @throws Exception
260
     */
261 3 View Code Duplication
    public function setOffset($offset)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
262
    {
263 3
        $isChanged = $this->offset != $offset;
264
265 3
        $this->offset = $offset;
266
267 3
        if ($isChanged && $this->loadStatus == 200) {
268
            $this->load(true);
269
        }
270
271 3
        return $this;
272
    }
273
274
    /**
275
     * Получение количества всех элементов без учета лимита
276
     *
277
     * Вернет общее количество элементов необходимое, например, для вычисления постраничной выборки
278
     *
279
     * Пример:
280
     * ```php
281
     *      $token = '7c0c2193d27108a509abd8ea84a8750c82b3a520'; // токен для тестового подписчика
282
     *
283
     *      $client = new Client($token); // инициализация клиента
284
     *
285
     *      $bookCollection = new BookCollection($client, [], '\Lan\Ebs\Sdk\Model\Book', 5, 100); // инициализация коллекции книг
286
     *
287
     *      echo $bookCollection->getFullCount(); // Вернет количество элементов без учета лимита
288
     * ```
289
     *
290
     * @return int
291
     *
292
     * Пример:
293
     * ```php
294
     *      echo $bookCollection>getFullCount(); // Вернет, например, 286
295
     *      echo $bookCollection->сount(); // Вернет, например, 5
296
     *      // Итого получаем ceil($bookCollection>getFullCount() /  $bookCollection>getLimit()) = 58 страниц
297
     * ```
298
     *
299
     * @throws Exception
300
     */
301
    public function getFullCount()
302
    {
303
        $this->load();
304
305
        return $this->fullCount;
306
    }
307
308
    /**
309
     * Получение нового инстанса итератора коллекции
310
     *
311
     * Итератор для реализации итерируемой коллекции
312
     *
313
     * @return CollectionIterator Вернет экзепляря итератора текущей коллекции
314
     */
315
    public function getIterator()
316
    {
317
        return new CollectionIterator($this);
318
    }
319
320
    /**
321
     * Количество моделей в коллекции
322
     *
323
     * Фактическое число моделей в коллекции
324
     *
325
     * Пример:
326
     * ```php
327
     *      $token = '7c0c2193d27108a509abd8ea84a8750c82b3a520'; // токен для тестового подписчика
328
     *
329
     *      $client = new Client($token); // инициализация клиента
330
     *
331
     *      $bookCollection = new BookCollection($client, [], '\Lan\Ebs\Sdk\Model\Book', 5, 100); // инициализация коллекции книг
332
     *
333
     *      echo $bookCollection>getFullCount(); // Вернет количество элементов без учета лимита
334
     * ```
335
     *
336
     * @return int
337
     *
338
     * Пример:
339
     * ```php
340
     *      echo $bookCollection->сount(); // Вернет, например, 5 (но не больше 5 - фактическое количество)
341
     * ```
342
     *
343
     * @throws Exception
344
     */
345 2
    public function count()
346
    {
347 2
        $this->load();
348
349
        return parent::count();
350
    }
351
352
    /**
353
     * Получение коллекции в виде массива
354
     *
355
     * Выгрузка коллекции в массив
356
     *
357
     * Пример:
358
     * ```php
359
     *      $token = '7c0c2193d27108a509abd8ea84a8750c82b3a520'; // токен для тестового подписчика
360
     *
361
     *      $client = new Client($token); // инициализация клиента
362
     *
363
     *      $bookCollection = new BookCollection($client, [], '\Lan\Ebs\Sdk\Model\Book', 1, 10); // инициализация коллекции книг
364
     *
365
     *      print_r($bookCollection->getData()); // Вернет количество элементов без учета лимита
366
     * ```
367
     *
368
     * @return array
369
     *
370
     * Пример:
371
     * ```
372
     * [
373
     *      'id' => 22445,
374
     *      'name' => 'Свадьба. Сцена в одном действии',
375
     *      'authors' => 'Чехов А.П.'
376
     * ]
377
     * ```
378
     *
379
     * @throws Exception
380
     */
381
    public function getData()
382
    {
383
        $this->load();
384
385
        return $this->getArrayCopy();
386
    }
387
388
    /**
389
     * Получение первой модели в коллекции
390
     *
391
     * Вернет первую модель коллекции.
392
     *
393
     * @return Model
394
     *
395
     * @throws Exception
396
     */
397 1
    public function reset()
398
    {
399 1
        $this->load();
400
401
        $data = reset($this);
402
403
        return $data ? $this->createModel($data) : null;
404
    }
405
406
    /**
407
     * Создание модели по переданным данным
408
     *
409
     * Создает модель по ее данным
410
     *
411
     * Пример:
412
     * ```php
413
     *      $token = '7c0c2193d27108a509abd8ea84a8750c82b3a520'; // токен для тестового подписчика
414
     *
415
     *      $client = new Client($token); // инициализация клиента
416
     *
417
     *      $bookCollection = new BookCollection($client, [], '\Lan\Ebs\Sdk\Model\Book', 1, 10); // инициализация коллекции книг
418
     *
419
     *      $bookData = [
420
     *          'id' => 22445,
421
     *          'name' => 'Свадьба. Сцена в одном действии',
422
     *          'authors' => 'Чехов А.П.'
423
     *      ];
424
     *
425
     *      $book = $bookCollection->createModel($bookData);
426
     * ```
427
     *
428
     * @param array $data Данные для создания модели
429
     *
430
     * @return Model Вернет модель на основе данных
431
     *
432
     * @throws Exception
433
     */
434
    public function createModel(array $data = null)
435
    {
436
        $class = $this->class;
437
438
        /**
439
         * @var Model $model
440
         */
441
        $model = new $class($this->client, $this->fields);
442
443
        $model->set($data === null ? current($this) : $data);
444
445
        return $model;
446
    }
447
448
    /**
449
     * Получение последней модели в коллекции
450
     *
451
     * Вернет полделнюю модель коллекции.
452
     *
453
     * @return Model
454
     *
455
     * @throws Exception
456
     */
457
    public function end()
458
    {
459
        $this->load();
460
461
        $data = end($this);
462
463
        return $data ? $this->createModel($data) : null;
464
    }
465
466
    /**
467
     * Получение инстанса клиента
468
     *
469
     * @return Client
470
     */
471
    protected function getClient()
472
    {
473
        return $this->client;
474
    }
475
476
    /**
477
     * Получение текущего лимита коллекции
478
     *
479
     * @return int
480
     */
481
    public function getLimit()
482
    {
483
        return $this->limit;
484
    }
485
486
    /**
487
     *
488
     * Получение текущего смещения коллекции
489
     *
490
     * @return int
491
     */
492
    public function getOffset()
493
    {
494
        return $this->offset;
495
    }
496
497
    /**
498
     * Общее количество страниц при заданом лимиите на страницу
499
     *
500
     * @return float
501
     * @throws Exception
502
     */
503
    public function getPages() {
504
        return ceil($this->getFullCount() /  $this->getLimit());
505
    }
506
}