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.

HasProperties::getEavRows()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 30
rs 9.44
c 0
b 0
f 0
cc 3
nc 3
nop 0
1
<?php
2
3
namespace app\properties;
4
5
use app\models\BaseObject;
6
use app\models\ObjectPropertyGroup;
7
use app\models\ObjectStaticValues;
8
use app\models\Property;
9
use app\models\PropertyGroup;
10
use app\models\PropertyStaticValues;
11
use app\modules\core\helpers\ContentBlockHelper;
12
use app\modules\core\models\ContentBlock;
13
use devgroup\TagDependencyHelper\ActiveRecordHelper;
14
use Yii;
15
use yii\base\Behavior;
16
use yii\caching\TagDependency;
17
use yii\db\ActiveRecord;
18
use yii\db\AfterSaveEvent;
19
use yii\db\Query;
20
use yii\helpers\ArrayHelper;
21
use yii\helpers\Json;
22
23
/**
24
 * Class HasProperties
25
 * @property \yii\db\ActiveRecord $owner
26
 * @property $object Object
27
 * @package app\properties
28
 */
29
class HasProperties extends Behavior
30
{
31
    const FIELD_ADD_PROPERTY_GROUP = 'AddPropertyGroup';
32
    const FIELD_REMOVE_PROPERTY_GROUP = 'RemovePropertyGroup';
33
    const FIELD_ADD_PROPERTY = 'AddProperty';
34
    /**
35
     * @var AbstractModel
36
     */
37
    private $abstract_model = null;
38
    private $eav_rows = null;
39
    private $object = null;
40
    private $properties = null;
41
    private $property_key_to_id = [];
42
    private $property_id_to_group_id = [];
43
    private $static_values = null;
44
    private $table_inheritance_row = null;
45
    private $propertiesFormName = null;
46
    public $props;
47
48
    /**
49
     * Get property group id by property id
50
     * @param int $id property id
51
     * @return int property group id
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
52
     */
53
    private function getGroupIdBypropertyId($id)
54
    {
55
        foreach ($this->property_id_to_group_id as $groupId => $propertyIds) {
56
            if (in_array($id, $propertyIds)) {
57
                return $groupId;
58
            }
59
        }
60
        $property = Property::findById($id);
61
        if (!array_key_exists($property->property_group_id, $this->property_id_to_group_id)) {
62
            $this->property_id_to_group_id[$property->property_group_id] = [$id];
63
        } else {
64
            $this->property_id_to_group_id[$property->property_group_id][] = $id;
65
        }
66
        return intval($property->property_group_id);
67
    }
68
69
    public function getObject()
70
    {
71
        if ($this->object === null) {
72
            $this->object = BaseObject::getForClass(get_class($this->owner));
73
            if ($this->object === null) {
74
                throw new \Exception("Can't find Object row for ".get_class($this->owner));
75
            }
76
        }
77
        return $this->object;
78
    }
79
80
    public function getPropertyGroups($force = false, $getByObjectId = false, $createAbstractModel = false)
81
    {
82
        $message = "getPropertyGroups ". $this->owner->className() . ':'.$this->owner->id.
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
83
            " force:".($force?'true':'false').
84
            " getByObjectId:".($getByObjectId?'true':'false') .
85
            " createAbstractModel:".($createAbstractModel?'true':'false');
86
        Yii::trace(
0 ignored issues
show
Deprecated Code introduced by
The method yii\BaseYii::trace() has been deprecated with message: since 2.0.14. Use [[debug()]] instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
87
            $message,
88
            'properties'
89
        );
90
        $cacheKey = $message;
91
92
93
        if ($this->properties === null && $force === false) {
94
            // try to get from cache
95
            $data = Yii::$app->cache->get($message);
96
            if ($data !== false) {
97
                Yii::trace("Properties from cache", 'properties');
0 ignored issues
show
Deprecated Code introduced by
The method yii\BaseYii::trace() has been deprecated with message: since 2.0.14. Use [[debug()]] instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
98
                $this->abstract_model = isset($data['abstract_model'])?$data['abstract_model']:[];
99
                $this->properties = $data['properties'];
100
                $this->property_key_to_id = $data['property_key_to_id'];
101
                $this->property_id_to_group_id = $data['property_id_to_group_id'];
102
            }
103
        }
104
105
        if ($createAbstractModel === true && is_null($this->abstract_model)) {
106
            // force creating abstract model if it is null and needed
107
            $force = true;
108
        }
109
110
        if ($this->properties === null || $force === true) {
111
            $tags = [ActiveRecordHelper::getObjectTag($this->owner->className(), $this->owner->id)];
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
112
            $this->properties = [];
113
            if ($getByObjectId === true) {
114
                $groups = PropertyGroup::getForObjectId($this->getObject()->id);
115
            } else {
116
                $groups = PropertyGroup::getForModel($this->getObject()->id, $this->owner->id);
117
            }
118
            $values_for_abstract = [];
119
            $properties_models = [];
120
            $rules = [];
121
            /** @var PropertyGroup $group */
122
            foreach ($groups as $group) {
123
                $tags[] = ActiveRecordHelper::getObjectTag(PropertyGroup::className(), $group->id);
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
124
                $this->properties[$group->id] = [];
125
                $props = Property::getForGroupId($group->id);
126
                foreach ($props as $p) {
127
                    $values = $this->getPropertyValues($p);
128
                    $this->properties[$group->id][$p->key] = $values;
129
130
                    if ($createAbstractModel === true) {
131
                        $values_for_abstract[$p->key] = $values;
132
                    }
133
134
                    $properties_models[$p->key] = $p;
135
                    $this->property_key_to_id[$p->key] = $p->id;
136
                    if (!isset($this->property_id_to_group_id[$group->id])) {
137
                        $this->property_id_to_group_id[$group->id] = [$p->key];
138
                    } else {
139
                        $this->property_id_to_group_id[$group->id][] = $p->key;
140
                    }
141
142
                    if ($createAbstractModel === true) {
143
                        $handlerAdditionalParams = Json::decode($p->handler_additional_params);
144
                        if (isset($handlerAdditionalParams['rules']) && is_array($handlerAdditionalParams['rules'])) {
145
                            foreach ($handlerAdditionalParams['rules'] as $rule) {
146
                                if (is_array($rule)) {
147
                                    $rules[] = ArrayHelper::merge([$p->key], $rule);
148
                                } else {
149
                                    $rules[] = [$p->key, $rule];
150
                                }
151
                            }
152
                        }
153
                    }
154
                }
155
            }
156
157
            if ($createAbstractModel === true) {
158
                $this->abstract_model = new AbstractModel([], $this->owner);
159
                $this->abstract_model->setPropertiesModels($properties_models);
160
                $this->abstract_model->setAttributes($values_for_abstract);
161
                $this->abstract_model->setFormName('Properties_' . $this->owner->formName() . '_' . $this->owner->id);
162
                $this->abstract_model->addRules($rules);
163
            }
164
165
            $res = Yii::$app->cache->set(
166
                $cacheKey,
167
                [
168
                    'properties' => $this->properties,
169
                    'abstract_model' => $this->abstract_model,
170
                    'property_id_to_group_id' => $this->property_id_to_group_id,
171
                    'property_key_to_id' => $this->property_key_to_id,
172
                ],
173
                86400,
174
                new TagDependency([
175
                    'tags' => $tags,
176
                ])
177
            );
178
            Yii::trace('putting props to cache: ' . ($res?'true':'false') . ' key:' . $cacheKey, 'properties');
0 ignored issues
show
Deprecated Code introduced by
The method yii\BaseYii::trace() has been deprecated with message: since 2.0.14. Use [[debug()]] instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
179
        }
180
        return $this->properties;
181
    }
182
183
    /**
184
     * Adds property group to object instance
185
     *
186
     * @param int|string $property_group_id Id of Property Group
187
     * @param bool $refreshProperties
188
     * @throws \Exception
189
     * @throws \yii\db\Exception
190
     */
191
    public function addPropertyGroup($property_group_id, $refreshProperties = true, $createAbstractModel = false)
192
    {
193
        $params = [];
194
        $where = [
195
            'object_id' => $this->getObject()->id,
196
            'object_model_id' => $this->owner->id,
197
            'property_group_id' => $property_group_id,
198
        ];
199
        if (null === ObjectPropertyGroup::findOne($where)) {
200
            $sql = Yii::$app->db->queryBuilder->insert(
201
                ObjectPropertyGroup::tableName(),
202
                $where,
203
                $params
204
            );
205
206
            Yii::$app->db->createCommand(
207
                $sql,
208
                $params
209
            )->execute();
210
        }
211
        if ($refreshProperties === true) {
212
            $this->updatePropertyGroupsInformation($createAbstractModel);
213
        }
214
    }
215
216
    public function removePropertyGroup($property_group_id)
217
    {
218
        ObjectPropertyGroup::deleteAll(
219
            [
220
                'object_id' => $this->getObject()->id,
221
                'object_model_id' => $this->owner->id,
222
                'property_group_id' => $property_group_id,
223
            ]
224
        );
225
    }
226
227
    public function setPropertiesFormName($name = null)
228
    {
229
        $this->propertiesFormName = $name;
230
    }
231
232
    public function saveProperties($data)
233
    {
234
        $form = $this->owner->formName();
235
        $formProperties = empty($this->propertiesFormName)
236
            ? 'Properties_'.$form.'_'.$this->owner->id
237
            : $this->propertiesFormName;
238
239
        $this->getPropertyGroups();
240
        if (isset($data[self::FIELD_ADD_PROPERTY_GROUP]) && isset($data[self::FIELD_ADD_PROPERTY_GROUP][$form])) {
241
            $groups_to_add = is_array($data[self::FIELD_ADD_PROPERTY_GROUP][$form])
242
                ? $data[self::FIELD_ADD_PROPERTY_GROUP][$form]
243
                : [$data[self::FIELD_ADD_PROPERTY_GROUP][$form]];
244
            foreach ($groups_to_add as $group_id) {
245
                $this->addPropertyGroup($group_id, false);
246
            }
247
            $this->updatePropertyGroupsInformation(true);
248
        }
249
        if (isset($data[self::FIELD_REMOVE_PROPERTY_GROUP]) && isset($data[self::FIELD_REMOVE_PROPERTY_GROUP][$form])) {
250
            $this->removePropertyGroup($data[self::FIELD_REMOVE_PROPERTY_GROUP][$form]);
251
        }
252
        if (isset($data[$formProperties])) {
253
            $my_data = $data[$formProperties];
254
255
            if (isset($data[self::FIELD_ADD_PROPERTY])) {
256
                // admin clicked add property button for multiple properties
257
                if (!isset($my_data[$data[self::FIELD_ADD_PROPERTY]])) {
258
                    $my_data[$data[self::FIELD_ADD_PROPERTY]] = [];
259
                }
260
                $my_data[$data[self::FIELD_ADD_PROPERTY]][] = '';
261
            }
262
263
            $propertiesModels = $this->getAbstractModel()->getPropertiesModels();
264
265
            $new_values_for_abstract = [];
266
            foreach ($my_data as $property_key => $values) {
267
                if (isset($this->property_key_to_id[$property_key])) {
268
                    $vals = [];
269
                    $property_id = $this->property_key_to_id[$property_key];
270
                    $values = is_array($values) ? $values : [$values];
271
272
                    if (isset($propertiesModels[$property_key])) {
273
                        $_property = $propertiesModels[$property_key];
274
                        $propertyHandler = PropertyHandlers::getHandlerById($_property->property_handler_id);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $propertyHandler is correct as \app\properties\Property...y->property_handler_id) (which targets app\properties\PropertyHandlers::getHandlerById()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
275
                        if (null === $propertyHandler) {
276
                            $propertyHandler = PropertyHandlers::createHandler($_property->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...
277
                        }
278
279
                        $values = $propertyHandler->processValues($_property, $formProperties, $values);
280
                    }
281
282
                    foreach ($values as $index => $val) {
283
                        $vals[] = ['value' => $val, 'property_id' => $property_id, 'sort_order' => $index];
284
                    }
285
286
                    $val = new PropertyValue(
287
                        $vals,
288
                        $property_id,
289
                        $this->getObject()->id,
290
                        $this->owner->id,
291
                        $this->getGroupIdBypropertyId($property_id)
292
                    );
293
                    $new_values_for_abstract[$property_key] = $val;
294
                }
295
            }
296
297
            $this->abstract_model->updateValues($new_values_for_abstract, $this->getObject()->id, $this->owner->id);
298
            $this->owner->trigger(ActiveRecord::EVENT_AFTER_UPDATE, new AfterSaveEvent(['changedAttributes' => []]));
299
        }
300
    }
301
302
    public function updatePropertyGroupsInformation($createAbstractModel = false)
303
    {
304
        $this->owner->invalidateTags();
0 ignored issues
show
Bug introduced by
The method invalidateTags() does not exist on yii\db\ActiveRecord. Did you maybe mean validate()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
305
        $this->table_inheritance_row = null;
306
        $this->eav_rows = null;
307
        $this->static_values = null;
308
        $this->abstract_model = null;
309
        $this->property_key_to_id = [];
310
        $this->getPropertyGroups(true, false, $createAbstractModel);
311
    }
312
313
    public function getAbstractModel()
314
    {
315
        if (empty($this->abstract_model)) {
316
            $this->getPropertyGroups(!is_object($this->abstract_model), false, true);
317
        }
318
        return $this->abstract_model;
319
    }
320
321
    public function setAbstractModel(AbstractModel $model)
322
    {
323
        $this->abstract_model = $model;
324
    }
325
326
    /**
327
     * Get PropertyValue model by key. It consists object property values
328
     * @param string $key
329
     * @return PropertyValue
330
     */
331 View Code Duplication
    public function getPropertyValuesByKey($key)
332
    {
333
        $this->getPropertyGroups();
334
        foreach ($this->properties as $group_id => $group) {
335
            foreach ($group as $property_key => $value) {
336
                if ($property_key === $key) {
337
                    return $value;
338
                }
339
            }
340
        }
341
        return null;
342
    }
343
344
    /**
345
     * Get property values by key.
346
     * @param $key
347
     * @param bool $asString
348
     * @param string $delimiter
349
     * @return array|string
350
     */
351
    public function property($key, $asString = true, $delimiter = ', ')
352
    {
353
        $values = [];
354
        $propertyValue = $this->getPropertyValuesByKey($key);
355
        if (is_null($propertyValue)) {
356
            return $asString ? '' : [];
357
        }
358
        foreach ($propertyValue->values as $value) {
359
            $values[] = $value['value'];
360
        }
361
        if ($asString) {
362
            return ContentBlockHelper::compileContentString(
363
                implode($delimiter, $values),
364
                "{$this->owner->className()}:{$this->owner->id}:property={$key}",
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
365
                new TagDependency(
366
                    [
367
                        'tags' => [
368
                            $this->owner->objectTag(),
369
                            ActiveRecordHelper::getCommonTag(ContentBlock::className())
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
370
                        ]
371
                    ]
372
                )
373
            );
374
        } else {
375
            return $values;
376
        }
377
    }
378
379 View Code Duplication
    public function getPropertyValuesByPropertyId($property_id)
380
    {
381
        $this->getPropertyGroups();
382
        foreach ($this->properties as $group_id => $group) {
383
            foreach ($group as $property_key => $value) {
384
                if ($value->property_id == $property_id) {
385
                    return $value;
386
                }
387
            }
388
        }
389
        return null;
390
    }
391
392
    private function getPropertyValues($property)
393
    {
394
        $values = [];
395
        if ($property->is_column_type_stored) {
396
            $row = $this->getTableInheritanceRow();
397
            if (isset($row[$property->key])) {
398
                $values[] = [
399
                    'value' => $row[$property->key],
400
                    'property_id' => $property->id,
401
                ];
402
            }
403
        } elseif ($property->has_static_values) {
404
            $static_values = $this->getStaticValues();
405
            if (isset($static_values[$property->id])) {
406
                $values = $static_values[$property->id];
407
            }
408
        } elseif ($property->is_eav) {
409
            foreach ($this->getEavRows() as $row) {
410
                if ($row['key'] === $property->key) {
411
                    $values[] = $row;
412
                }
413
            }
414
415
        }
416
        return new PropertyValue($values, $property->id, $this->getObject()->id, $this->owner->id);
417
    }
418
419
    private function getEavRows()
420
    {
421
        if ($this->eav_rows === null) {
422
            $cacheKey = md5("EAV_ROWS:".$this->getObject()->eav_table_name.":".$this->owner->id);
423
424
            $this->eav_rows = Yii::$app->cache->get($cacheKey);
425
426
            if ($this->eav_rows === false) {
427
                $this->eav_rows =
428
                    (new Query())
429
                        ->select('`key`, value, sort_order, id as eav_id')
430
                        ->from($this->getObject()->eav_table_name)
431
                        ->where(['object_model_id' => $this->owner->id])
432
                        ->orderBy('sort_order')
433
                        ->all();
434
435
                Yii::$app->cache->set(
436
                    $cacheKey,
437
                    $this->eav_rows,
438
                    86400,
439
                    new TagDependency([
440
                        'tags' => [
441
                            ActiveRecordHelper::getObjectTag($this->owner->className(), $this->owner->id)
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
442
                        ]
443
                    ])
444
                );
445
            }
446
        }
447
        return $this->eav_rows;
448
    }
449
450
    private function getTableInheritanceRow()
451
    {
452
        if ($this->table_inheritance_row === null) {
453
            $cacheKey = "TIR:" . $this->getObject()->id . ':' . $this->owner->id;
454
            $this->table_inheritance_row = Yii::$app->cache->get($cacheKey);
455
            if (!is_array($this->table_inheritance_row)) {
456
                $this->table_inheritance_row = (new Query())
457
                    ->select('*')
458
                    ->from($this->getObject()->column_properties_table_name)
459
                    ->where(['object_model_id' => $this->owner->id])
460
                    ->one();
461
                if (!is_array($this->table_inheritance_row)) {
462
                    $this->table_inheritance_row = [];
463
                }
464
                Yii::$app->cache->set(
465
                    $cacheKey,
466
                    $this->table_inheritance_row,
467
                    86400,
468
                    new TagDependency(
469
                        [
470
                            'tags' => [
471
                                ActiveRecordHelper::getObjectTag($this->owner, $this->owner->id),
472
                            ],
473
                        ]
474
                    )
475
                );
476
            }
477
        }
478
        return $this->table_inheritance_row;
479
    }
480
481
    private function getStaticValues()
482
    {
483
        if ($this->static_values === null) {
484
            $cacheKey = "PSV:" . $this->getObject()->id . ":" . $this->owner->id;
485
            $array = Yii::$app->cache->get($cacheKey);
486
            if (!is_array($array)) {
487
                $array = (new Query())
488
                    ->select("PSV.property_id, PSV.value, PSV.slug, PSV.name, PSV.id as psv_id")
489
                    ->from(ObjectStaticValues::tableName() . " OSV")
490
                    ->innerJoin(PropertyStaticValues::tableName() . " PSV", "PSV.id = OSV.property_static_value_id")
491
                    ->where(
492
                        [
493
                            'OSV.object_id' => $this->getObject()->id,
494
                            'OSV.object_model_id' => $this->owner->id,
495
                        ]
496
                    )->orderBy('PSV.sort_order')
497
                    ->all();
498
                Yii::$app->cache->set(
499
                    $cacheKey,
500
                    $array,
501
                    86400,
502
                    new TagDependency(
503
                        [
504
                            'tags' => [
505
                                ActiveRecordHelper::getObjectTag($this->owner, $this->owner->id),
506
                            ],
507
                        ]
508
                    )
509
                );
510
            }
511
            $this->static_values = [];
512
            foreach ($array as $row) {
513
                $this->static_values[$row['property_id']][$row['value']] = $row;
514
            }
515
        }
516
        return $this->static_values;
517
    }
518
}
519