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 Page 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 Page, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 9 | class Page |
||
|
|
|||
| 10 | { |
||
| 11 | public $title; |
||
| 12 | public $subtitle = ""; |
||
| 13 | public $authorName = ""; |
||
| 14 | public $authorUri = ""; |
||
| 15 | public $authorEmail = ""; |
||
| 16 | public $idPage; |
||
| 17 | public $idGet; |
||
| 18 | public $query; |
||
| 19 | public $favicon; |
||
| 20 | public $n; |
||
| 21 | public $book; |
||
| 22 | public $totalNumber = -1; |
||
| 23 | |||
| 24 | /* @var Entry[] */ |
||
| 25 | public $entryArray = array(); |
||
| 26 | |||
| 27 | 102 | public static function getPage ($pageId, $id, $query, $n) |
|
| 28 | { |
||
| 29 | switch ($pageId) { |
||
| 30 | 102 | case Base::PAGE_ALL_AUTHORS : |
|
| 31 | 3 | return new PageAllAuthors ($id, $query, $n); |
|
| 32 | 99 | case Base::PAGE_AUTHORS_FIRST_LETTER : |
|
| 33 | 1 | return new PageAllAuthorsLetter ($id, $query, $n); |
|
| 34 | 98 | case Base::PAGE_AUTHOR_DETAIL : |
|
| 35 | 7 | return new PageAuthorDetail ($id, $query, $n); |
|
| 36 | 91 | case Base::PAGE_ALL_TAGS : |
|
| 37 | 2 | return new PageAllTags ($id, $query, $n); |
|
| 38 | 89 | case Base::PAGE_TAG_DETAIL : |
|
| 39 | 1 | return new PageTagDetail ($id, $query, $n); |
|
| 40 | 88 | case Base::PAGE_ALL_LANGUAGES : |
|
| 41 | 2 | return new PageAllLanguages ($id, $query, $n); |
|
| 42 | 86 | case Base::PAGE_LANGUAGE_DETAIL : |
|
| 43 | 1 | return new PageLanguageDetail ($id, $query, $n); |
|
| 44 | 85 | case Base::PAGE_ALL_CUSTOMS : |
|
| 45 | 12 | return new PageAllCustoms ($id, $query, $n); |
|
| 46 | 73 | case Base::PAGE_CUSTOM_DETAIL : |
|
| 47 | 4 | return new PageCustomDetail ($id, $query, $n); |
|
| 48 | 69 | case Base::PAGE_ALL_RATINGS : |
|
| 49 | 1 | return new PageAllRating ($id, $query, $n); |
|
| 50 | 68 | case Base::PAGE_RATING_DETAIL : |
|
| 51 | 1 | return new PageRatingDetail ($id, $query, $n); |
|
| 52 | 67 | case Base::PAGE_ALL_SERIES : |
|
| 53 | 2 | return new PageAllSeries ($id, $query, $n); |
|
| 54 | 65 | case Base::PAGE_ALL_BOOKS : |
|
| 55 | 3 | return new PageAllBooks ($id, $query, $n); |
|
| 56 | 62 | case Base::PAGE_ALL_BOOKS_LETTER: |
|
| 57 | 1 | return new PageAllBooksLetter ($id, $query, $n); |
|
| 58 | 61 | case Base::PAGE_ALL_RECENT_BOOKS : |
|
| 59 | 4 | return new PageRecentBooks ($id, $query, $n); |
|
| 60 | 57 | case Base::PAGE_SERIE_DETAIL : |
|
| 61 | 1 | return new PageSerieDetail ($id, $query, $n); |
|
| 62 | 56 | case Base::PAGE_OPENSEARCH_QUERY : |
|
| 63 | 31 | return new PageQueryResult ($id, $query, $n); |
|
| 64 | 25 | case Base::PAGE_BOOK_DETAIL : |
|
| 65 | 1 | return new PageBookDetail ($id, $query, $n); |
|
| 66 | 24 | case Base::PAGE_ALL_PUBLISHERS: |
|
| 67 | 2 | return new PageAllPublishers ($id, $query, $n); |
|
| 68 | 22 | case Base::PAGE_PUBLISHER_DETAIL : |
|
| 69 | 1 | return new PagePublisherDetail ($id, $query, $n); |
|
| 70 | 21 | case Base::PAGE_ABOUT : |
|
| 71 | return new PageAbout ($id, $query, $n); |
||
| 72 | 21 | case Base::PAGE_CUSTOMIZE : |
|
| 73 | return new PageCustomize ($id, $query, $n); |
||
| 74 | default: |
||
| 75 | 21 | $page = new Page ($id, $query, $n); |
|
| 76 | 21 | $page->idPage = "cops:catalog"; |
|
| 77 | 21 | return $page; |
|
| 78 | } |
||
| 79 | } |
||
| 80 | |||
| 81 | 102 | public function __construct($pid, $pquery, $pn) { |
|
| 92 | |||
| 93 | 21 | public function InitializeContent () |
|
| 94 | { |
||
| 95 | 21 | global $config; |
|
| 96 | 21 | $this->title = $config['cops_title_default']; |
|
| 97 | 21 | $this->subtitle = $config['cops_subtitle_default']; |
|
| 98 | 21 | if (Base::noDatabaseSelected ()) { |
|
| 99 | 2 | $i = 0; |
|
| 100 | 2 | foreach (Base::getDbNameList () as $key) { |
|
| 101 | 2 | $nBooks = Book::getBookCount ($i); |
|
| 102 | 2 | array_push ($this->entryArray, new Entry ($key, "cops:{$i}:catalog", |
|
| 103 | 2 | str_format (localize ("bookword", $nBooks), $nBooks), "text", |
|
| 104 | 2 | array ( new LinkNavigation ("?" . DB . "={$i}")), "", $nBooks)); |
|
| 105 | 2 | $i++; |
|
| 106 | 2 | Base::clearDb (); |
|
| 107 | } |
||
| 108 | } else { |
||
| 109 | 19 | if (!in_array (PageQueryResult::SCOPE_AUTHOR, getCurrentOption ('ignored_categories'))) { |
|
| 110 | 18 | array_push ($this->entryArray, Author::getCount()); |
|
| 111 | } |
||
| 112 | 19 | View Code Duplication | if (!in_array (PageQueryResult::SCOPE_SERIES, getCurrentOption ('ignored_categories'))) { |
| 113 | 18 | $series = Serie::getCount(); |
|
| 114 | 18 | if (!is_null ($series)) array_push ($this->entryArray, $series); |
|
| 115 | } |
||
| 116 | 19 | View Code Duplication | if (!in_array (PageQueryResult::SCOPE_PUBLISHER, getCurrentOption ('ignored_categories'))) { |
| 117 | 18 | $publisher = Publisher::getCount(); |
|
| 118 | 18 | if (!is_null ($publisher)) array_push ($this->entryArray, $publisher); |
|
| 119 | } |
||
| 120 | 19 | View Code Duplication | if (!in_array (PageQueryResult::SCOPE_TAG, getCurrentOption ('ignored_categories'))) { |
| 121 | 18 | $tags = Tag::getCount(); |
|
| 122 | 18 | if (!is_null ($tags)) array_push ($this->entryArray, $tags); |
|
| 123 | } |
||
| 124 | 19 | View Code Duplication | if (!in_array (PageQueryResult::SCOPE_RATING, getCurrentOption ('ignored_categories'))) { |
| 125 | 19 | $rating = Rating::getCount(); |
|
| 126 | 19 | if (!is_null ($rating)) array_push ($this->entryArray, $rating); |
|
| 127 | } |
||
| 128 | 19 | View Code Duplication | if (!in_array ("language", getCurrentOption ('ignored_categories'))) { |
| 129 | 18 | $languages = Language::getCount(); |
|
| 130 | 18 | if (!is_null ($languages)) array_push ($this->entryArray, $languages); |
|
| 131 | } |
||
| 132 | 19 | foreach ($config['cops_calibre_custom_column'] as $lookup) { |
|
| 133 | 15 | $customColumn = CustomColumnType::createByLookup($lookup); |
|
| 134 | 15 | if (!is_null ($customColumn) && $customColumn->isSearchable()) { |
|
| 135 | 15 | array_push ($this->entryArray, $customColumn->getCount()); |
|
| 136 | } |
||
| 137 | } |
||
| 138 | 19 | $this->entryArray = array_merge ($this->entryArray, Book::getCount()); |
|
| 139 | |||
| 140 | 19 | if (Base::isMultipleDatabaseEnabled ()) $this->title = Base::getDbName (); |
|
| 141 | } |
||
| 142 | 21 | } |
|
| 143 | |||
| 144 | 17 | public function isPaginated () |
|
| 150 | |||
| 151 | 2 | View Code Duplication | public function getNextLink () |
| 159 | |||
| 160 | 2 | View Code Duplication | public function getPrevLink () |
| 168 | |||
| 169 | 2 | public function getMaxPage () |
|
| 173 | |||
| 174 | 70 | public function containsBook () |
|
| 180 | } |
||
| 181 |
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.