Total Complexity | 48 |
Total Lines | 372 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like MyActiveTrait 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.
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 MyActiveTrait, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
25 | trait MyActiveTrait { |
||
26 | |||
27 | |||
28 | /** |
||
29 | * |
||
30 | * @var bool $is_logicDelete by default all deletes are logical deletes |
||
31 | */ |
||
32 | public $is_logicDelete = true; |
||
33 | |||
34 | |||
35 | // for updater & time & closer id |
||
36 | public $userCreatedCol = 'user_created'; |
||
37 | public $userUpdatedCol = 'user_updated'; |
||
38 | public $userClosedCol = 'user_closed'; |
||
39 | public $timeCreatedCol = 'time_created'; |
||
40 | public $timeUpdatedCol = 'time_updated'; |
||
41 | public $timeClosedCol = 'time_closed'; |
||
42 | |||
43 | |||
44 | |||
45 | /** |
||
46 | * {@inheritdoc} |
||
47 | */ |
||
48 | public function save($runValidation = true, $attributeNames = null) |
||
49 | { |
||
50 | $userId = $this->userId(); |
||
51 | if ($this->isNewRecord) { |
||
52 | $this->{$this->timeClosedCol} = $this->dateHelper->getEndOfTime(); |
||
53 | $this->{$this->userCreatedCol} = $userId; |
||
54 | $this->{$this->timeCreatedCol} = $this->dateHelper->getDatetime6(); |
||
55 | } |
||
56 | |||
57 | $this->{$this->userUpdatedCol} = $userId; |
||
58 | $this->{$this->timeUpdatedCol} = $this->dateHelper->getDatetime6(); |
||
59 | return parent::save($runValidation, $attributeNames); |
||
60 | |||
61 | } |
||
62 | |||
63 | /** |
||
64 | * @return int |
||
65 | * @throws yii\base\InvalidConfigException |
||
66 | */ |
||
67 | protected function getIdentityId() |
||
74 | |||
75 | } |
||
76 | |||
77 | /** |
||
78 | * Get an user id for the record manipulation |
||
79 | * @return integer |
||
80 | */ |
||
81 | private function userId() |
||
90 | |||
91 | } |
||
92 | |||
93 | |||
94 | |||
95 | /** |
||
96 | * Return a label for the model eg for display lists, selections |
||
97 | * this method must be overridden |
||
98 | * @return string |
||
99 | */ |
||
100 | public function label() { |
||
102 | } |
||
103 | |||
104 | /** |
||
105 | * Get Model name for views. |
||
106 | * This method needs to be overridden |
||
107 | * @return string Model display name |
||
108 | */ |
||
109 | public static function modelName() |
||
110 | { |
||
111 | return Inflector::camel2words(StringHelper::basename(self::tableName())); |
||
112 | } |
||
113 | |||
114 | /** |
||
115 | * Override delete function to make it logical delete |
||
116 | * {@inheritdoc} |
||
117 | */ |
||
118 | public function delete() { |
||
119 | if ($this->is_logicDelete) { |
||
120 | return $this->logicalDelete(); |
||
121 | } |
||
122 | return parent::delete(); |
||
123 | } |
||
124 | |||
125 | /** |
||
126 | * @return bool |
||
127 | * @throws yii\base\InvalidConfigException |
||
128 | * @throws yii\base\UserException |
||
129 | */ |
||
130 | private function logicalDelete() { |
||
131 | $this->beforeDelete(); |
||
|
|||
132 | // don't put new data if deleting |
||
133 | $this->setAttributes($this->oldAttributes); |
||
134 | |||
135 | // delete logically |
||
136 | if ($this->userUpdatedCol) { |
||
137 | $this->{$this->userUpdatedCol} = $this->getIdentityId(); ; |
||
138 | } |
||
139 | if ($this->userClosedCol) { |
||
140 | $this->{$this->userClosedCol} = $this->getIdentityId(); ; |
||
141 | } |
||
142 | |||
143 | if ($this->timeUpdatedCol) { |
||
144 | $this->{$this->timeUpdatedCol} = $this->dateHelper->getDatetime6(); |
||
145 | } |
||
146 | |||
147 | if ($this->timeClosedCol) { |
||
148 | $this->{$this->timeClosedCol} = $this->dateHelper->getDatetime6(); |
||
149 | } |
||
150 | |||
151 | // don't validate on deleting |
||
152 | if ($this->save(false)) { |
||
153 | self::updateClosingTime(static::tableName()); |
||
154 | $this->afterDelete(); |
||
155 | return 1; |
||
156 | } |
||
157 | |||
158 | throw new yii\base\UserException('Error deleting model'); |
||
159 | } |
||
160 | |||
161 | |||
162 | public static function bulkCopy($objects, $replaceParams) { |
||
163 | /** |
||
164 | * @var yii\db\ActiveRecord $model |
||
165 | */ |
||
166 | $model = new static; |
||
167 | if (!empty($objects)) { |
||
168 | $rows = []; |
||
169 | $cols = []; |
||
170 | foreach ($objects as $object) { |
||
171 | if (!empty($object->attributes)) { |
||
172 | $row = $object->attributes; |
||
173 | $cols = $model->attributes(); |
||
174 | foreach ($replaceParams as $key =>$value) { |
||
175 | // remove primary keys (assuming auto-increment) |
||
176 | foreach ($model->primaryKey as $pk) { |
||
177 | unset($row[$pk]); |
||
178 | } |
||
179 | // remove pk fields from cols |
||
180 | $cols = array_diff($cols, $model->primaryKey); |
||
181 | $row[$key] = $value; |
||
182 | } |
||
183 | $rows[] = $row; |
||
184 | } else { |
||
185 | throw new yii\base\InvalidArgumentException('Missing object attributes in ' . get_called_class() . ' ' . __FUNCTION__); |
||
186 | } |
||
187 | |||
188 | } |
||
189 | \Yii::$app->db->createCommand()->batchInsert(parent::tableName(), $cols, $rows)->execute(); |
||
190 | |||
191 | } |
||
192 | } |
||
193 | |||
194 | /** |
||
195 | * Bulk delete (logic) objects based on the conditions set in $params |
||
196 | * NB! this does NOT call before/after delete |
||
197 | * @param array $params Array with the WHERE conditions as per QueryBuilder eg ['id'=>1] or.. ['>','id',3] |
||
198 | */ |
||
199 | public static function bulkDelete($params) { |
||
200 | $dateHelper = new DateHelper(); |
||
201 | |||
202 | /** |
||
203 | * @var \yii\db\ActiveRecord |
||
204 | */ |
||
205 | $model = new static; |
||
206 | if (!empty($params)) { |
||
207 | |||
208 | $baseParams = [ |
||
209 | $model->timeClosedCol=>$dateHelper->getDatetime6(), |
||
210 | $model->userClosedCol => (new static)->getIdentityId(), |
||
211 | $model->timeUpdatedCol=>$dateHelper->getDatetime6(), |
||
212 | $model->userUpdatedCol =>(new static)->getIdentityId(), |
||
213 | ]; |
||
214 | |||
215 | $conditions = []; |
||
216 | $conditions[] = 'and'; |
||
217 | $conditions[] = ['>', static::tableName() . ".`" . $model->timeClosedCol . '`', $dateHelper->getDatetime6()]; |
||
218 | $conditions[] = $params; |
||
219 | \Yii::$app->db->createCommand()->update(parent::tableName(), $baseParams, $conditions)->execute(); |
||
220 | self::updateClosingTime(static::tableName()); |
||
221 | |||
222 | } else { |
||
223 | throw new yii\base\InvalidArgumentException('No conditions defined for ' . get_called_class() . ' ' . __FUNCTION__); |
||
224 | } |
||
225 | |||
226 | |||
227 | |||
228 | } |
||
229 | |||
230 | |||
231 | /** |
||
232 | * {@inheritdoc} |
||
233 | */ |
||
234 | public function rules() { |
||
235 | return [ |
||
236 | [[$this->userCreatedCol, $this->userUpdatedCol, $this->timeCreatedCol, $this->timeUpdatedCol, $this->timeClosedCol], 'required'], |
||
237 | [[$this->userCreatedCol, $this->userUpdatedCol, $this->userClosedCol], 'integer'], |
||
238 | [[$this->timeCreatedCol, $this->timeUpdatedCol, $this->timeClosedCol], 'safe'], |
||
239 | ]; |
||
240 | } |
||
241 | /** |
||
242 | * {@inheritdoc} |
||
243 | */ |
||
244 | public function attributeLabels() { |
||
245 | return [ |
||
246 | $this->userCreatedCol => Yii::t('app', 'Created by'), |
||
247 | $this->userUpdatedCol => Yii::t('app', 'Updated by'), |
||
248 | $this->userClosedCol => Yii::t('app', 'Closed by'), |
||
249 | $this->timeCreatedCol => Yii::t('app', 'Created at'), |
||
250 | $this->timeUpdatedCol => Yii::t('app', 'Updated at'), |
||
251 | $this->timeClosedCol => Yii::t('app', 'Closed at'), |
||
252 | ]; |
||
253 | } |
||
254 | |||
255 | /** |
||
256 | * Only returns models that have not been closed |
||
257 | * {@inheritdoc} |
||
258 | * @return ActiveQuery the newly created [[ActiveQuery]] instance. |
||
259 | */ |
||
260 | public static function find() { |
||
261 | $child = new static; |
||
262 | $query = parent::find() |
||
263 | ->andFilterWhere($child->timeClosedCondition()); |
||
264 | return $query; |
||
265 | } |
||
266 | |||
267 | public function timeClosedCondition() |
||
268 | { |
||
269 | $lastClosingTime = self::lastClosingTime(static::tableName()); |
||
270 | return ['>', static::tableName() . ".`" . $this->timeClosedCol . '`', $lastClosingTime]; |
||
271 | } |
||
272 | |||
273 | |||
274 | public static function getCount($filter = null) { |
||
275 | $query = self::find(); |
||
276 | if ($filter) { |
||
277 | $query->andFilterWhere($filter); |
||
278 | } |
||
279 | return $query->count(); |
||
280 | } |
||
281 | |||
282 | /** |
||
283 | * a general query that adds the UserStrings filter on top of original query |
||
284 | * @return Query |
||
285 | */ |
||
286 | public static function query() { |
||
287 | $child = new static; |
||
288 | $dateHelper = new DateHelper(); |
||
289 | return (new Query())->andFilterWhere(['>', parent::tableName() . ".`" . $child->timeClosedCol . '`', $dateHelper->getDatetime6()]); |
||
290 | } |
||
291 | |||
292 | /** |
||
293 | * Copy a model to a new model while replacing some params with new values |
||
294 | * @param \yii\db\ActiveRecord $model |
||
295 | * @param array $map map of old model attribute as keys and new values as values |
||
296 | * @return bool|static |
||
297 | * @throws yii\base\UserException |
||
298 | */ |
||
299 | public static function copy($model, $map) { |
||
300 | $newModel = new static; |
||
301 | $newModel->attributes = $model->attributes; |
||
302 | foreach ($map as $key => $value) { |
||
303 | $newModel->{$key} = $value; |
||
304 | } |
||
305 | if ($newModel->save()) { |
||
306 | return $newModel; |
||
307 | } |
||
308 | throw new yii\base\UserException('Error copying model'); |
||
309 | } |
||
310 | |||
311 | /** |
||
312 | * @param string $tableName |
||
313 | * @return mixed|string |
||
314 | */ |
||
315 | private static function lastClosingTime($tableName) { |
||
316 | $dateHelper = new DateHelper(); |
||
317 | |||
318 | if (!self::hasClosing($tableName)) { |
||
319 | self::createClosingRow($tableName); |
||
320 | } |
||
321 | /** @var Closing $closing */ |
||
322 | $closing = Closing::findOne($tableName); |
||
323 | if ($closing) { |
||
324 | return $closing->last_closing_time; |
||
325 | } |
||
326 | return $dateHelper->getDatetime6(); |
||
327 | } |
||
328 | |||
329 | /** |
||
330 | * @param string $tableName |
||
331 | * @return bool |
||
332 | */ |
||
333 | private static function hasClosing($tableName){ |
||
334 | $closing = Closing::findOne($tableName); |
||
335 | return !($closing == null); |
||
336 | } |
||
337 | |||
338 | /** |
||
339 | * @param $tableName |
||
340 | * @return Closing |
||
341 | */ |
||
342 | private static function createClosingRow($tableName) { |
||
343 | |||
344 | if (!self::hasClosing($tableName)) { |
||
345 | $dateHelper = new DateHelper(); |
||
346 | $closing = new Closing([ |
||
347 | 'table_name'=>$tableName, |
||
348 | 'last_closing_time' => $dateHelper->getDatetime6(), |
||
349 | ]); |
||
350 | $closing->save(); |
||
351 | return $closing; |
||
352 | } |
||
353 | return null; |
||
354 | } |
||
355 | |||
356 | private static function updateClosingTime($tableName) { |
||
365 | } |
||
366 | |||
367 | /** |
||
368 | * @return string |
||
369 | */ |
||
370 | public function getTimeCreated() |
||
371 | { |
||
372 | return $this->{$this->timeCreatedCol}; |
||
373 | } |
||
374 | |||
375 | /** |
||
376 | * @return string |
||
377 | */ |
||
378 | public function getTimeUpdated() |
||
379 | { |
||
380 | return $this->{$this->timeUpdatedCol}; |
||
381 | } |
||
382 | |||
383 | /** |
||
384 | * @return string |
||
385 | */ |
||
386 | public function getTimeClosed() |
||
387 | { |
||
388 | return $this->{$this->timeClosedCol}; |
||
389 | } |
||
390 | |||
391 | /** |
||
392 | * @return DateHelper |
||
393 | */ |
||
394 | public function getDateHelper() |
||
397 | } |
||
398 | |||
399 | |||
400 | } |
||
401 |