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 PMF_Category 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 PMF_Category, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
43 | class PMF_Category |
||
44 | { |
||
45 | /** |
||
46 | * @var PMF_Configuration |
||
47 | */ |
||
48 | private $_config = null; |
||
49 | |||
50 | /** |
||
51 | * User ID. |
||
52 | * |
||
53 | * @var int |
||
54 | */ |
||
55 | private $user = -1; |
||
56 | |||
57 | /** |
||
58 | * Groupd. |
||
59 | * |
||
60 | * @var array |
||
61 | */ |
||
62 | private $groups = array(-1); |
||
63 | |||
64 | /** |
||
65 | * The categories as an array. |
||
66 | * |
||
67 | * @var array |
||
68 | */ |
||
69 | public $categories = []; |
||
70 | |||
71 | /** |
||
72 | * The category names as an array. |
||
73 | * |
||
74 | * @var array |
||
75 | */ |
||
76 | public $categoryName = []; |
||
77 | |||
78 | /** |
||
79 | * The category tree. |
||
80 | * |
||
81 | * @var array |
||
82 | */ |
||
83 | public $catTree = []; |
||
84 | |||
85 | /** |
||
86 | * The children nodes. |
||
87 | * |
||
88 | * @var array |
||
89 | */ |
||
90 | private $children = []; |
||
91 | |||
92 | /** |
||
93 | * The current language. |
||
94 | * |
||
95 | * @var string |
||
96 | */ |
||
97 | private $language = null; |
||
98 | |||
99 | /** |
||
100 | * The lines of tabs. |
||
101 | * |
||
102 | * @var array |
||
103 | */ |
||
104 | private $lineTab = []; |
||
105 | |||
106 | /** |
||
107 | * The tree with the tabs. |
||
108 | * |
||
109 | * @var array |
||
110 | */ |
||
111 | public $treeTab = []; |
||
112 | |||
113 | /** |
||
114 | * Category owners |
||
115 | * |
||
116 | * @var array |
||
117 | */ |
||
118 | private $owner = array(); |
||
119 | |||
120 | /** |
||
121 | * Symbol for each item |
||
122 | * NOTE: We do not use this currently. |
||
123 | * |
||
124 | * @var array |
||
125 | */ |
||
126 | private $symbols = array( |
||
127 | 'vertical' => '|', |
||
128 | 'plus' => '+', |
||
129 | 'minus' => '-', |
||
130 | 'space' => ' ', |
||
131 | 'angle' => '-', |
||
132 | 'medium' => '|-', ); |
||
133 | |||
134 | /** |
||
135 | * Constructor. |
||
136 | * |
||
137 | * @param PMF_Configuration $config Configuration object |
||
138 | * @param array $groups Array with group IDs |
||
139 | * @param bool $withperm With or without permission check |
||
140 | */ |
||
141 | public function __construct(PMF_Configuration $config, $groups = [], $withperm = true) |
||
142 | { |
||
143 | $this->_config = $config; |
||
144 | |||
145 | $this->setGroups($groups); |
||
146 | $this->setLanguage($this->_config->getLanguage()->getLanguage()); |
||
147 | |||
148 | $this->lineTab = $this->getOrderedCategories($withperm); |
||
149 | foreach (array_keys($this->lineTab) as $i) { |
||
150 | $this->lineTab[$i]['level'] = $this->levelOf($this->lineTab[$i]['id']); |
||
151 | } |
||
152 | } |
||
153 | |||
154 | /** |
||
155 | * @param int $userId |
||
156 | */ |
||
157 | public function setUser($userId = -1) |
||
161 | |||
162 | /** |
||
163 | * @param array $groups |
||
164 | */ |
||
165 | public function setGroups(Array $groups) |
||
172 | |||
173 | /** |
||
174 | * Returns all categories with ordered category IDs according to the user |
||
175 | * and group permissions. |
||
176 | * |
||
177 | * @param bool $withperm With or without permission check |
||
178 | * |
||
179 | * @return array |
||
180 | */ |
||
181 | private function getOrderedCategories($withperm = true) |
||
249 | |||
250 | /** |
||
251 | * Gets the main categories and write them in an array. |
||
252 | * |
||
253 | * @param string $categories Array of parent category ids |
||
254 | * @param bool $parentId Only top level categories? |
||
255 | * |
||
256 | * @return array |
||
257 | */ |
||
258 | public function getCategories($categories, $parentId = true) |
||
289 | |||
290 | /** |
||
291 | * Gets all categories and write them in an array. |
||
292 | * |
||
293 | * @return array |
||
294 | */ |
||
295 | public function getAllCategories() |
||
323 | |||
324 | /** |
||
325 | * Gets all category IDs |
||
326 | * |
||
327 | * @return array |
||
328 | */ |
||
329 | public function getAllCategoryIds() |
||
353 | |||
354 | /** |
||
355 | * Builds the category tree. |
||
356 | * |
||
357 | * @param int $id_parent Parent id |
||
358 | * @param int $indent Indention |
||
359 | */ |
||
360 | public function buildTree($id_parent = 0, $indent = 0) |
||
385 | |||
386 | /** |
||
387 | * Get the level of the item id. |
||
388 | * |
||
389 | * @param int $id Category id |
||
390 | * |
||
391 | * @return int |
||
392 | */ |
||
393 | private function levelOf($id) |
||
410 | |||
411 | /** |
||
412 | * Transforms the linear array in a 1D array in the order of the tree, with |
||
413 | * the info. |
||
414 | * |
||
415 | * @param int $id Category id |
||
416 | */ |
||
417 | public function transform($id) |
||
471 | |||
472 | /** |
||
473 | * Get the line number where to find the node $id in the category tree. |
||
474 | * |
||
475 | * @param int $id Category id |
||
476 | * |
||
477 | * @return int |
||
478 | */ |
||
479 | private function getLineCategory($id) |
||
488 | |||
489 | // |
||
490 | /** |
||
491 | * List in a array of the $id of the child. |
||
492 | * |
||
493 | * @param int $id Category id |
||
494 | * |
||
495 | * @return array |
||
496 | * |
||
497 | * @author Thorsten Rinne <[email protected]> |
||
498 | */ |
||
499 | public function getChildren($id) |
||
503 | |||
504 | /** |
||
505 | * list in a array of the $id of the child. |
||
506 | * |
||
507 | * @param int $id Category id |
||
508 | * |
||
509 | * @return array |
||
510 | */ |
||
511 | public function getChildNodes($id) |
||
524 | |||
525 | /** |
||
526 | * List in array the root, super-root, ... of the $id. |
||
527 | * |
||
528 | * @param int $id Category id |
||
529 | * |
||
530 | * @return array |
||
531 | */ |
||
532 | private function getNodes($id) |
||
545 | |||
546 | /** |
||
547 | * Collapse the complete category tree. |
||
548 | */ |
||
549 | View Code Duplication | public function collapseAll() |
|
558 | |||
559 | /** |
||
560 | * expand the node $id. |
||
561 | * |
||
562 | * @param int $id Category id |
||
563 | */ |
||
564 | public function expand($id) |
||
568 | |||
569 | /** |
||
570 | * Try to expand from the parent_id to the node $id |
||
571 | * |
||
572 | * @param int $id |
||
573 | * |
||
574 | * @return void |
||
575 | */ |
||
576 | public function expandTo($id) |
||
593 | |||
594 | /** |
||
595 | * Expand the entire tree |
||
596 | * |
||
597 | * @return void |
||
598 | */ |
||
599 | View Code Duplication | public function expandAll() |
|
608 | |||
609 | /** |
||
610 | * Total height of the expanded tree. |
||
611 | * |
||
612 | * @return int |
||
613 | */ |
||
614 | public function height() |
||
618 | |||
619 | /** |
||
620 | * print the static tree with the number of records. |
||
621 | * |
||
622 | * @return string |
||
623 | */ |
||
624 | public function viewTree() |
||
749 | |||
750 | /** |
||
751 | * Returns the four parts of a line to display: category name, the ID of |
||
752 | * the root node, the description and if the category is active |
||
753 | * |
||
754 | * @param integer $node |
||
755 | * |
||
756 | * @return array |
||
757 | */ |
||
758 | public function getLineDisplay($node) |
||
768 | |||
769 | /** |
||
770 | * Gets the next line in the array treeTab, depending of the |
||
771 | * collapse/expand node. |
||
772 | * |
||
773 | * @param int $line Current line |
||
774 | * |
||
775 | * @return int |
||
776 | */ |
||
777 | public function getNextLineTree($line) |
||
791 | |||
792 | /** |
||
793 | * Gets the list of the brothers of $id (include $id). |
||
794 | * |
||
795 | * @param int $id Brothers |
||
796 | * |
||
797 | * @return array |
||
798 | */ |
||
799 | private function getBrothers($id) |
||
803 | |||
804 | /** |
||
805 | * Creates a category link. |
||
806 | * |
||
807 | * @param string $sids Session id |
||
808 | * @param int $categoryId Parent category |
||
809 | * @param string $categoryName Category name |
||
810 | * @param string $description Description |
||
811 | * @param bool $hasChildren Child categories available |
||
812 | * @param bool $isActive Sets a link active via CSS |
||
813 | * |
||
814 | * @return string |
||
815 | */ |
||
816 | public function addCategoryLink($sids, $categoryId, $categoryName, $description, $hasChildren = false, $isActive = false) |
||
844 | |||
845 | /** |
||
846 | * Gets the path from root to child as breadcrumbs. |
||
847 | * |
||
848 | * @param int $id Category ID |
||
849 | * @param string $separator Path separator |
||
850 | * @param bool $renderAsMicroData Renders breadcrumbs as HTML5 microdata |
||
851 | * @param string $useCssClass Use CSS class "breadcrumb" |
||
852 | * |
||
853 | * @return string |
||
854 | */ |
||
855 | public function getPath($id, $separator = ' / ', $renderAsMicroData = false, $useCssClass = 'breadcrumb') |
||
913 | |||
914 | /** |
||
915 | * Returns the categories from a record id and language. |
||
916 | * |
||
917 | * @param int $record_id record id |
||
918 | * @param int $record_lang record language |
||
919 | * |
||
920 | * @return array |
||
921 | */ |
||
922 | View Code Duplication | public function getCategoryRelationsFromArticle($record_id, $record_lang) |
|
948 | |||
949 | /** |
||
950 | * Returns all categories that are related to the given article-id and |
||
951 | * the current language $this->language in an unsorted array which consists |
||
952 | * of associative arrays with the keys 'name', 'id', 'lang', |
||
953 | * 'parent_id' and 'description'. |
||
954 | * |
||
955 | * @param int $articleId Record id |
||
956 | * |
||
957 | * @return array |
||
958 | */ |
||
959 | public function getCategoriesFromArticle($articleId) |
||
996 | |||
997 | /** |
||
998 | * Returns the ID of a category that associated with the given article. |
||
999 | * |
||
1000 | * @param int $article_id Record id |
||
1001 | * |
||
1002 | * @return int |
||
1003 | */ |
||
1004 | public function getCategoryIdFromArticle($article_id) |
||
1013 | |||
1014 | /** |
||
1015 | * Returns an array with the IDs of all categories that are associated with |
||
1016 | * the given article. |
||
1017 | * |
||
1018 | * @param int $article_id Record id |
||
1019 | * |
||
1020 | * @return array |
||
1021 | */ |
||
1022 | public function getCategoryIdsFromArticle($article_id) |
||
1032 | |||
1033 | /** |
||
1034 | <<<<<<< HEAD |
||
1035 | * Returns the admin user of the given category. |
||
1036 | * |
||
1037 | * @param int $categoryId |
||
1038 | * |
||
1039 | * @return int |
||
1040 | */ |
||
1041 | public function getCategoryUser($categoryId) |
||
1049 | |||
1050 | /** |
||
1051 | * Returns the moderator group ID of the given category. |
||
1052 | ======= |
||
1053 | * Adds a new category entry |
||
1054 | >>>>>>> Fixed broken category tree, closes #1125 |
||
1055 | * |
||
1056 | * @param int $categoryId |
||
1057 | * |
||
1058 | * @return int |
||
1059 | */ |
||
1060 | public function getModeratorGroupId($categoryId) |
||
1064 | |||
1065 | /** |
||
1066 | * Adds a new category entry. |
||
1067 | * |
||
1068 | * @param array $categoryData Array of category data |
||
1069 | * @param int $parentId Parent id |
||
1070 | * @param int $id Category id |
||
1071 | * |
||
1072 | * @return int |
||
1073 | */ |
||
1074 | public function addCategory(Array $categoryData, $parentId = 0, $id = null) |
||
1101 | |||
1102 | /** |
||
1103 | * Updates an existent category entry. |
||
1104 | * |
||
1105 | * @param array $categoryData Array of category data |
||
1106 | * |
||
1107 | * @return bool |
||
1108 | */ |
||
1109 | public function updateCategory(Array $categoryData) |
||
1137 | |||
1138 | /** |
||
1139 | * Returns the data of the given category. |
||
1140 | * |
||
1141 | * @param int $categoryId |
||
1142 | * |
||
1143 | * @return PMF_Entity_Category |
||
1144 | */ |
||
1145 | public function getCategoryData($categoryId) |
||
1171 | |||
1172 | /** |
||
1173 | * Move the categories ownership for users. |
||
1174 | * |
||
1175 | * @param int $from Old user id |
||
1176 | * @param int $to New user id |
||
1177 | * |
||
1178 | * @return bool |
||
1179 | */ |
||
1180 | public function moveOwnership($from, $to) |
||
1201 | |||
1202 | /** |
||
1203 | * Checks if a language is already defined for a category id. |
||
1204 | * |
||
1205 | * @param int $category_id Category id |
||
1206 | * @param string $category_lang Category language |
||
1207 | * |
||
1208 | * @return bool |
||
1209 | */ |
||
1210 | public function checkLanguage($category_id, $category_lang) |
||
1229 | |||
1230 | /** |
||
1231 | * Swaps two categories. |
||
1232 | * |
||
1233 | * @param int $category_id_1 First category |
||
1234 | * @param int $category_id_2 Second category |
||
1235 | * |
||
1236 | * @return bool |
||
1237 | */ |
||
1238 | public function swapCategories($category_id_1, $category_id_2) |
||
1300 | |||
1301 | /** |
||
1302 | * Updates the parent category. |
||
1303 | * |
||
1304 | * @param int $category_id Category id |
||
1305 | * @param int $parent_id Parent category id |
||
1306 | * |
||
1307 | * @return bool |
||
1308 | */ |
||
1309 | public function updateParentCategory($category_id, $parent_id) |
||
1329 | |||
1330 | /** |
||
1331 | * Deletes a category. |
||
1332 | * |
||
1333 | * @param int $category_id Category id |
||
1334 | * @param string $category_lang Categiry language |
||
1335 | * @param bool $delete_all Delete all languages? |
||
1336 | * |
||
1337 | * @return bool |
||
1338 | */ |
||
1339 | View Code Duplication | public function deleteCategory($category_id, $category_lang, $delete_all = false) |
|
1355 | /** |
||
1356 | * Deletes a category relation. |
||
1357 | * |
||
1358 | * @param int $category_id Category id |
||
1359 | * @param string $category_lang Categiry language |
||
1360 | * @param bool $delete_all Delete all languages? |
||
1361 | * |
||
1362 | * @return bool |
||
1363 | */ |
||
1364 | View Code Duplication | public function deleteCategoryRelation($category_id, $category_lang, $delete_all = false) |
|
1380 | |||
1381 | /** |
||
1382 | * Create array with translated categories. |
||
1383 | * |
||
1384 | * @param int $category_id |
||
1385 | * |
||
1386 | * @return array |
||
1387 | * |
||
1388 | * @since 2006-09-10 |
||
1389 | * |
||
1390 | * @author Rudi Ferrari <[email protected]> |
||
1391 | */ |
||
1392 | public function getCategoryLanguagesTranslated($category_id) |
||
1421 | |||
1422 | /** |
||
1423 | * Create all languages which can be used for translation as <option>. |
||
1424 | * |
||
1425 | * @param int $category_id Category id |
||
1426 | * @param string $selected_lang Selected language |
||
1427 | * |
||
1428 | * @return string |
||
1429 | */ |
||
1430 | public function getCategoryLanguagesToTranslate($category_id, $selected_lang) |
||
1447 | |||
1448 | /** |
||
1449 | * Gets all categories which are not translated in actual language |
||
1450 | * to add in this->categories (used in admin section). |
||
1451 | */ |
||
1452 | public function getMissingCategories() |
||
1473 | |||
1474 | /** |
||
1475 | * Get number of nodes at the same parent_id level. |
||
1476 | * |
||
1477 | * @param int $parent_id Parent id |
||
1478 | * |
||
1479 | * @return int |
||
1480 | */ |
||
1481 | public function numParent($parent_id) |
||
1496 | |||
1497 | /** |
||
1498 | * Adds the category permissions for users and groups. |
||
1499 | * |
||
1500 | * @param string $mode 'group' or 'user' |
||
1501 | * @param array $categories ID of the current category |
||
1502 | * @param array $ids Array of group or user IDs |
||
1503 | * |
||
1504 | * @return bool |
||
1505 | */ |
||
1506 | public function addPermission($mode, Array $categories, Array $ids) |
||
1542 | |||
1543 | /** |
||
1544 | * Deletes the category permissions for users and groups. |
||
1545 | * |
||
1546 | * @param string $mode 'group' or 'user' |
||
1547 | * @param array $categories ID of the current category |
||
1548 | * |
||
1549 | * @return bool |
||
1550 | */ |
||
1551 | View Code Duplication | public function deletePermission($mode, $categories) |
|
1574 | |||
1575 | /** |
||
1576 | * Returns the category permissions for users and groups. |
||
1577 | * |
||
1578 | * @param string $mode 'group' or 'user' |
||
1579 | * @param array $categories Array of category ids |
||
1580 | * |
||
1581 | * @return array |
||
1582 | */ |
||
1583 | public function getPermissions($mode, Array $categories) |
||
1612 | |||
1613 | /** |
||
1614 | * Returns the number of records in each category. |
||
1615 | * |
||
1616 | * @return array |
||
1617 | */ |
||
1618 | public function getNumberOfRecordsOfCategory() |
||
1646 | |||
1647 | /** |
||
1648 | * Create a matrix for representing categories and faq records. |
||
1649 | * |
||
1650 | * @return array |
||
1651 | */ |
||
1652 | public function getCategoryRecordsMatrix() |
||
1682 | |||
1683 | /** |
||
1684 | * Sets language. |
||
1685 | * |
||
1686 | * @param string $language |
||
1687 | */ |
||
1688 | public function setLanguage($language) |
||
1692 | |||
1693 | /** |
||
1694 | * Returns the user id of the category owner |
||
1695 | * |
||
1696 | * @param integer $categoryId |
||
1697 | * |
||
1698 | * @return integer |
||
1699 | */ |
||
1700 | public function getOwner($categoryId) |
||
1704 | } |
||
1705 |
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.