Complex classes like MessageTrait 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 MessageTrait, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
28 | trait MessageTrait |
||
29 | { |
||
30 | use MutualTrait; |
||
31 | |||
32 | public $attachmentAttribute = 'attachment'; |
||
33 | public $receivedAtAttribute = 'received_at'; |
||
34 | public $readAtAttribute = 'read_at'; |
||
35 | public static $eventMessageReceived = 'messageReceived'; |
||
36 | public static $eventMessageRead = 'messageRead'; |
||
37 | public $permitChangeContent = false; |
||
38 | public $permitChangeReceivedAt = false; |
||
39 | public $permitChangeReadAt = false; |
||
40 | |||
41 | /** |
||
42 | * Whether the message has been received. |
||
43 | * Note: This trait should be used for models which use [[TimestampTrait]]. |
||
44 | * @return boolean |
||
45 | */ |
||
46 | 4 | public function hasBeenReceived() |
|
50 | |||
51 | /** |
||
52 | * Whether the message has been read. |
||
53 | * If a message has been read, it must have been received. |
||
54 | * Note: This trait should be used for models which use [[TimestampTrait]]. |
||
55 | * @return boolean |
||
56 | */ |
||
57 | 4 | public function hasBeenRead() |
|
61 | |||
62 | 2 | public function touchReceived() |
|
66 | |||
67 | 2 | public function touchRead() |
|
71 | |||
72 | 4 | public function getReceivedAt() |
|
80 | |||
81 | 20 | public function setReceivedAt($receivedAt) |
|
89 | |||
90 | 4 | public function getReadAt() |
|
98 | |||
99 | 20 | public function setReadAt($readAt) |
|
107 | |||
108 | /** |
||
109 | * |
||
110 | * @param ModelEvent $event |
||
111 | */ |
||
112 | 20 | public function onInitReceivedAtAttribute($event) |
|
118 | |||
119 | /** |
||
120 | * |
||
121 | * @param ModelEvent $event |
||
122 | */ |
||
123 | 20 | public function onInitReadAtAttribute($event) |
|
129 | |||
130 | /** |
||
131 | * We consider you have received the message if you read it. |
||
132 | * @param ModelEvent $event |
||
133 | */ |
||
134 | 4 | public function onReadAtChanged($event) |
|
155 | |||
156 | /** |
||
157 | * You are not allowed to change receiving time if you have received it. |
||
158 | * @param ModelEvent $event |
||
159 | */ |
||
160 | 4 | public function onReceivedAtChanged($event) |
|
176 | |||
177 | /** |
||
178 | * You are not allowed to change the content if it is not new message. |
||
179 | * @param ModelEvent $event |
||
180 | */ |
||
181 | 4 | public function onContentChanged($event) |
|
196 | |||
197 | /** |
||
198 | * |
||
199 | * @param AfterSaveEvent $event |
||
200 | */ |
||
201 | 4 | public function onMessageUpdated($event) |
|
214 | |||
215 | /** |
||
216 | * |
||
217 | */ |
||
218 | 20 | public function initMessageEvents() |
|
227 | |||
228 | /** |
||
229 | * Return rules associated with message. |
||
230 | * @return array |
||
231 | */ |
||
232 | 20 | public function getMessageRules() |
|
247 | |||
248 | /** |
||
249 | * @inheritdoc |
||
250 | * @return array |
||
251 | */ |
||
252 | 20 | public function rules() |
|
256 | |||
257 | /** |
||
258 | * @inheritdoc |
||
259 | * @return array |
||
260 | */ |
||
261 | 20 | public function enabledFields() |
|
278 | } |
||
279 |
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.