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 ideas 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 ideas, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
20 | class ideas |
||
21 | { |
||
22 | const SORT_AUTHOR = 'author'; |
||
23 | const SORT_DATE = 'date'; |
||
24 | const SORT_NEW = 'new'; |
||
25 | const SORT_SCORE = 'score'; |
||
26 | const SORT_TITLE = 'title'; |
||
27 | const SORT_TOP = 'top'; |
||
28 | const SORT_VOTES = 'votes'; |
||
29 | const SORT_MYIDEAS = 'egosearch'; |
||
30 | const SUBJECT_LENGTH = 120; |
||
31 | |||
32 | /** @var array Idea status names and IDs */ |
||
33 | public static $statuses = array( |
||
34 | 'NEW' => 1, |
||
35 | 'IN_PROGRESS' => 2, |
||
36 | 'IMPLEMENTED' => 3, |
||
37 | 'DUPLICATE' => 4, |
||
38 | 'INVALID' => 5, |
||
39 | ); |
||
40 | |||
41 | /** @var auth */ |
||
42 | protected $auth; |
||
43 | |||
44 | /* @var config */ |
||
45 | protected $config; |
||
46 | |||
47 | /* @var driver_interface */ |
||
48 | protected $db; |
||
49 | |||
50 | /** @var language */ |
||
51 | protected $language; |
||
52 | |||
53 | /* @var user */ |
||
54 | protected $user; |
||
55 | |||
56 | /** @var string */ |
||
57 | protected $table_ideas; |
||
58 | |||
59 | /** @var string */ |
||
60 | protected $table_votes; |
||
61 | |||
62 | /** @var string */ |
||
63 | protected $table_topics; |
||
64 | |||
65 | /** @var int */ |
||
66 | protected $idea_count; |
||
67 | |||
68 | /** @var string */ |
||
69 | protected $php_ext; |
||
70 | |||
71 | /** @var string */ |
||
72 | protected $profile_url; |
||
73 | |||
74 | /** @var array */ |
||
75 | protected $sql; |
||
76 | |||
77 | /** |
||
78 | * @param auth $auth |
||
79 | * @param config $config |
||
80 | * @param driver_interface $db |
||
81 | * @param language $language |
||
82 | * @param user $user |
||
83 | * @param string $table_ideas |
||
84 | * @param string $table_votes |
||
85 | * @param string $table_topics |
||
86 | * @param string $phpEx |
||
87 | */ |
||
88 | View Code Duplication | public function __construct(auth $auth, config $config, driver_interface $db, language $language, user $user, $table_ideas, $table_votes, $table_topics, $phpEx) |
|
102 | |||
103 | /** |
||
104 | * Returns an array of ideas. Defaults to ten ideas ordered by date |
||
105 | * excluding implemented, duplicate or invalid ideas. |
||
106 | * |
||
107 | * @param int $number The number of ideas to return |
||
108 | * @param string $sort A sorting option/collection |
||
109 | * @param string $direction Should either be ASC or DESC |
||
110 | * @param array|int $status The id of the status(es) to load |
||
111 | * @param int $start Start value for pagination |
||
112 | * |
||
113 | * @return array Array of row data |
||
114 | */ |
||
115 | public function get_ideas($number = 10, $sort = 'date', $direction = 'DESC', $status = [], $start = 0) |
||
148 | |||
149 | /** |
||
150 | * Initialize the $sql property with necessary SQL statements. |
||
151 | * |
||
152 | * @return \phpbb\ideas\factory\ideas $this For chaining calls |
||
153 | */ |
||
154 | protected function query_ideas() |
||
171 | |||
172 | /** |
||
173 | * Update the $sql property with ORDER BY statements to obtain |
||
174 | * the requested collection of Ideas. Some instances may add |
||
175 | * additional WHERE or SELECT statements to refine the collection. |
||
176 | * |
||
177 | * @param string $sort A sorting option/collection |
||
178 | * @param string $direction Will either be ASC or DESC |
||
179 | * |
||
180 | * @return \phpbb\ideas\factory\ideas $this For chaining calls |
||
181 | */ |
||
182 | protected function query_sort($sort, $direction) |
||
223 | |||
224 | /** |
||
225 | * Update $sql property with additional SQL statements to filter ideas |
||
226 | * by status. If $status is given we'll get those ideas. If no $status |
||
227 | * is given, the default is to get all ideas excluding Duplicates, Invalid |
||
228 | * and Implemented statuses (because they are considered done & dusted, |
||
229 | * if they were gases they'd be inert). |
||
230 | * |
||
231 | * @param array|int $status The id(s) of the status(es) to load |
||
232 | * |
||
233 | * @return \phpbb\ideas\factory\ideas $this For chaining calls |
||
234 | */ |
||
235 | protected function query_status($status = []) |
||
243 | |||
244 | /** |
||
245 | * Run a query using the $sql property to get a collection of ideas. |
||
246 | * |
||
247 | * @param int $number The number of ideas to return |
||
248 | * @param int $start Start value for pagination |
||
249 | * |
||
250 | * @return mixed Nested array if the query had rows, false otherwise |
||
251 | * @throws \phpbb\exception\runtime_exception |
||
252 | */ |
||
253 | protected function query_get($number, $start) |
||
272 | |||
273 | /** |
||
274 | * Run a query using the $sql property to get a count of ideas. |
||
275 | * |
||
276 | * @return int The number of ideas |
||
277 | * @throws \phpbb\exception\runtime_exception |
||
278 | */ |
||
279 | protected function query_count() |
||
297 | |||
298 | /** |
||
299 | * Returns the specified idea. |
||
300 | * |
||
301 | * @param int $id The ID of the idea to return. |
||
302 | * |
||
303 | * @return array|false The idea row set, or false if not found. |
||
304 | */ |
||
305 | View Code Duplication | public function get_idea($id) |
|
316 | |||
317 | /** |
||
318 | * Returns an idea specified by its topic ID. |
||
319 | * |
||
320 | * @param int $id The ID of the idea to return. |
||
321 | * |
||
322 | * @return array|false The idea row set, or false if not found. |
||
323 | */ |
||
324 | View Code Duplication | public function get_idea_by_topic_id($id) |
|
335 | |||
336 | /** |
||
337 | * Do a live search on idea titles. Return any matches based on a given search query. |
||
338 | * |
||
339 | * @param string $search The string of characters to search using LIKE |
||
340 | * @param int $limit The number of results to return |
||
341 | * @return array An array of matching idea id/key and title/values |
||
342 | */ |
||
343 | public function ideas_title_livesearch($search, $limit = 10) |
||
363 | |||
364 | /** |
||
365 | * Returns the status name from the status ID specified. |
||
366 | * |
||
367 | * @param int $id ID of the status. |
||
368 | * |
||
369 | * @return string|bool The status name if it exists, false otherwise. |
||
370 | */ |
||
371 | public function get_status_from_id($id) |
||
375 | |||
376 | /** |
||
377 | * Updates the status of an idea. |
||
378 | * |
||
379 | * @param int $idea_id The ID of the idea. |
||
380 | * @param int $status The ID of the status. |
||
381 | * |
||
382 | * @return void |
||
383 | */ |
||
384 | public function change_status($idea_id, $status) |
||
392 | |||
393 | /** |
||
394 | * Sets the ID of the duplicate for an idea. |
||
395 | * |
||
396 | * @param int $idea_id ID of the idea to be updated. |
||
397 | * @param string $duplicate Idea ID of duplicate. |
||
398 | * |
||
399 | * @return bool True if set, false if invalid. |
||
400 | */ |
||
401 | View Code Duplication | public function set_duplicate($idea_id, $duplicate) |
|
416 | |||
417 | /** |
||
418 | * Sets the RFC link of an idea. |
||
419 | * |
||
420 | * @param int $idea_id ID of the idea to be updated. |
||
421 | * @param string $rfc Link to the RFC. |
||
422 | * |
||
423 | * @return bool True if set, false if invalid. |
||
424 | */ |
||
425 | View Code Duplication | public function set_rfc($idea_id, $rfc) |
|
441 | |||
442 | /** |
||
443 | * Sets the ticket ID of an idea. |
||
444 | * |
||
445 | * @param int $idea_id ID of the idea to be updated. |
||
446 | * @param string $ticket Ticket ID. |
||
447 | * |
||
448 | * @return bool True if set, false if invalid. |
||
449 | */ |
||
450 | View Code Duplication | public function set_ticket($idea_id, $ticket) |
|
465 | |||
466 | /** |
||
467 | * Sets the implemented version of an idea. |
||
468 | * |
||
469 | * @param int $idea_id ID of the idea to be updated. |
||
470 | * @param string $version Version of phpBB the idea was implemented in. |
||
471 | * |
||
472 | * @return bool True if set, false if invalid. |
||
473 | */ |
||
474 | View Code Duplication | public function set_implemented($idea_id, $version) |
|
490 | |||
491 | /** |
||
492 | * Sets the title of an idea. |
||
493 | * |
||
494 | * @param int $idea_id ID of the idea to be updated. |
||
495 | * @param string $title New title. |
||
496 | * |
||
497 | * @return boolean True if updated, false if invalid length. |
||
498 | */ |
||
499 | public function set_title($idea_id, $title) |
||
514 | |||
515 | /** |
||
516 | * Get the title of an idea. |
||
517 | * |
||
518 | * @param int $id ID of an idea |
||
519 | * |
||
520 | * @return string The idea's title |
||
521 | */ |
||
522 | View Code Duplication | public function get_title($id) |
|
533 | |||
534 | /** |
||
535 | * Submits a vote on an idea. |
||
536 | * |
||
537 | * @param array $idea The idea returned by get_idea(). |
||
538 | * @param int $user_id The ID of the user voting. |
||
539 | * @param int $value Up (1) or down (0)? |
||
540 | * |
||
541 | * @return array|string Array of information or string on error. |
||
542 | */ |
||
543 | public function vote(&$idea, $user_id, $value) |
||
624 | |||
625 | /** |
||
626 | * Remove a user's vote from an idea |
||
627 | * |
||
628 | * @param array $idea The idea returned by get_idea(). |
||
629 | * @param int $user_id The ID of the user voting. |
||
630 | * |
||
631 | * @return array Array of information. |
||
632 | */ |
||
633 | public function remove_vote(&$idea, $user_id) |
||
666 | |||
667 | /** |
||
668 | * Returns voter info on an idea. |
||
669 | * |
||
670 | * @param int $id ID of the idea. |
||
671 | * |
||
672 | * @return array Array of row data |
||
673 | */ |
||
674 | public function get_voters($id) |
||
695 | |||
696 | /** |
||
697 | * Get a user's votes from a group of ideas |
||
698 | * |
||
699 | * @param int $user_id The user's id |
||
700 | * @param array $ids An array of idea ids |
||
701 | * @return array An array of ideas the user voted on and their vote result, or empty otherwise. |
||
702 | * example: [idea_id => vote_result] |
||
703 | * 1 => 1, idea 1, voted up by the user |
||
704 | * 2 => 0, idea 2, voted down by the user |
||
705 | */ |
||
706 | public function get_users_votes($user_id, array $ids) |
||
722 | |||
723 | /** |
||
724 | * Submits a new idea. |
||
725 | * |
||
726 | * @param string $title The title of the idea. |
||
727 | * @param string $message The description of the idea. |
||
728 | * @param int $user_id The ID of the author. |
||
729 | * |
||
730 | * @return array|int Either an array of errors, or the ID of the new idea. |
||
731 | */ |
||
732 | public function submit($title, $message, $user_id) |
||
816 | |||
817 | /** |
||
818 | * Preview a new idea. |
||
819 | * |
||
820 | * @param string $message The description of the idea. |
||
821 | * @return string The idea parsed for display in preview. |
||
822 | */ |
||
823 | public function preview($message) |
||
829 | |||
830 | /** |
||
831 | * Deletes an idea and the topic to go with it. |
||
832 | * |
||
833 | * @param int $id The ID of the idea to be deleted. |
||
834 | * @param int $topic_id The ID of the idea topic. Optional, but preferred. |
||
835 | * |
||
836 | * @return boolean Whether the idea was deleted or not. |
||
837 | */ |
||
838 | public function delete($id, $topic_id = 0) |
||
857 | |||
858 | /** |
||
859 | * Delete orphaned ideas. Orphaned ideas may exist after a |
||
860 | * topic has been deleted or moved to another forum. |
||
861 | * |
||
862 | * @return int Number of rows affected |
||
863 | */ |
||
864 | public function delete_orphans() |
||
895 | |||
896 | /** |
||
897 | * Helper method for inserting new idea data |
||
898 | * |
||
899 | * @param array $data The array of data to insert |
||
900 | * @param string $table The name of the table |
||
901 | * |
||
902 | * @return int The ID of the inserted row |
||
903 | */ |
||
904 | protected function insert_idea_data(array $data, $table) |
||
912 | |||
913 | /** |
||
914 | * Helper method for updating idea data |
||
915 | * |
||
916 | * @param array $data The array of data to insert |
||
917 | * @param int $id The ID of the idea |
||
918 | * @param string $table The name of the table |
||
919 | * |
||
920 | * @return void |
||
921 | */ |
||
922 | protected function update_idea_data(array $data, $id, $table) |
||
929 | |||
930 | /** |
||
931 | * Helper method for deleting idea data |
||
932 | * |
||
933 | * @param int $id The ID of the idea |
||
934 | * @param string $table The name of the table |
||
935 | * |
||
936 | * @return bool True if idea was deleted, false otherwise |
||
937 | */ |
||
938 | protected function delete_idea_data($id, $table) |
||
946 | |||
947 | /** |
||
948 | * Get the stored idea count |
||
949 | * Note: this should only be called after get_ideas() |
||
950 | * |
||
951 | * @return int Count of ideas |
||
952 | */ |
||
953 | public function get_idea_count() |
||
957 | |||
958 | /** |
||
959 | * Helper to generate the user profile URL with an |
||
960 | * absolute URL, which helps avoid problems when |
||
961 | * used in AJAX requests. |
||
962 | * |
||
963 | * @return string User profile URL |
||
964 | */ |
||
965 | protected function profile_url() |
||
974 | } |
||
975 |
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.