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 ( 951ad1...29ba67 )
by Alexey
08:55
created

BaseList::getModelIds()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 4.048
Metric Value
dl 0
loc 17
ccs 2
cts 10
cp 0.2
rs 9.4285
cc 2
eloc 9
nc 2
nop 1
crap 4.048
1
<?php
2
/**
3
 * @author Sergey Glagolev <[email protected]>, Alexey Tatarinov <[email protected]>
4
 * @link https://github.com/shogodev/argilla/
5
 * @copyright Copyright &copy; 2003-2014 Shogo
6
 * @license http://argilla.ru/LICENSE
7
 *
8
 * @property CDbCriteria $criteria
9
 */
10
class BaseList extends CComponent
11
{
12
  /**
13
   * @var string $sorting
14
   */
15
  public $sorting;
16
17
  /**
18
   * @var bool $pagination
19
   */
20
  public $pagination;
21
22
  /**
23
   * @var Filter[]|null $filters
24
   */
25
  public $filters = null;
26
27
  /**
28
   * Параметр, отвечающий за выборку параметров и картинок товаров,
29
   * можно отключить, если данные эти не используются, чтобы не тратить время на обработку
30
   * @var bool
31
   */
32
  public $fetchContent = true;
33
34
  public static $sortingRange = array();
35
36
  /**
37
   * @var $products FActiveDataProvider
38
   */
39
  protected $dataProvider;
40
41
  /**
42
   * @var CDbCriteria $criteria
43
   */
44
  protected $criteria;
45
46
  /**
47
   * @var CDbCriteria $criteria
48
   */
49
  protected $filteredCriteria;
50
51
  /**
52
   * @param CDbCriteria $criteria
53
   * @param null $sorting
54
   * @param bool $pagination
55
   * @param null $filters
56
   */
57 2
  public function __construct(CDbCriteria $criteria, $sorting = null, $pagination = true, $filters = null)
58
  {
59 2
    $this->sorting = $sorting;
60 2
    $this->pagination = $pagination;
61 2
    $this->criteria = clone $criteria;
62
63 2
    if( !empty($filters) )
64 2
      $this->filters = is_array($filters) ? $filters : array($filters);
65
66 2
    $this->init();
67 2
  }
68
69
  public function init()
70
  {
71
    $this->setOrder();
72
  }
73
74
  /**
75
   * @param boolean $refresh
76
   *
77
   * @return FActiveDataProvider
78
   */
79 2
  public function getDataProvider($refresh = false)
80
  {
81 2
    if( is_null($this->dataProvider) || $refresh )
82 2
      $this->buildDataProvider($this->getFilterCriteria());
83
84 2
    return $this->dataProvider;
85
  }
86
87
  /**
88
   * @return FActiveDataProvider
89
   */
90
  public function getRandomDataProvider()
91
  {
92
    $criteria = clone $this->getFilterCriteria();
93
    $criteria->condition = '';
94
    $criteria->params = $this->getConditionParams($criteria, 'order');
95
96
    $modelIds = $this->getModelIds();
97
98
    if( $criteria->limit )
99
    {
100
      shuffle($modelIds);
101
      $modelIds = array_slice($modelIds, 0, $criteria->limit);
102
    }
103
    $criteria->addInCondition($this->getTablePrefix().'.id', $modelIds);
104
105
    return $this->buildDataProvider($criteria);
106
  }
107
108
  /**
109
   * @param bool $resetLimit
110
   *
111
   * @return array
112
   * @throws CDbException
113
   */
114 2
  public function getModelIds($resetLimit = true)
115
  {
116
    $criteria = clone $this->getFilterCriteria();
117
118
    if( $resetLimit )
119
    {
120
      $criteria->limit = -1;
121
      $criteria->offset = -1;
122
    }
123
124
    ProductAssignment::model()->addAssignmentCondition($criteria);
125
126
    $builder = new CDbCommandBuilder(Yii::app()->db->getSchema());
127 2
    $command = $builder->createFindCommand($this->getModel()->tableName(), $criteria);
128
129
    return CHtml::listData($command->queryAll(), 'id', 'id');
130
  }
131
132
  public function getCacheKey()
133
  {
134
    $arrayForSerialize = array(
135
      $this->criteria->toArray(),
136
      $this->sorting,
137
    );
138
139
    if( $this->filters )
140
      foreach($this->filters as $filter)
141
        $arrayForSerialize[] = $filter->getState();
142
143
    return sha1(serialize($arrayForSerialize));
144
  }
145
146 2
  public function getFilterCriteria()
147
  {
148 2
    if( $this->filteredCriteria == null )
149 2
    {
150 2
      $filteredCriteria = clone $this->criteria;
151
152 2
      if( $this->filters )
153 2
      {
154
        foreach($this->filters as $filter)
155
          $filteredCriteria = $filter->apply($filteredCriteria);
156
157
        foreach(array('distinct', 'order') as $value)
158
        {
159
          $filteredCriteria->$value = $this->criteria->$value;
160
          if( $value == 'order' && !empty($this->criteria->join) )
161
          {
162
            $filteredCriteria->join = $this->getOrderJoin($filteredCriteria->order, $this->criteria->join);
163
          }
164
        }
165
      }
166
167 2
      $this->filteredCriteria = $filteredCriteria;
168 2
    }
169
170 2
    return $this->filteredCriteria;
171
  }
172
173
  /**
174
   * Возвращает раздельный массив join'ов
175
   * @param $sql
176
   *
177
   * @return array
178
   * @throws CHttpException
179
   */
180
  protected function getJoins($sql)
181
  {
182
    $joins = array();
183
    $sql = strtr($sql, array("\n" => ' ', "\r" => '', '  ' => ' '));
184
    $sql = trim(preg_replace('/\s+2/', '', $sql));
185
    if( $data = preg_split('/(CROSS JOIN)|(INNER JOIN)|(LEFT OUTER JOIN)|(LEFT JOIN)|(RIGHT JOIN)|(RIGHT OUTER JOIN)|(JOIN)/i', $sql, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) )
186
    {
187
      if( count($data) % 2 !== 0 )
188
        throw new CHttpException(500, 'Ошибка!');
189
190
      for($i = 0; $i < count($data); $i += 2)
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
Performance Best Practice introduced by
Consider avoiding function calls on each iteration of the for loop.

If you have a function call in the test part of a for loop, this function is executed on each iteration. Often such a function, can be moved to the initialization part and be cached.

// count() is called on each iteration
for ($i=0; $i < count($collection); $i++) { }

// count() is only called once
for ($i=0, $c=count($collection); $i<$c; $i++) { }
Loading history...
191
      {
192
        $joins[] = $data[$i].' '.$data[$i + 1];
193
      }
194
    }
195
196
    return $joins;
197
  }
198
199
  /**
200
   * Возвращает join нужный для сортировки
201
   * @param $order
202
   * @param $baseJoin
203
   *
204
   * @return string
205
   * @throws CHttpException
206
   */
207
  protected function getOrderJoin($order, $baseJoin)
208
  {
209
    $orderJoins = array();
210
211
    $joins = $this->getJoins($baseJoin);
212
213
    if( preg_match_all('/(\w+)\./i', $order, $matches) )
214
    {
215
      $tableAliases = array_unique($matches[1]);
216
217
      foreach($tableAliases as $alias)
218
      {
219
        foreach($joins as $join)
220
        {
221
          if( preg_match('/AS\s*(\w+)\s|$/i', $join, $matches) )
222
          {
223
            if( $matches[1] == $alias )
224
              $orderJoins[] = $join;
225
          }
226
        }
227
      }
228
    }
229
230
    return implode(' ', $orderJoins);
231
  }
232
233
  protected function setOrder()
234
  {
235
    if( empty($this->criteria->order) )
236
      $this->criteria->order = Arr::get(static::$sortingRange, $this->sorting, Arr::reset(static::$sortingRange));
237
  }
238
239 2
  protected function buildDataProvider(CDbCriteria $criteria)
240
  {
241 2
    $config = array('criteria' => $criteria);
242 2
    if( !$this->pagination || $this->pagination instanceof FPagination )
243 2
      $config['pagination'] = $this->pagination;
244
245 2
    $this->dataProvider = new FActiveDataProvider($this->getModelName(), $config);
246
247 2
    if( $this->fetchContent )
248 2
      $this->dataProvider->attachEventHandler('onAfterFetchData', array($this, 'afterFetchData'));
249
250 2
    return $this->dataProvider;
251
  }
252
253
  protected function afterFetchData($event)
254
  {
255
    $this->setImages();
256
  }
257
258 2
  protected function setImages()
259
  {
260
    /**
261
     * @var ActiveImageBehavior $imagesBehavior
262
     */
263 2
    if( $imagesBehavior = $this->getModel()->asa('imagesBehavior') )
264 2
    {
265 2
      $modelImages = $this->findRecords('parent', $imagesBehavior->imageClass, null, $imagesBehavior->getColorCriteria());
266
267 2
      $images = array();
268 2
      foreach($modelImages as $image)
269 2
        $images[$image['parent']][$image['type']][] = $image;
270
271
      /**
272
       * @var $product Product
273
       */
274 2
      foreach($this->dataProvider->getData() as $product)
275
      {
276 2
        if( isset($images[$product->id]) )
277 2
        {
278
          foreach($images[$product->id] as $type => $imgs)
279
          {
280
            $product->setImages($imgs, $type);
281
          }
282
        }
283
        else
284
        {
285 2
          $product->setImages(array(), null);
286
        }
287 2
      }
288 2
    }
289 2
  }
290
291
  protected function setRelations($relationName)
292
  {
293
    $models = array();
294
    $relation = Product::model()->getMetaData()->relations[$relationName];
295
    $records = $this->findRecords($relation->foreignKey, $relation->className);
296
297
    foreach($records as $record)
298
    {
299
      if( get_class($relation) === 'CHasOneRelation' )
300
      {
301
        $models[$record['product_id']] = $record;
302
      }
303
      else
304
      {
305
        $models[$record['product_id']][] = $record;
306
      }
307
    }
308
309
    $this->setRecords($relationName, $models);
310
  }
311
312
  /**
313
   * @param string $fk
314
   * @param string $className
315
   * @param array $keys
316
   * @param CDbCriteria $criteria
317
   *
318
   * @return FActiveRecord[]
319
   */
320 2
  protected function findRecords($fk, $className, array $keys = null, CDbCriteria $criteria = null)
321
  {
322 2
    if( !isset($criteria) )
323 2
    {
324
      $criteria = new CDbCriteria();
325
    }
326
327 2
    $criteria->addInCondition($fk, isset($keys) ? $keys : $this->dataProvider->getKeys(true));
328
329 2
    return $className::model()->findAll($criteria);
330
  }
331
332
  /**
333
   * @param string $modelName
334
   * @param FActiveRecord[] $models
335
   */
336 2
  protected function setRecords($modelName, array $models)
337
  {
338
    /**
339
     * @var $product Product
340
     */
341 2
    foreach($this->dataProvider->getData() as $product)
342
    {
343 2
      $records = Arr::get($models, $product->id, array(null));
344
345 2
      if( is_object($records) )
346 2
      {
347 2
        $useIndex = false;
348 2
        $records = array($records);
349 2
      }
350
351 2
      foreach($records as $model)
0 ignored issues
show
Bug introduced by
The expression $records of type integer|double|string|null|array|boolean|resource is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
352
      {
353 2
        $product->addRelatedRecord($modelName, $model, isset($useIndex) ? $useIndex : true);
354 2
      }
355 2
    }
356 2
  }
357
358
  /**
359
   * @return CActiveRecord
360
   */
361 2
  protected function getModelName()
362
  {
363 2
    return str_replace('List', '', get_class($this));
364
  }
365
366 2
  protected function getTablePrefix()
367
  {
368 2
    return 't';
369
  }
370
371
  /**
372
   * @return CActiveRecord
373
   */
374 2
  protected function getModel()
375
  {
376 2
    $modelName = $this->getModelName();
377 2
    return $modelName::model();
378
  }
379
380
  /**
381
   * @param CDbCriteria $criteria
382
   * @param $attribute
383
   *
384
   * @return array
385
   */
386
  protected function getConditionParams(CDbCriteria $criteria, $attribute)
387
  {
388
    $params = array();
389
390
    if( preg_match_all('/(:\w+)/', $criteria->{$attribute}, $matches) )
391
    {
392
      foreach($matches[0] as $param)
393
      {
394
        $params[$param] = Arr::get($criteria->params, $param);
395
      }
396
    }
397
398
    return $params;
399
  }
400
}