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 |
||
| 29 | class PropertyStaticValues extends ActiveRecord |
||
| 30 | { |
||
| 31 | use GetImages; |
||
| 32 | |||
| 33 | public static $identity_map_by_property_id = []; |
||
| 34 | private static $identity_map = []; |
||
| 35 | |||
| 36 | use SortModels; |
||
| 37 | |||
| 38 | /** |
||
| 39 | * @inheritdoc |
||
| 40 | */ |
||
| 41 | public function behaviors() |
||
| 42 | { |
||
| 43 | return [ |
||
| 44 | [ |
||
| 45 | 'class' => AttributeBehavior::className(), |
||
| 46 | 'attributes' => [ |
||
| 47 | \yii\db\ActiveRecord::EVENT_BEFORE_INSERT => 'sort_order', |
||
| 48 | ], |
||
| 49 | 'value' => 0, |
||
| 50 | ], |
||
| 51 | [ |
||
| 52 | 'class' => ActiveRecordHelper::className(), |
||
| 53 | ], |
||
| 54 | [ |
||
| 55 | 'class' => HasProperties::className(), |
||
| 56 | ], |
||
| 57 | ]; |
||
| 58 | } |
||
| 59 | |||
| 60 | /** |
||
| 61 | * @inheritdoc |
||
| 62 | */ |
||
| 63 | public static function tableName() |
||
| 67 | |||
| 68 | /** |
||
| 69 | * @inheritdoc |
||
| 70 | */ |
||
| 71 | View Code Duplication | public function rules() |
|
| 72 | { |
||
| 73 | return [ |
||
| 74 | [['property_id', 'name', 'value'], 'required'], |
||
| 75 | [['property_id', 'sort_order', 'dont_filter'], 'integer'], |
||
| 76 | [['title_prepend'], 'boolean'], |
||
| 77 | [['name', 'value', 'slug', 'title_append'], 'string'] |
||
| 78 | ]; |
||
| 79 | } |
||
| 80 | |||
| 81 | /** |
||
| 82 | * @inheritdoc |
||
| 83 | */ |
||
| 84 | public function attributeLabels() |
||
| 85 | { |
||
| 86 | return [ |
||
| 87 | 'id' => Yii::t('app', 'ID'), |
||
| 88 | 'property_id' => Yii::t('app', 'Property ID'), |
||
| 89 | 'name' => Yii::t('app', 'Name'), |
||
| 90 | 'value' => Yii::t('app', 'Value'), |
||
| 91 | 'slug' => Yii::t('app', 'Slug'), |
||
| 92 | 'sort_order' => Yii::t('app', 'Sort Order'), |
||
| 93 | 'title_append' => Yii::t('app', 'Title append'), |
||
| 94 | 'title_prepend' => Yii::t('app', 'Prepend title?'), |
||
| 95 | 'dont_filter' => Yii::t('app', 'Don\'t filter (for FilterWidget only)'), |
||
| 96 | ]; |
||
| 97 | } |
||
| 98 | |||
| 99 | /** |
||
| 100 | * Search tasks |
||
| 101 | * @param $params |
||
| 102 | * @return ActiveDataProvider |
||
| 103 | */ |
||
| 104 | View Code Duplication | public function search($params) |
|
| 105 | { |
||
| 106 | $query = static::find()->where(['property_id' => $this->property_id]); |
||
| 107 | $dataProvider = new ActiveDataProvider( |
||
| 108 | [ |
||
| 109 | 'query' => $query, |
||
| 110 | 'pagination' => [ |
||
| 111 | 'pageSize' => 10, |
||
| 112 | ], |
||
| 113 | ] |
||
| 114 | ); |
||
| 115 | if (!($this->load($params))) { |
||
| 116 | return $dataProvider; |
||
| 117 | } |
||
| 118 | $query->andFilterWhere(['id' => $this->id]); |
||
| 119 | $query->andFilterWhere(['like', 'name', $this->name]); |
||
| 120 | $query->andFilterWhere(['like', 'value', $this->value]); |
||
| 121 | $query->andFilterWhere(['like', 'slug', $this->slug]); |
||
| 122 | return $dataProvider; |
||
| 123 | } |
||
| 124 | |||
| 125 | public function getProperty() |
||
| 129 | |||
| 130 | /** |
||
| 131 | * Возвращает Массив! по ID с использованием IdentityMap |
||
| 132 | * @param int $id |
||
| 133 | * @return null|PropertyStaticValues |
||
| 134 | */ |
||
| 135 | View Code Duplication | public static function findById($id) |
|
| 163 | |||
| 164 | /** |
||
| 165 | * Возвращает массив возможных значений свойств по property_id |
||
| 166 | * Внимание! Это массивы, а не объекты! |
||
| 167 | * Это сделано для экономии памяти. |
||
| 168 | * Используется identity_map |
||
| 169 | * |
||
| 170 | * @return array |
||
| 171 | */ |
||
| 172 | public static function getValuesForPropertyId($property_id) |
||
| 182 | |||
| 183 | public static function getSelectForPropertyId($property_id) |
||
| 192 | |||
| 193 | /** |
||
| 194 | * @param $property_id |
||
| 195 | * @param $category_id |
||
| 196 | * @param $properties |
||
| 197 | * @return PropertyStaticValues[] |
||
| 198 | */ |
||
| 199 | public static function getValuesForFilter($property_id, $category_id, $properties, $multiple = false, $parentsOnly = true) |
||
| 200 | { |
||
| 201 | $priceMin = Yii::$app->request->get('price_min'); |
||
| 202 | $priceMax = Yii::$app->request->get('price_max'); |
||
| 203 | $cacheKey = "getValuesForFilter:" . json_encode([$property_id, $category_id, $properties, $priceMin, $priceMax]); |
||
| 204 | if (false === $allSelections = Yii::$app->cache->get($cacheKey)) { |
||
| 205 | $joinCondition = (true === $parentsOnly) ? |
||
| 206 | 'p.id = {{%product_category}}.object_model_id AND p.active = 1 AND p.parent_id = 0' |
||
| 207 | : 'p.id = {{%product_category}}.object_model_id AND p.active = 1'; |
||
| 208 | $objectModel = Object::getForClass(Product::className()); |
||
| 209 | $objectId = $objectModel !== null ? $objectModel->id : 0; |
||
| 210 | $allSelections = static::find() |
||
| 211 | ->asArray(true) |
||
| 212 | ->select([self::tableName() . '.id', self::tableName() . '.name', 'value', self::tableName() . '.slug']) |
||
| 213 | ->innerJoin( |
||
| 214 | ObjectStaticValues::tableName(), |
||
| 215 | ObjectStaticValues::tableName() . '.property_static_value_id=' . self::tableName() . '.id' |
||
| 216 | ) |
||
| 217 | ->innerJoin( |
||
| 218 | '{{%product_category}}', |
||
| 219 | '{{%product_category}}.object_model_id = ' . ObjectStaticValues::tableName() . '.object_model_id' |
||
| 220 | ) |
||
| 221 | ->innerJoin( |
||
| 222 | Product::tableName() . ' p', |
||
| 223 | $joinCondition |
||
| 224 | ) |
||
| 225 | ->where( |
||
| 226 | [ |
||
| 227 | self::tableName() . '.property_id' => $property_id, |
||
| 228 | self::tableName() . '.dont_filter' => 0, |
||
| 229 | '{{%product_category}}.category_id' => $category_id, |
||
| 230 | ] |
||
| 231 | ) |
||
| 232 | ->orderBy( |
||
| 233 | [ |
||
| 234 | self::tableName() . '.sort_order' => SORT_ASC, |
||
| 235 | self::tableName() . '.name' => SORT_ASC, |
||
| 236 | ] |
||
| 237 | ) |
||
| 238 | ->all(); |
||
| 239 | /** @var ActiveQuery $query */ |
||
| 240 | $query = ObjectStaticValues::find() |
||
| 241 | ->distinct(true) |
||
| 242 | ->select(ObjectStaticValues::tableName() . '.object_model_id') |
||
| 243 | ->where(['object_id' => $objectId]); |
||
| 244 | if (false === empty($properties)) { |
||
| 245 | foreach ($properties as $propertyId => $propertyStaticValues) { |
||
| 246 | $subQuery = self::initSubQuery($category_id, $joinCondition); |
||
| 247 | $subQuery->andWhere(['property_static_value_id' => $propertyStaticValues,]); |
||
| 248 | View Code Duplication | $subQueryOptimisation = Yii::$app->db->cache(function($db) use ($subQuery) { |
|
| 249 | $ids = implode(', ', $subQuery->createCommand($db)->queryColumn()); |
||
| 250 | return empty($ids) === true ? '(-1)' : "($ids)"; |
||
| 251 | }, 86400, new TagDependency([ |
||
| 252 | 'tags' => [ |
||
| 253 | ActiveRecordHelper::getCommonTag(ObjectStaticValues::className()), |
||
| 254 | ] |
||
| 255 | ])); |
||
| 256 | $query->andWhere(new Expression('`object_model_id` IN ' . $subQueryOptimisation)); |
||
| 257 | } |
||
| 258 | } |
||
| 259 | if (false === empty($priceMin) && false === empty($priceMax)) { |
||
| 260 | $subQuery = self::initSubQuery($category_id, $joinCondition); |
||
| 261 | $subQuery |
||
| 262 | ->andWhere(['>=', 'p.price', $priceMin]) |
||
| 263 | ->andWhere(['<=', 'p.price', $priceMax]); |
||
| 264 | View Code Duplication | $subQueryOptimisation = Yii::$app->db->cache(function($db) use ($subQuery) { |
|
| 265 | $ids = implode(', ', $subQuery->createCommand($db)->queryColumn()); |
||
| 266 | return empty($ids) === true ? '(-1)' : "($ids)"; |
||
| 267 | }, 86400, new TagDependency([ |
||
| 268 | 'tags' => [ |
||
| 269 | ActiveRecordHelper::getCommonTag(ObjectStaticValues::className()), |
||
| 270 | ] |
||
| 271 | ])); |
||
| 272 | $query->andWhere(new Expression('`object_model_id` IN ' . $subQueryOptimisation)); |
||
| 273 | } |
||
| 274 | $selectedQuery = static::find() |
||
| 275 | ->select(static::tableName() . '.id') |
||
| 276 | ->asArray(true) |
||
| 277 | ->innerJoin( |
||
| 278 | ObjectStaticValues::tableName(), |
||
| 279 | ObjectStaticValues::tableName() . '.property_static_value_id = ' . static::tableName() . '.id' |
||
| 280 | ) |
||
| 281 | ->where([ |
||
| 282 | 'property_id' => $property_id, |
||
| 283 | ]) |
||
| 284 | ->andWhere( |
||
| 285 | new Expression( |
||
| 286 | ObjectStaticValues::tableName() . '.object_model_id IN (' . $query->createCommand()->getRawSql() . ')' |
||
| 287 | ) |
||
| 288 | ); |
||
| 289 | if (false == $multiple) { |
||
| 290 | if (isset($properties[$property_id])) { |
||
| 291 | $selectedQuery->andWhere([self::tableName() . '.id' => $properties[$property_id]]); |
||
| 292 | } |
||
| 293 | } else { |
||
| 294 | unset($properties[$property_id]); |
||
| 295 | } |
||
| 296 | $selected = $selectedQuery->column(); |
||
| 297 | foreach ($allSelections as $index => $selection) { |
||
| 298 | $allSelections[$index]['active'] = in_array($selection['id'], $selected); |
||
| 299 | } |
||
| 300 | View Code Duplication | if (null !== $allSelections) { |
|
| 301 | Yii::$app->cache->set( |
||
| 302 | $cacheKey, |
||
| 303 | $allSelections, |
||
| 304 | 0, |
||
| 305 | new TagDependency( |
||
| 306 | [ |
||
| 307 | 'tags' => [ |
||
| 308 | ActiveRecordHelper::getCommonTag(PropertyStaticValues::className()), |
||
| 309 | ActiveRecordHelper::getCommonTag(Property::className()), |
||
| 310 | ] |
||
| 311 | |||
| 312 | ] |
||
| 313 | ) |
||
| 314 | ); |
||
| 315 | } |
||
| 316 | } |
||
| 317 | return $allSelections; |
||
| 318 | } |
||
| 319 | |||
| 320 | private static function initSubQuery($category_id, $joinCondition) |
||
| 337 | /** |
||
| 338 | * Аналогично getValuesForPropertyId |
||
| 339 | * Но identity_map не используется |
||
| 340 | * @param int $property_id |
||
| 341 | * @return array|mixed|\yii\db\ActiveRecord[] |
||
| 342 | */ |
||
| 343 | public static function arrayOfValuesForPropertyId($property_id) |
||
| 373 | |||
| 374 | public function afterSave($insert, $changedAttributes) |
||
| 381 | |||
| 382 | public function beforeDelete() |
||
| 389 | |||
| 390 | public function afterDelete() |
||
| 395 | } |
||
| 396 |
This check looks for accesses to local static members using the fully qualified name instead of
self::.While this is perfectly valid, the fully qualified name of
Certificate::TRIPLEDES_CBCcould just as well be replaced byself::TRIPLEDES_CBC. Referencing local members withself::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.