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:
Complex classes like User 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 User, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
39 | class User extends \Flipside\SerializableObject |
||
40 | { |
||
41 | /** |
||
42 | * An array to cache the title to string mappings so that they don't need to be pulled from the database |
||
43 | * everytime |
||
44 | */ |
||
45 | public static $titlenames = null; |
||
46 | |||
47 | /** |
||
48 | * An array of properties that cannot be set on a user |
||
49 | */ |
||
50 | protected $unsettableElements = array( |
||
51 | 'uid', |
||
52 | 'email' |
||
53 | ); |
||
54 | |||
55 | /** |
||
56 | * Is this user in the Group or a child of that group? |
||
57 | * |
||
58 | * @param string $name The name of the group to check if the user is in |
||
59 | * |
||
60 | * @return boolean True if the user is in the group, false otherwise |
||
61 | */ |
||
62 | public function isInGroupNamed($name) |
||
66 | |||
67 | public function __get($propName) |
||
71 | |||
72 | public function __set($propName, $value) |
||
75 | |||
76 | public function __isset($propName) |
||
80 | |||
81 | /** |
||
82 | * The list of titles for the user |
||
83 | * |
||
84 | * @return boolean|array The user's title(s) in user friendly strings |
||
85 | * |
||
86 | * @SuppressWarnings("StaticAccess") |
||
87 | */ |
||
88 | public function getTitleNames() |
||
118 | |||
119 | /** |
||
120 | * The groups the user is a part of |
||
121 | * |
||
122 | * @return boolean|array The user's Auth\Group structures |
||
123 | */ |
||
124 | public function getGroups() |
||
128 | |||
129 | /** |
||
130 | * Add a supplemental login type that the user can use to login |
||
131 | * |
||
132 | * @param string $provider The hostname for the provider |
||
133 | */ |
||
134 | public function addLoginProvider($provider) |
||
147 | |||
148 | /** |
||
149 | * Can the user login with this provider? |
||
150 | * |
||
151 | * @param string $provider The hostname for the provider |
||
152 | * |
||
153 | * @return boolean true if they can login with the provider, false otherwise |
||
154 | */ |
||
155 | public function canLoginWith($provider) |
||
172 | |||
173 | /** |
||
174 | * Set the user's password without verifying the current password |
||
175 | * |
||
176 | * @param string $password The new user password |
||
177 | * |
||
178 | * @return boolean true if the user's password was changed, false otherwise |
||
179 | */ |
||
180 | protected function setPass($password) |
||
184 | |||
185 | /** |
||
186 | * Has the user completely filled out their user profile? |
||
187 | * |
||
188 | * @return boolean true if the user's profile is complete, false otherwise |
||
189 | */ |
||
190 | public function isProfileComplete() |
||
200 | |||
201 | /** |
||
202 | * Validate that the user's password is the specified password |
||
203 | * |
||
204 | * @param string $password The user's current password |
||
205 | * |
||
206 | * @return boolean true if the user's password is correct, false otherwise |
||
207 | * |
||
208 | * @SuppressWarnings("UnusedFormalParameter") |
||
209 | */ |
||
210 | public function validate_password($password) |
||
214 | |||
215 | /** |
||
216 | * Validate that the user's reset hash is the sepcified hash |
||
217 | * |
||
218 | * @param string $hash The user's reset hash |
||
219 | * |
||
220 | * @return boolean true if the user's hash is correct, false otherwise |
||
221 | * |
||
222 | * @SuppressWarnings("UnusedFormalParameter") |
||
223 | */ |
||
224 | public function validate_reset_hash($hash) |
||
228 | |||
229 | /** |
||
230 | * Change the user's password, validating the old password or reset hash |
||
231 | * |
||
232 | * @param string $oldpass The user's original password or reset hash if $isHash is true |
||
233 | * @param string $newpass The user's new password |
||
234 | * @param boolean $isHash Is $old_pass a password or a hash |
||
235 | * |
||
236 | * @return boolean true if the user's password was changed, false otherwise |
||
237 | */ |
||
238 | public function change_pass($oldpass, $newpass, $isHash = false) |
||
254 | |||
255 | /** |
||
256 | * Allow write for the user |
||
257 | */ |
||
258 | protected function enableReadWrite() |
||
261 | |||
262 | /** |
||
263 | * Update the user password if required |
||
264 | */ |
||
265 | private function editUserPassword(&$data) |
||
296 | |||
297 | private function checkForUnsettableElements($data) |
||
313 | |||
314 | /** |
||
315 | * Modify the user given the provided data object |
||
316 | * |
||
317 | * @param stdClass $data The user's new data |
||
318 | * |
||
319 | * @return boolean true if the user's data was changed, false otherwise |
||
320 | */ |
||
321 | public function editUser($data) |
||
350 | |||
351 | /** |
||
352 | * Obtain the user's password reset hash |
||
353 | * |
||
354 | * @return string|false A hash if available, false otherwise |
||
355 | */ |
||
356 | public function getPasswordResetHash() |
||
360 | |||
361 | /** |
||
362 | * Remove the email address from the user account |
||
363 | * |
||
364 | * @param string $email The email to remove |
||
365 | * |
||
366 | * @return boolean If the operation succeeded or not |
||
367 | */ |
||
368 | public function removeEmail($email) |
||
372 | |||
373 | /** |
||
374 | * Serialize the user data into a format usable by the json_encode method |
||
375 | * |
||
376 | * @return array A simple keyed array representing the user |
||
377 | */ |
||
378 | public function jsonSerialize() |
||
406 | |||
407 | /** |
||
408 | * Serialize the user data into a VCARD 2.1 format |
||
409 | * |
||
410 | * @return string The VCARD for the user |
||
411 | */ |
||
412 | public function getVcard() |
||
428 | } |
||
429 | /* vim: set tabstop=4 shiftwidth=4 expandtab: */ |
||
430 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.