Complex classes like UserRelationTrait 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 UserRelationTrait, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
41 | trait UserRelationTrait |
||
42 | { |
||
43 | use mb, |
||
44 | MutualTrait { |
||
45 | mb::addBlame as addGroup; |
||
46 | mb::createBlame as createGroup; |
||
47 | mb::addOrCreateBlame as addOrCreateGroup; |
||
48 | mb::removeBlame as removeGroup; |
||
49 | mb::removeAllBlames as removeAllGroups; |
||
50 | mb::getBlame as getGroup; |
||
51 | mb::getOrCreateBlame as getOrCreateGroup; |
||
52 | mb::getBlameds as getGroupMembers; |
||
53 | mb::getBlameGuids as getGroupGuids; |
||
54 | mb::setBlameGuids as setGroupGuids; |
||
55 | mb::getAllBlames as getAllGroups; |
||
56 | mb::getNonBlameds as getNonGroupMembers; |
||
57 | mb::getBlamesCount as getGroupsCount; |
||
58 | mb::getMultipleBlameableAttributeRules as getGroupsRules; |
||
59 | mb::getEmptyBlamesJson as getEmptyGroupJson; |
||
60 | } |
||
61 | |||
62 | /** |
||
63 | * @var string |
||
64 | */ |
||
65 | public $remarkAttribute = 'remark'; |
||
66 | public static $relationSingle = 0; |
||
67 | public static $relationMutual = 1; |
||
68 | public $relationType = 1; |
||
69 | public $relationTypes = [ |
||
70 | 0 => 'Single', |
||
71 | 1 => 'Mutual', |
||
72 | ]; |
||
73 | |||
74 | /** |
||
75 | * @var string the attribute name of which determines the relation type. |
||
76 | */ |
||
77 | public $mutualTypeAttribute = 'type'; |
||
78 | public static $mutualTypeNormal = 0x00; |
||
79 | public static $mutualTypeSuspend = 0x01; |
||
80 | |||
81 | /** |
||
82 | * @var array Mutual types. |
||
83 | */ |
||
84 | public static $mutualTypes = [ |
||
85 | 0x00 => 'Normal', |
||
86 | 0x01 => 'Suspend', |
||
87 | ]; |
||
88 | |||
89 | /** |
||
90 | * @var string the attribute name of which determines the `favorite` field. |
||
91 | */ |
||
92 | public $favoriteAttribute = 'favorite'; |
||
93 | |||
94 | /** |
||
95 | * Permit to build self relation. |
||
96 | * @var boolean |
||
97 | */ |
||
98 | public $relationSelf = false; |
||
99 | |||
100 | /** |
||
101 | * Get whether this relation is favorite or not. |
||
102 | * @return boolean |
||
103 | */ |
||
104 | 1 | public function getIsFavorite() |
|
105 | { |
||
106 | 1 | $favoriteAttribute = $this->favoriteAttribute; |
|
107 | 1 | return is_string($favoriteAttribute) ? (int) $this->$favoriteAttribute > 0 : null; |
|
108 | } |
||
109 | |||
110 | /** |
||
111 | * Set favorite. |
||
112 | * @param boolean $fav |
||
113 | */ |
||
114 | 1 | public function setIsFavorite($fav) |
|
115 | { |
||
116 | 1 | $favoriteAttribute = $this->favoriteAttribute; |
|
117 | 1 | return is_string($favoriteAttribute) ? $this->$favoriteAttribute = ($fav ? 1 : 0) : null; |
|
118 | } |
||
119 | |||
120 | /** |
||
121 | * @inheritdoc |
||
122 | */ |
||
123 | 8 | public function rules() |
|
124 | { |
||
125 | 8 | return array_merge(parent::rules(), $this->getUserRelationRules()); |
|
126 | } |
||
127 | |||
128 | /** |
||
129 | * Validation rules associated with user relation. |
||
130 | * @return array rules. |
||
131 | */ |
||
132 | 8 | public function getUserRelationRules() |
|
133 | { |
||
134 | 8 | $rules = []; |
|
135 | 8 | if ($this->relationType == static::$relationMutual) { |
|
136 | $rules = [ |
||
137 | 7 | [[$this->mutualTypeAttribute], 'in', 'range' => array_keys(static::$mutualTypes)], |
|
138 | 7 | [[$this->mutualTypeAttribute], 'default', 'value' => static::$mutualTypeNormal], |
|
139 | 7 | ]; |
|
140 | 7 | } |
|
141 | 8 | return array_merge($rules, $this->getRemarkRules(), $this->getFavoriteRules(), $this->getGroupsRules(), $this->getOtherGuidRules()); |
|
|
|||
142 | } |
||
143 | |||
144 | /** |
||
145 | * Get remark. |
||
146 | * @return string remark. |
||
147 | */ |
||
148 | public function getRemark() |
||
149 | { |
||
150 | $remarkAttribute = $this->remarkAttribute; |
||
151 | return is_string($remarkAttribute) ? $this->$remarkAttribute : null; |
||
152 | } |
||
153 | |||
154 | /** |
||
155 | * Set remark. |
||
156 | * @param string $remark |
||
157 | * @return string remark. |
||
158 | */ |
||
159 | public function setRemark($remark) |
||
160 | { |
||
161 | $remarkAttribute = $this->remarkAttribute; |
||
162 | return is_string($remarkAttribute) ? $this->$remarkAttribute = $remark : null; |
||
163 | } |
||
164 | |||
165 | /** |
||
166 | * Validation rules associated with remark attribute. |
||
167 | * @return array rules. |
||
168 | */ |
||
169 | 8 | public function getRemarkRules() |
|
170 | { |
||
171 | 8 | return is_string($this->remarkAttribute) ? [ |
|
172 | 8 | [[$this->remarkAttribute], 'string'], |
|
173 | 8 | [[$this->remarkAttribute], 'default', 'value' => ''], |
|
174 | 8 | ] : []; |
|
175 | } |
||
176 | |||
177 | /** |
||
178 | * Validation rules associated with favorites attribute. |
||
179 | * @return array rules. |
||
180 | */ |
||
181 | 8 | public function getFavoriteRules() |
|
182 | { |
||
183 | 8 | return is_string($this->favoriteAttribute) ? [ |
|
184 | 8 | [[$this->favoriteAttribute], 'boolean'], |
|
185 | 8 | [[$this->favoriteAttribute], 'default', 'value' => 0], |
|
186 | 8 | ] : []; |
|
187 | } |
||
188 | |||
189 | /** |
||
190 | * Validation rules associated with other guid attribute. |
||
191 | * @return array rules. |
||
192 | */ |
||
193 | 8 | public function getOtherGuidRules() |
|
194 | { |
||
195 | 8 | $rules = array_merge($this->getMutualRules(), [ |
|
196 | 8 | [[$this->otherGuidAttribute, $this->createdByAttribute], 'unique', 'targetAttribute' => [$this->otherGuidAttribute, $this->createdByAttribute]], |
|
197 | 8 | ]); |
|
198 | 8 | return $rules; |
|
199 | } |
||
200 | |||
201 | /** |
||
202 | * Attach events associated with user relation. |
||
203 | */ |
||
204 | 8 | public function initUserRelationEvents() |
|
214 | |||
215 | /** |
||
216 | * Get opposite relation against self. |
||
217 | * @return \vistart\Models\models\BaseUserRelationModel |
||
218 | */ |
||
219 | 7 | public function getOpposite() |
|
220 | { |
||
221 | 7 | if ($this->isNewRecord) { |
|
222 | 1 | return null; |
|
223 | } |
||
228 | |||
229 | /** |
||
230 | * Build new or return existed suspend mutual relation, of return null if |
||
231 | * current type is not mutual. |
||
232 | * @see buildRelation() |
||
233 | * @param BaseUserModel|string $user Initiator or its GUID. |
||
234 | * @param BaseUserModel|string $other Recipient or its GUID. |
||
235 | * @return \vistart\Models\models\BaseUserRelationModel The relation will be |
||
236 | * given if exists, or return a new relation. |
||
237 | */ |
||
238 | 1 | public static function buildSuspendRelation($user, $other) |
|
248 | |||
249 | /** |
||
250 | * Build new or return existed normal relation. |
||
251 | * The status of mutual relation will be changed to normal if it is not. |
||
252 | * @see buildRelation() |
||
253 | * @param BaseUserModel|string $user Initiator or its GUID. |
||
254 | * @param BaseUserModel|string $other Recipient or its GUID. |
||
255 | * @return \vistart\Models\models\BaseUserRelationModel The relation will be |
||
256 | * given if exists, or return a new relation. |
||
257 | */ |
||
258 | 8 | public static function buildNormalRelation($user, $other) |
|
267 | |||
268 | /** |
||
269 | * Build new or return existed relation between initiator and recipient. |
||
270 | * If relation between initiator and recipient is not found, new relation will |
||
271 | * be built. If initiator and recipient are the same one and it is not allowed |
||
272 | * to build self relation, null will be given. |
||
273 | * If you want to know whether the relation exists, you can check the return |
||
274 | * value of `getIsNewRecord()` method. |
||
275 | * @param BaseUserModel|string $user Initiator or its GUID. |
||
276 | * @param BaseUserModel|string $other Recipient or its GUID. |
||
277 | * @return \vistart\Models\models\BaseUserRelationModel The relation will be |
||
278 | * given if exists, or return a new relation. Or return null if not allowed |
||
279 | * to build self relation, |
||
280 | */ |
||
281 | 8 | protected static function buildRelation($user, $other) |
|
304 | |||
305 | /** |
||
306 | * Build opposite relation throughout the current relation. The opposite |
||
307 | * relation will be given if existed. |
||
308 | * @param \vistart\Models\models\BaseUserRelationModel $relation |
||
309 | * @return \vistart\Models\models\BaseUserRelationModel |
||
310 | */ |
||
311 | 7 | protected static function buildOppositeRelation($relation) |
|
327 | |||
328 | /** |
||
329 | * Remove myself. |
||
330 | * @return integer|false The number of relations removed, or false if the remove |
||
331 | * is unsuccessful for some reason. Note that it is possible the number of relations |
||
332 | * removed is 0, even though the remove execution is successful. |
||
333 | */ |
||
334 | 2 | public function remove() |
|
338 | |||
339 | /** |
||
340 | * Remove first relation between initiator(s) and recipient(s). |
||
341 | * @param BaseUserModel|string|array $user Initiator or its guid, or array of them. |
||
342 | * @param BaseUserModel|string|array $other Recipient or its guid, or array of them. |
||
343 | * @return integer|false The number of relations removed. |
||
344 | */ |
||
345 | 1 | public static function removeOneRelation($user, $other) |
|
349 | |||
350 | /** |
||
351 | * Remove all relations between initiator(s) and recipient(s). |
||
352 | * @param BaseUserModel|string|array $user Initiator or its guid, or array of them. |
||
353 | * @param BaseUserModel|string|array $other Recipient or its guid, or array of them. |
||
354 | * @return integer The number of relations removed. |
||
355 | */ |
||
356 | 2 | public static function removeAllRelations($user, $other) |
|
363 | |||
364 | /** |
||
365 | * Get first relation between initiator(s) and recipient(s). |
||
366 | * @param BaseUserModel|string|array $user Initiator or its guid, or array of them. |
||
367 | * @param BaseUserModel|string|array $other Recipient or its guid, or array of them. |
||
368 | * @return \vistart\Models\models\BaseUserRelationModel |
||
369 | */ |
||
370 | 1 | public static function findOneRelation($user, $other) |
|
374 | |||
375 | /** |
||
376 | * Get first opposite relation between initiator(s) and recipient(s). |
||
377 | * @param BaseUserModel|string $user Initiator or its guid, or array of them. |
||
378 | * @param BaseUserModel|string $other Recipient or its guid, or array of them. |
||
379 | * @return \vistart\Models\models\BaseUserRelationModel |
||
380 | */ |
||
381 | 7 | public static function findOneOppositeRelation($user, $other) |
|
385 | |||
386 | /** |
||
387 | * Get user's or users' all relations, or by specified groups. |
||
388 | * @param BaseUserModel|string|array $user Initiator or its GUID, or Initiators or their GUIDs. |
||
389 | * @param BaseUserRelationGroupModel|string|array|null $groups UserRelationGroup |
||
390 | * or its guid, or array of them. If you do not want to delimit the groups, please assign null. |
||
391 | * @return array all eligible relations |
||
392 | */ |
||
393 | public static function findOnesAllRelations($user, $groups = null) |
||
397 | |||
398 | /** |
||
399 | * Initialize groups attribute. |
||
400 | * @param \yii\base\Event $event |
||
401 | */ |
||
402 | 8 | public function onInitGroups($event) |
|
407 | |||
408 | /** |
||
409 | * Initialize remark attribute. |
||
410 | * @param \yii\base\Event $event |
||
411 | */ |
||
412 | 8 | public function onInitRemark($event) |
|
418 | |||
419 | /** |
||
420 | * The event triggered after insert new relation. |
||
421 | * The opposite relation should be inserted without triggering events |
||
422 | * simultaneously after new relation inserted, |
||
423 | * @param \yii\base\Event $event |
||
424 | */ |
||
425 | 8 | public function onInsertRelation($event) |
|
437 | |||
438 | /** |
||
439 | * The event triggered after update relation. |
||
440 | * The opposite relation should be updated without triggering events |
||
441 | * simultaneously after existed relation removed. |
||
442 | * @param \yii\base\Event $event |
||
443 | */ |
||
444 | 3 | public function onUpdateRelation($event) |
|
456 | |||
457 | /** |
||
458 | * The event triggered after delete relation. |
||
459 | * The opposite relation should be deleted without triggering events |
||
460 | * simultaneously after existed relation removed. |
||
461 | * @param \yii\base\Event $event |
||
462 | */ |
||
463 | 2 | public function onDeleteRelation($event) |
|
474 | } |
||
475 |
This check looks for methods that are used by a trait but not required by it.
To illustrate, let’s look at the following code example
The trait
Idable
provides a methodequalsId
that in turn relies on the methodgetId()
. If this method does not exist on a class mixing in this trait, the method will fail.Adding the
getId()
as an abstract method to the trait will make sure it is available.