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.
Test Setup Failed
Push — action_getCatTree_order ( 77944b )
by
unknown
23:56
created

Property   C

Complexity

Total Complexity 49

Size/Duplication

Total Lines 404
Duplicated Lines 5.69 %

Coupling/Cohesion

Components 1
Dependencies 17

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 49
lcom 1
cbo 17
dl 23
loc 404
rs 5.7127
c 2
b 0
f 0

18 Methods

Rating   Name   Duplication   Size   Complexity  
A tableName() 0 4 1
A getGroup() 0 4 1
A behaviors() 0 18 1
B rules() 0 37 1
B attributeLabels() 0 29 1
B search() 0 24 2
A getHandler() 0 5 1
B findById() 23 23 4
B getForGroupId() 0 37 6
A handler() 0 12 3
C afterFind() 0 24 10
C beforeSave() 0 26 7
A invalidateModelCache() 0 13 1
A afterSave() 0 6 1
A beforeDelete() 0 5 1
B afterDelete() 0 27 5
A getAdditionalParam() 0 7 2
A getAliases() 0 10 1

How to fix   Duplicated Code    Complexity   

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:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Property often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Property, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace app\models;
3
4
use app\modules\shop\models\FilterSets;
5
use app\properties\HasProperties;
6
use app\properties\PropertyHandlers;
7
use app\traits\GetImages;
8
use Yii;
9
use yii\behaviors\AttributeBehavior;
10
use yii\caching\TagDependency;
11
use yii\data\ActiveDataProvider;
12
use yii\db\ActiveRecord;
13
use yii\helpers\Json;
14
use \devgroup\TagDependencyHelper\ActiveRecordHelper;
15
16
17
/**
18
 * This is the model class for table "property".
19
 * @property integer $id
20
 * @property integer $property_group_id
21
 * @property string $name
22
 * @property string $key
23
 * @property string $value_type
24
 * @property integer $property_handler_id
25
 * @property integer $has_static_values
26
 * @property integer $has_slugs_in_values
27
 * @property integer $is_eav
28
 * @property integer $is_column_type_stored
29
 * @property integer $multiple
30
 * @property integer $sort_order
31
 * @property string $handler_additional_params
32
 * @property integer $required
33
 * @property integer $interpret_as
34
 * @property integer $captcha
35
 * @property string $mask
36
 * @property integer $alias
37
 * @property PropertyGroup $group
38
 */
39
class Property extends ActiveRecord
40
{
41
    use GetImages;
42
43
    public static $identity_map = [];
44
    public static $group_id_to_property_ids = [];
45
    private $handlerAdditionalParams = [];
46
    public $required;
47
    public $interpret_as;
48
    public $captcha;
49
50
    /**
51
     * @inheritdoc
52
     */
53
    public function behaviors()
54
    {
55
        return [
56
            [
57
                'class' => AttributeBehavior::className(),
58
                'attributes' => [
59
                    ActiveRecord::EVENT_BEFORE_INSERT => 'sort_order',
60
                ],
61
                'value' => 0,
62
            ],
63
            [
64
                'class' => ActiveRecordHelper::className(),
65
            ],
66
            [
67
                'class' => HasProperties::className(),
68
            ],
69
        ];
70
    }
71
72
    /**
73
     * @inheritdoc
74
     */
75
    public static function tableName()
76
    {
77
        return '{{%property}}';
78
    }
79
80
    /**
81
     * @inheritdoc
82
     */
83
    public function rules()
84
    {
85
        return [
86
            [['property_group_id', 'name', 'property_handler_id', 'handler_additional_params'], 'required'],
87
            [
88
                [
89
                    'property_group_id',
90
                    'property_handler_id',
91
                    'has_static_values',
92
                    'has_slugs_in_values',
93
                    'is_eav',
94
                    'is_column_type_stored',
95
                    'multiple',
96
                    'sort_order',
97
                    'alias',
98
                ],
99
                'integer'
100
            ],
101
            [
102
                [
103
                    'display_only_on_depended_property_selected',
104
                    'depends_on_property_id',
105
                    'depends_on_category_group_id',
106
                    'hide_other_values_if_selected'
107
                ],
108
                'integer'
109
            ],
110
            [['interpret_as'], 'string'],
111
            [['name', 'handler_additional_params', 'depended_property_values', 'value_type', 'mask'], 'string'],
112
            [['key'], 'string', 'max' => 20],
113
            [['key'], 'match', 'pattern' => '#^[\w]+$#'],
114
            [['depends_on_property_id', 'depends_on_category_group_id'], 'default', 'value' => 0],
115
            [['required', 'captcha'], 'integer', 'min' => 0, 'max' => 1],
116
            [['dont_filter'], 'safe'],
117
            [['key'], 'unique', 'targetAttribute' => ['key', 'property_group_id']],
118
        ];
119
    }
120
121
    /**
122
     * @inheritdoc
123
     */
124
    public function attributeLabels()
125
    {
126
        return [
127
            'id' => Yii::t('app', 'ID'),
128
            'property_group_id' => Yii::t('app', 'Property Group ID'),
129
            'name' => Yii::t('app', 'Name'),
130
            'key' => Yii::t('app', 'Key'),
131
            'value_type' => Yii::t('app', 'Value Type'),
132
            'property_handler_id' => Yii::t('app', 'Property Handler ID'),
133
            'has_static_values' => Yii::t('app', 'Has Static Values'),
134
            'has_slugs_in_values' => Yii::t('app', 'Has Slugs In Values'),
135
            'is_eav' => Yii::t('app', 'Is Eav'),
136
            'is_column_type_stored' => Yii::t('app', 'Is Column Type Stored'),
137
            'multiple' => Yii::t('app', 'Multiple'),
138
            'sort_order' => Yii::t('app', 'Sort Order'),
139
            'handler_additional_params' => Yii::t('app', 'Handler Additional Params'),
140
            'required' => Yii::t('app', 'Required'),
141
            'interpret_as' => Yii::t('app', 'Interpret Field As'),
142
            'captcha' => Yii::t('app', 'Captcha'),
143
            'dont_filter' => Yii::t('app', 'Don\'t use in filtration'),
144
            'hide_other_values_if_selected' => Yii::t('app', 'Hide Other Values If Selected'),
145
            'display_only_on_depended_property_selected' => Yii::t('app', 'Display Only On Depended Property Selected'),
146
            'depends_on_property_id' => Yii::t('app', 'Depends On Property Id'),
147
            'depended_property_values' => Yii::t('app', 'Depended Property Values'),
148
            'depends_on_category_group_id' => Yii::t('app', 'Depends On Category Group Id'),
149
            'mask' => Yii::t('app', 'Mask'),
150
            'alias' => Yii::t('app', 'Alias'),
151
        ];
152
    }
153
154
    /**
155
     * Search tasks
156
     * @param $params
157
     * @return ActiveDataProvider
158
     */
159
    public function search($params)
160
    {
161
        /* @var $query \yii\db\ActiveQuery */
162
        $query = static::find()->where(['property_group_id' => $this->property_group_id]);
163
        $dataProvider = new ActiveDataProvider([
164
            'query' => $query,
165
            'pagination' => [
166
                'pageSize' => 10,
167
            ],
168
        ]);
169
        if (!($this->load($params))) {
170
            return $dataProvider;
171
        }
172
        $query->andFilterWhere(['id' => $this->id]);
173
        $query->andFilterWhere(['like', 'name', $this->name]);
174
        $query->andFilterWhere(['like', 'key', $this->key]);
175
        $query->andFilterWhere(['property_handler_id' => $this->property_handler_id]);
176
        $query->andFilterWhere(['has_static_values' => $this->has_static_values]);
177
        $query->andFilterWhere(['has_slugs_in_values' => $this->has_slugs_in_values]);
178
        $query->andFilterWhere(['is_eav' => $this->is_eav]);
179
        $query->andFilterWhere(['is_column_type_stored' => $this->is_column_type_stored]);
180
        $query->andFilterWhere(['multiple' => $this->multiple]);
181
        return $dataProvider;
182
    }
183
184
    /**
185
     * @return \yii\db\ActiveQuery
186
     */
187
    public function getGroup()
188
    {
189
        return $this->hasOne(PropertyGroup::className(), ['id' => 'property_group_id']);
190
    }
191
192
    /**
193
     * @return PropertyHandler
194
     */
195
    public function getHandler()
196
    {
197
//        return $this->hasOne(PropertyHandler::className(), ['id' => 'property_handler_id']);
0 ignored issues
show
Unused Code Comprehensibility introduced by
66% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
198
        return PropertyHandler::findById($this->property_handler_id);
199
    }
200
201
    /**
202
     * Возвращает модель по ID с использованием IdentityMap
203
     * @param int $id
204
     * @return null|Property
205
     */
206 View Code Duplication
    public static function findById($id)
207
    {
208
        if (!isset(static::$identity_map[$id])) {
209
            $cacheKey = "Property:$id";
210
            if (false === $prop = Yii::$app->cache->get($cacheKey)) {
211
                if (null === $prop = static::findOne($id)) {
212
                    return null;
213
                }
214
                Yii::$app->cache->set(
215
                    $cacheKey,
216
                    $prop,
217
                    0,
218
                    new TagDependency([
219
                        'tags' => [
220
                            ActiveRecordHelper::getObjectTag($prop, $id)
0 ignored issues
show
Documentation introduced by
$prop is of type array|boolean, but the function expects a string|object<yii\db\ActiveRecord>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
221
                        ],
222
                    ])
223
                );
224
            }
225
            static::$identity_map[$id] = $prop;
226
        }
227
        return static::$identity_map[$id];
228
    }
229
230
    /**
231
     * @param $group_id
232
     * @return null|array<Property>
233
     */
234
    public static function getForGroupId($group_id)
235
    {
236
        if (!isset(static::$group_id_to_property_ids[$group_id])) {
237
            $cacheKey = "PropsForGroup:$group_id";
238
            if (false === $props = Yii::$app->cache->get($cacheKey)) {
239
                if (null !== $props = static::find()->where(['property_group_id' => $group_id])->orderBy(
240
                        'sort_order'
241
                    )->all()
242
                ) {
243
                    Yii::$app->cache->set(
244
                        $cacheKey,
245
                        $props,
246
                        0,
247
                        new TagDependency([
248
                            'tags' => [
249
                                ActiveRecordHelper::getObjectTag(
250
                                    PropertyGroup::className(),
251
                                    $group_id
252
                                )
253
                            ],
254
                        ])
255
                    );
256
                }
257
            }
258
            static::$group_id_to_property_ids[$group_id] = [];
259
            foreach ($props as $property) {
260
                static::$identity_map[$property->id] = $property;
261
                static::$group_id_to_property_ids[$group_id][] = $property->id;
262
            }
263
            return $props;
264
        }
265
        $properties = [];
266
        foreach (static::$group_id_to_property_ids[$group_id] as $property_id) {
267
            $properties[] = static::findById($property_id);
268
        }
269
        return $properties;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $properties; (array) is incompatible with the return type documented by app\models\Property::getForGroupId of type null|app\models\Property[].

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
270
    }
271
272
    /**
273
     * @param $form
274
     * @param $model
275
     * @param $values
276
     * @param string $renderType
277
     * @return string
278
     */
279
    public function handler($form, $model, $values, $renderType = 'frontend_render_view')
280
    {
281
        $handler = $this->handler;
0 ignored issues
show
Bug introduced by
The property handler does not seem to exist. Did you mean handlerAdditionalParams?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
282
        if (null === $handler) {
283
            return '';
284
        }
285
        $handler = PropertyHandlers::createHandler($handler);
286
        if (null === $handler) {
287
            return '';
288
        }
289
        return $handler->render($this, $model, $values, $form, $renderType);
290
    }
291
292
    /**
293
     * @inheritdoc
294
     */
295
    public function afterFind()
296
    {
297
        parent::afterFind();
298
        $this->handlerAdditionalParams = Json::decode($this->handler_additional_params);
0 ignored issues
show
Documentation Bug introduced by
It seems like \yii\helpers\Json::decod...dler_additional_params) of type * is incompatible with the declared type array of property $handlerAdditionalParams.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
299
        $this->required = isset($this->handlerAdditionalParams['rules']) && is_array(
300
                $this->handlerAdditionalParams['rules']
301
            ) && in_array('required', $this->handlerAdditionalParams['rules']);
302
        $this->interpret_as = isset($this->handlerAdditionalParams['interpret_as']) ? $this->handlerAdditionalParams['interpret_as'] : 0;
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 137 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
303
        if (isset($this->handlerAdditionalParams['rules']) && is_array($this->handlerAdditionalParams['rules'])) {
304
            foreach ($this->handlerAdditionalParams['rules'] as $rule) {
305
                if (is_array($rule)) {
306
                    if (in_array('captcha', $rule, true)) {
307
                        $this->captcha = true;
308
                    }
309
                } else {
310
                    switch ($rule) {
311
                        case 'required':
312
                            $this->required = true;
313
                            break;
314
                    }
315
                }
316
            }
317
        }
318
    }
319
320
    /**
321
     * @inheritdoc
322
     * @param bool $insert
323
     * @return bool
324
     */
325
    public function beforeSave($insert)
326
    {
327
        if (!parent::beforeSave($insert)) {
328
            return false;
329
        }
330
        $handlerAdditionalParams = $this->isNewRecord ? [] : Json::decode($this->handler_additional_params);
331
        $handlerRules = [];
332
        if (1 === intval($this->required)) {
333
            $handlerRules[] = 'required';
334
        }
335
        if (PropertyHandler::findByName('File') === intval($this->property_handler_id)) {
336
            if (1 === intval($this->multiple)) {
337
                $handlerRules[] = ['file', 'maxFiles' => 0];
338
            } else {
339
                $handlerRules[] = ['file', 'maxFiles' => 1];
340
            }
341
        }
342
        if (1 === intval($this->captcha)) {
343
            $handlerRules[] = ['captcha', 'captchaAction' => '/default/captcha'];
344
        }
345
        $handlerAdditionalParams['interpret_as'] = $this->interpret_as;
346
        $handlerAdditionalParams['rules'] = $handlerRules;
347
        $this->handlerAdditionalParams = $handlerAdditionalParams;
0 ignored issues
show
Documentation Bug introduced by
It seems like $handlerAdditionalParams of type * is incompatible with the declared type array of property $handlerAdditionalParams.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
348
        $this->handler_additional_params = Json::encode($handlerAdditionalParams);
349
        return true;
350
    }
351
352
    /**
353
     *
354
     */
355
    public function invalidateModelCache()
356
    {
357
        TagDependency::invalidate(
358
            Yii::$app->cache,
359
            [
360
                ActiveRecordHelper::getObjectTag(
361
                    PropertyGroup::className(),
362
                    $this->property_group_id
363
                ),
364
                ActiveRecordHelper::getObjectTag(Property::className(), $this->id)
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
365
            ]
366
        );
367
    }
368
369
    /**
370
     * @param bool $insert
371
     * @param array $changedAttributes
372
     */
373
    public function afterSave($insert, $changedAttributes)
374
    {
375
        // @todo clear table schema
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
376
        $this->invalidateModelCache();
377
        parent::afterSave($insert, $changedAttributes);
378
    }
379
380
    /**
381
     * @return bool
382
     */
383
    public function beforeDelete()
384
    {
385
        $this->invalidateModelCache();
386
        return parent::beforeDelete();
387
    }
388
389
    public function afterDelete()
390
    {
391
        $object = Object::findById($this->group->object_id);
392
        $staticValues = PropertyStaticValues::find()->where(['property_id' => $this->id])->all();
393
        foreach ($staticValues as $psv) {
394
            $psv->delete();
395
        }
396
        if (null !== $object) {
397
            if ($this->is_eav) {
398
                Yii::$app->db->createCommand()->delete(
399
                    $object->eav_table_name,
400
                    ['key' => $this->key, 'property_group_id' => $this->group->id]
401
                )->execute();
402
            }
403
            if ($this->is_column_type_stored) {
404
                Yii::$app->db->createCommand()->dropColumn($object->column_properties_table_name, $this->key)->execute();
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 121 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
405
                //                if ($object->object_class == Form::className()) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
406
                //                    $submissionObject = Object::getForClass(Submission::className());
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
407
                //                    Yii::$app->db->createCommand()
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
408
                //                        ->dropColumn($submissionObject->column_properties_table_name, $this->key)
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
409
                //                        ->execute();
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
410
                //                }
411
            }
412
        }
413
        FilterSets::deleteAll(['property_id' => $this->id]);
414
        parent::afterDelete();
415
    }
416
417
    /**
418
     * @param $name
419
     * @return null|mixed
420
     */
421
    public function getAdditionalParam($name)
422
    {
423
        if (isset($this->handlerAdditionalParams[$name])) {
424
            return $this->handlerAdditionalParams[$name];
425
        }
426
        return null;
427
    }
428
429
    /**
430
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use string[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
431
     */
432
    public static function getAliases()
433
    {
434
        return [
435
            0 => Yii::t('app', 'Not selected'),
436
            1 => 'date',
437
            2 => 'ip',
438
            3 => 'url',
439
            4 => 'email',
440
        ];
441
    }
442
}