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 midcom_services_rcs_backend_rcs 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 midcom_services_rcs_backend_rcs, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 12 | class midcom_services_rcs_backend_rcs implements midcom_services_rcs_backend |
||
|
1 ignored issue
–
show
|
|||
| 13 | { |
||
| 14 | /** |
||
| 15 | * GUID of the current object |
||
| 16 | */ |
||
| 17 | private $_guid; |
||
| 18 | |||
| 19 | /** |
||
| 20 | * Cached revision history for the object |
||
| 21 | */ |
||
| 22 | private $_history; |
||
| 23 | |||
| 24 | private $_config; |
||
| 25 | |||
| 26 | public function __construct($object, $config) |
||
| 31 | |||
| 32 | private function _generate_rcs_filename($guid) |
||
| 43 | |||
| 44 | /** |
||
| 45 | * Save a new revision |
||
| 46 | * |
||
| 47 | * @param object object to be saved |
||
| 48 | * @return boolean true on success. |
||
| 49 | */ |
||
| 50 | public function update($object, $updatemessage = null) |
||
| 81 | |||
| 82 | /** |
||
| 83 | * Update object to RCS |
||
| 84 | * Should be called just before $object->update(), if the type parameter is omitted |
||
| 85 | * the function will use GUID to determine the type, this makes an extra DB query. |
||
| 86 | * |
||
| 87 | * @param string root of rcs directory. |
||
| 88 | * @param object object to be updated. |
||
| 89 | * @return int : |
||
| 90 | * 0 on success |
||
| 91 | * 3 on missing object->guid |
||
| 92 | * nonzero on error in one of the commands. |
||
| 93 | */ |
||
| 94 | public function rcs_update ($object, $message) |
||
| 125 | |||
| 126 | /** |
||
| 127 | * Get the object of a revision |
||
| 128 | * |
||
| 129 | * @param string revision identifier of revision wanted |
||
| 130 | * @return array array representation of the object |
||
| 131 | */ |
||
| 132 | public function get_revision($revision) |
||
| 158 | |||
| 159 | /** |
||
| 160 | * Check if a revision exists |
||
| 161 | * |
||
| 162 | * @param string version |
||
| 163 | * @return booleann true if exists |
||
| 164 | */ |
||
| 165 | public function version_exists($version) |
||
| 170 | |||
| 171 | /** |
||
| 172 | * Get the previous versionID |
||
| 173 | * |
||
| 174 | * @param string version |
||
| 175 | * @return string versionid before this one or empty string. |
||
| 176 | */ |
||
| 177 | View Code Duplication | public function get_prev_version($version) |
|
| 178 | { |
||
| 179 | $versions = $this->list_history_numeric(); |
||
| 180 | |||
| 181 | if ( !in_array($version, $versions) |
||
| 182 | || $version === end($versions)) |
||
| 183 | { |
||
| 184 | return ''; |
||
| 185 | } |
||
| 186 | |||
| 187 | $mode = end($versions); |
||
| 188 | |||
| 189 | while( $mode |
||
| 190 | && $mode !== $version) |
||
| 191 | { |
||
| 192 | $mode = prev($versions); |
||
| 193 | |||
| 194 | if ($mode === $version) |
||
| 195 | { |
||
| 196 | return next($versions); |
||
| 197 | } |
||
| 198 | } |
||
| 199 | |||
| 200 | return ''; |
||
| 201 | } |
||
| 202 | |||
| 203 | /** |
||
| 204 | * Mirror method for get_prev_version() |
||
| 205 | * |
||
| 206 | * @param string $version |
||
| 207 | * @return mixed |
||
| 208 | */ |
||
| 209 | public function get_previous_version($version) |
||
| 213 | |||
| 214 | /** |
||
| 215 | * Get the next versionID |
||
| 216 | * |
||
| 217 | * @param string version |
||
| 218 | * @return string versionid before this one or empty string. |
||
| 219 | */ |
||
| 220 | View Code Duplication | public function get_next_version($version) |
|
| 221 | { |
||
| 222 | $versions = $this->list_history_numeric(); |
||
| 223 | |||
| 224 | if ( !in_array($version, $versions) |
||
| 225 | || $version === current($versions)) |
||
| 226 | { |
||
| 227 | return ''; |
||
| 228 | } |
||
| 229 | |||
| 230 | $mode = current($versions); |
||
| 231 | |||
| 232 | while ( $mode |
||
| 233 | && $mode !== $version) |
||
| 234 | { |
||
| 235 | $mode = next($versions); |
||
| 236 | |||
| 237 | if ($mode === $version) |
||
| 238 | { |
||
| 239 | return prev($versions); |
||
| 240 | } |
||
| 241 | } |
||
| 242 | |||
| 243 | return ''; |
||
| 244 | } |
||
| 245 | |||
| 246 | /** |
||
| 247 | * Return a list of the revisions as a key => value pair where |
||
| 248 | * the key is the index of the revision and the value is the revision id. |
||
| 249 | * Order: revision 0 is the newest. |
||
| 250 | * |
||
| 251 | * @return array |
||
| 252 | */ |
||
| 253 | public function list_history_numeric() |
||
| 258 | |||
| 259 | /** |
||
| 260 | * Lists the number of changes that has been done to the object |
||
| 261 | * |
||
| 262 | * @return array list of changeids |
||
| 263 | */ |
||
| 264 | public function list_history() |
||
| 279 | |||
| 280 | /* it is debatable to move this into the object when it resides nicely in a libary... */ |
||
| 281 | |||
| 282 | private function rcs_parse_history_entry($entry) |
||
| 334 | |||
| 335 | /* |
||
| 336 | * the functions below are mostly rcs functions moved into the class. Someday I'll get rid of the |
||
| 337 | * old files... |
||
| 338 | */ |
||
| 339 | /** |
||
| 340 | * Get a list of the object's history |
||
| 341 | * |
||
| 342 | * @param string objectid (usually the guid) |
||
| 343 | * @return array list of revisions and revision comment. |
||
| 344 | */ |
||
| 345 | private function rcs_gethistory($what) |
||
| 374 | |||
| 375 | /** |
||
| 376 | * execute a command |
||
| 377 | * |
||
| 378 | * @param string $command The command to execute |
||
| 379 | * @param string $filename The file to operate on |
||
| 380 | * @return string command result. |
||
| 381 | */ |
||
| 382 | private function rcs_exec($command, $filename) |
||
| 399 | |||
| 400 | /** |
||
| 401 | * Writes $data to file $guid, does not return anything. |
||
| 402 | */ |
||
| 403 | private function rcs_writefile ($guid, $data) |
||
| 413 | |||
| 414 | /** |
||
| 415 | * Reads data from file $guid and returns it. |
||
| 416 | * |
||
| 417 | * @param string guid |
||
| 418 | * @return string xml representation of guid |
||
| 419 | */ |
||
| 420 | private function rcs_readfile ($guid) |
||
| 432 | |||
| 433 | /** |
||
| 434 | * Make xml out of an object. |
||
| 435 | * |
||
| 436 | * @param midcom_core_dbaobject $object |
||
| 437 | * @return xmldata |
||
| 438 | */ |
||
| 439 | private function rcs_object2data(midcom_core_dbaobject $object) |
||
| 449 | |||
| 450 | /** |
||
| 451 | * Add object to RCS |
||
| 452 | * |
||
| 453 | * @param object $object object to be saved |
||
| 454 | * @param string $description changelog comment.- |
||
| 455 | * @return int : |
||
| 456 | * 0 on success |
||
| 457 | * 3 on missing object->guid |
||
| 458 | * nonzero on error in one of the commands. |
||
| 459 | */ |
||
| 460 | private function rcs_create(midcom_core_dbaobject $object, $description) |
||
| 483 | |||
| 484 | private function exec($command) |
||
| 510 | |||
| 511 | /** |
||
| 512 | * Get a html diff between two versions. |
||
| 513 | * |
||
| 514 | * @param string latest_revision id of the latest revision |
||
| 515 | * @param string oldest_revision id of the oldest revision |
||
| 516 | * @return array array with the original value, the new value and a diff -u |
||
| 517 | */ |
||
| 518 | public function get_diff($oldest_revision, $latest_revision, $renderer_style = 'inline') |
||
| 581 | |||
| 582 | /** |
||
| 583 | * Get the comment of one revision. |
||
| 584 | * |
||
| 585 | * @param string revison id |
||
| 586 | * @return string comment |
||
| 587 | */ |
||
| 588 | public function get_comment($revision) |
||
| 593 | |||
| 594 | /** |
||
| 595 | * Restore an object to a certain revision. |
||
| 596 | * |
||
| 597 | * @param string id of revision to restore object to. |
||
| 598 | * @return boolean true on success. |
||
| 599 | */ |
||
| 600 | public function restore_to_revision($revision) |
||
| 620 | } |
||
| 621 |
You can fix this by adding a namespace to your class:
When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.