| Total Complexity | 58 |
| Total Lines | 490 |
| Duplicated Lines | 0 % |
| Changes | 2 | ||
| Bugs | 0 | Features | 0 |
Complex classes like ConstructPageIndex 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.
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 ConstructPageIndex, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 46 | class ConstructPageIndex extends AbstractModel |
||
| 47 | { |
||
| 48 | /** @var int stating page */ |
||
| 49 | private $start; |
||
| 50 | |||
| 51 | /** @var array holds the desired options for the index all, prev_next, all_selected */ |
||
| 52 | private $show; |
||
| 53 | |||
| 54 | /** @var int max page # to show */ |
||
| 55 | private $max_value; |
||
| 56 | |||
| 57 | /** @var int */ |
||
| 58 | private $num_per_page; |
||
| 59 | |||
| 60 | /** @var bool */ |
||
| 61 | private $flexible_start; |
||
| 62 | |||
| 63 | /** @var string */ |
||
| 64 | private $base_url; |
||
| 65 | |||
| 66 | /** @var string */ |
||
| 67 | private $base_link; |
||
| 68 | |||
| 69 | /** @var bool If we have tried to navigate off the end */ |
||
| 70 | private $start_invalid; |
||
| 71 | |||
| 72 | /** @var int */ |
||
| 73 | private $counter; |
||
| 74 | |||
| 75 | /** @var mixed|string What we are after */ |
||
| 76 | private $pageindex; |
||
| 77 | |||
| 78 | /** @var int the maximum number of pages in the index */ |
||
| 79 | private $maxPages; |
||
| 80 | |||
| 81 | /** |
||
| 82 | * ConstructPageIndex constructor. |
||
| 83 | * |
||
| 84 | * @param string $base_url |
||
| 85 | * @param int $start |
||
| 86 | * @param int $max_value |
||
| 87 | * @param int $num_per_page |
||
| 88 | * @param bool $flexible_start |
||
| 89 | * @param array $show |
||
| 90 | */ |
||
| 91 | public function __construct($base_url, &$start, $max_value, $num_per_page, $flexible_start = false, $show = []) |
||
| 106 | } |
||
| 107 | |||
| 108 | /** |
||
| 109 | * Does what it says, creates the handy pageindex navigation bar |
||
| 110 | */ |
||
| 111 | public function createPageIndex(): void |
||
| 112 | { |
||
| 113 | global $context; |
||
| 114 | |||
| 115 | $this->setStart(); |
||
| 116 | $context['current_page'] = $this->start / $this->num_per_page; |
||
| 117 | |||
| 118 | $this->setBaseLink(); |
||
| 119 | |||
| 120 | if ($this->max_value <= $this->num_per_page) |
||
| 121 | { |
||
| 122 | $pageindex = $this->noLinks(); |
||
| 123 | } |
||
| 124 | elseif (empty($this->_modSettings['compactTopicPagesEnable'])) |
||
| 125 | { |
||
| 126 | $pageindex = $this->simpleLinks(); |
||
| 127 | } |
||
| 128 | else |
||
| 129 | { |
||
| 130 | $pageindex = $this->compactLinks(); |
||
| 131 | } |
||
| 132 | |||
| 133 | // Here it is, use getPageIndex to fetch it |
||
| 134 | $this->pageindex = $this->showAll($pageindex); |
||
| 135 | } |
||
| 136 | |||
| 137 | /** |
||
| 138 | * Returns the completed page index |
||
| 139 | * |
||
| 140 | * @return string |
||
| 141 | */ |
||
| 142 | public function getPageIndex(): string |
||
| 145 | } |
||
| 146 | |||
| 147 | /** |
||
| 148 | * Validate and sets the page starting point |
||
| 149 | * |
||
| 150 | * @return int |
||
| 151 | */ |
||
| 152 | public function setStart(): int |
||
| 153 | { |
||
| 154 | // Save whether $start was less than 0 or not. |
||
| 155 | $this->start_invalid = $this->start < 0; |
||
| 156 | |||
| 157 | // Make sure we have a valid number per page to avoid division by zero |
||
| 158 | if ($this->num_per_page <= 0) |
||
| 159 | { |
||
| 160 | return $this->start = 0; |
||
| 161 | } |
||
| 162 | |||
| 163 | // Make sure $start is a proper variable - not less than 0. |
||
| 164 | if ($this->start_invalid) |
||
| 165 | { |
||
| 166 | return $this->start = 0; |
||
| 167 | } |
||
| 168 | |||
| 169 | // Not greater than the upper bound. |
||
| 170 | if ($this->start >= $this->max_value) |
||
| 171 | { |
||
| 172 | $upper = $this->max_value % $this->num_per_page === 0 |
||
| 173 | ? $this->num_per_page |
||
| 174 | : $this->max_value % $this->num_per_page; |
||
| 175 | |||
| 176 | return $this->start = max(0, $this->max_value - $upper); |
||
| 177 | } |
||
| 178 | |||
| 179 | // And it has to be a multiple of $num_per_page! |
||
| 180 | return $this->start = max(0, $this->start - ($this->start % $this->num_per_page)); |
||
| 181 | } |
||
| 182 | |||
| 183 | /** |
||
| 184 | * Sets the base url that navigation will start from. |
||
| 185 | * Will replace {base_link} and {scripturl} as needed. |
||
| 186 | * Uses ['page_index_template']['base_link'] template |
||
| 187 | */ |
||
| 188 | private function setBaseLink(): void |
||
| 189 | { |
||
| 190 | global $scripturl, $settings; |
||
| 191 | |||
| 192 | $base_link = str_replace('{base_link}', ($this->flexible_start |
||
| 193 | ? $this->base_url |
||
| 194 | : strtr($this->base_url, ['%' => '%%']) . ';start=%1$d'), $settings['page_index_template']['base_link']); |
||
| 195 | |||
| 196 | $this->base_link = str_replace('{scripturl}', $scripturl, $base_link); |
||
| 197 | } |
||
| 198 | |||
| 199 | /** |
||
| 200 | * When there is only one page, no need to show an index |
||
| 201 | * |
||
| 202 | * @return string |
||
| 203 | */ |
||
| 204 | private function noLinks(): string |
||
| 205 | { |
||
| 206 | global $settings; |
||
| 207 | |||
| 208 | return $settings['page_index_template']['none'] ?? '<li class="hide"></li>'; |
||
| 209 | } |
||
| 210 | |||
| 211 | /** |
||
| 212 | * Simple prev 1 2 3 4 next style links |
||
| 213 | * |
||
| 214 | * @return string |
||
| 215 | */ |
||
| 216 | private function simpleLinks(): string |
||
| 217 | { |
||
| 218 | $pageindex = $this->setLeftNavigation(); |
||
| 219 | $pageindex .= $this->setAll(); |
||
| 220 | |||
| 221 | return $pageindex . $this->setRightNavigation(); |
||
| 222 | } |
||
| 223 | |||
| 224 | /** |
||
| 225 | * AKA previous button for simple navigation index |
||
| 226 | * uses ['page_index_template']['previous_page'] template |
||
| 227 | * |
||
| 228 | * @return string |
||
| 229 | */ |
||
| 230 | private function setLeftNavigation(): string |
||
| 231 | { |
||
| 232 | global $settings, $txt; |
||
| 233 | |||
| 234 | // Previous page language substitution into the page index template |
||
| 235 | $previous = str_replace('{prev_txt}', $txt['prev'], $settings['page_index_template']['previous_page']); |
||
| 236 | |||
| 237 | return ($this->start === 0 || !$this->show['prev_next']) |
||
| 238 | ? ' ' |
||
| 239 | : sprintf($this->base_link, $this->start - $this->num_per_page, $previous); |
||
| 240 | } |
||
| 241 | |||
| 242 | /** |
||
| 243 | * AKA all the pages 1 2 3 4 5 for simple navigation |
||
| 244 | * Uses ['page_index_template']['current_page'] template |
||
| 245 | * |
||
| 246 | * @return string |
||
| 247 | */ |
||
| 248 | private function setAll(): string |
||
| 249 | { |
||
| 250 | global $settings; |
||
| 251 | |||
| 252 | // Show all the pages. |
||
| 253 | $display_page = 1; |
||
| 254 | $pageindex = ''; |
||
| 255 | for ($counter = 0; $counter < $this->max_value; $counter += $this->num_per_page) |
||
| 256 | { |
||
| 257 | $pageindex .= $this->start === $counter && !$this->start_invalid && empty($this->show['all_selected']) |
||
| 258 | ? sprintf($settings['page_index_template']['current_page'], $display_page++) |
||
| 259 | : sprintf($this->base_link, $counter, $display_page++); |
||
| 260 | } |
||
| 261 | |||
| 262 | $this->counter = $counter; |
||
| 263 | |||
| 264 | return $pageindex; |
||
| 265 | } |
||
| 266 | |||
| 267 | /** |
||
| 268 | * AKA the next button for simple navigation. Uses 'page_index_template']['next_page'] |
||
| 269 | * template |
||
| 270 | * |
||
| 271 | * @return string |
||
| 272 | */ |
||
| 273 | private function setRightNavigation(): string |
||
| 293 | } |
||
| 294 | |||
| 295 | /** |
||
| 296 | * Compact links, good for displaying many available pages bar |
||
| 297 | * prev page >1< ... 6 7 [8] 9 10 ... 15) |
||
| 298 | * |
||
| 299 | * @return string |
||
| 300 | */ |
||
| 301 | private function compactLinks(): string |
||
| 302 | { |
||
| 303 | $pageindex = ''; |
||
| 304 | |||
| 305 | // If they didn't enter an odd value, pretend they did. |
||
| 306 | $PageContiguous = ($this->_modSettings['compactTopicPagesContiguous'] - ($this->_modSettings['compactTopicPagesContiguous'] % 2)) / 2; |
||
| 307 | |||
| 308 | // Start with previous if there is one |
||
| 309 | $pageindex .= $this->compactPreviousNavigation(); |
||
| 310 | |||
| 311 | // Show the first page. (prev page >1< ... 6 7 [8] 9 10 ... 15) |
||
| 312 | if ($this->start > $this->num_per_page * $PageContiguous) |
||
| 313 | { |
||
| 314 | $pageindex .= sprintf($this->base_link, 0, '1'); |
||
| 315 | } |
||
| 316 | |||
| 317 | // Show the ... after the first page. (prev page 1 >...< 6 7 [8] 9 10 ... 15 next page) |
||
| 318 | if ($this->start > $this->num_per_page * ($PageContiguous + 1)) |
||
| 319 | { |
||
| 320 | $pageindex .= $this->compactContinuation($PageContiguous, 'before'); |
||
| 321 | } |
||
| 322 | |||
| 323 | // Show a few pages before the current one. (prev page 1 ... >6 7< [8] 9 10 ... 15 next page) |
||
| 324 | $pageindex .= $this->compactBeforeCurrent($PageContiguous); |
||
| 325 | |||
| 326 | // Show the current page. (prev page 1 ... 6 7 >[8]< 9 10 ... 15 next page) |
||
| 327 | $pageindex .= $this->compactCurrent(); |
||
| 328 | |||
| 329 | // Show a few pages after the current one... (prev page 1 ... 6 7 [8] >9 10< ... 15 next page) |
||
| 330 | $pageindex .= $this->compactAfterCurrent($PageContiguous); |
||
| 331 | |||
| 332 | // Show the '...' part near the end. (prev page 1 ... 6 7 [8] 9 10 >...< 15 next page) |
||
| 333 | if ($this->start + $this->num_per_page * ($PageContiguous + 1) < $this->getMaxPages()) |
||
| 334 | { |
||
| 335 | $pageindex .= $this->compactContinuation($PageContiguous, 'after'); |
||
| 336 | } |
||
| 337 | |||
| 338 | // Show the last number in the list. (prev page 1 ... 6 7 [8] 9 10 ... >15< next page) |
||
| 339 | if ($this->start + $this->num_per_page * $PageContiguous < $this->getMaxPages()) |
||
| 340 | { |
||
| 341 | $pageindex .= sprintf($this->base_link, $this->getMaxPages(), $this->getMaxPages() / $this->num_per_page + 1); |
||
| 342 | } |
||
| 343 | |||
| 344 | // Show the "next page" link. (prev page 1 ... 6 7 [8] 9 10 ... 15 >next page<) |
||
| 345 | $pageindex .= $this->compactNextNavigation(); |
||
| 346 | |||
| 347 | return $pageindex; |
||
| 348 | } |
||
| 349 | |||
| 350 | /** |
||
| 351 | * Shows the previous page link |
||
| 352 | * Uses ['page_index_template']['previous_page' template |
||
| 353 | * |
||
| 354 | * @return string |
||
| 355 | */ |
||
| 356 | private function compactPreviousNavigation(): string |
||
| 357 | { |
||
| 358 | global $settings, $txt; |
||
| 359 | |||
| 360 | // Show the "prev page" link. (>prev page< 1 ... 6 7 [8] 9 10 ... 15 next page) |
||
| 361 | if (!empty($this->start) && $this->show['prev_next']) |
||
| 362 | { |
||
| 363 | $previous = str_replace('{prev_txt}', $txt['prev'], $settings['page_index_template']['previous_page']); |
||
| 364 | |||
| 365 | return sprintf($this->base_link, $this->start - $this->num_per_page, $previous); |
||
| 366 | } |
||
| 367 | |||
| 368 | return ''; |
||
| 369 | } |
||
| 370 | |||
| 371 | /** |
||
| 372 | * Shows the ... continuation link, helper function for before or after |
||
| 373 | * |
||
| 374 | * @param int $PageContiguous |
||
| 375 | * @param string $position before or after |
||
| 376 | * @return string|string[] |
||
| 377 | */ |
||
| 378 | private function compactContinuation($PageContiguous, $position) |
||
| 379 | { |
||
| 380 | global $settings; |
||
| 381 | |||
| 382 | if ($position === 'before') |
||
| 383 | { |
||
| 384 | $firstpage = $this->num_per_page; |
||
| 385 | $lastpage = $this->start - $this->num_per_page * $PageContiguous; |
||
| 386 | } |
||
| 387 | else |
||
| 388 | { |
||
| 389 | $firstpage = $this->start + $this->num_per_page * ($PageContiguous + 1); |
||
| 390 | $lastpage = $this->getMaxPages(); |
||
| 391 | } |
||
| 392 | |||
| 393 | return str_replace( |
||
| 394 | '{custom}', |
||
| 395 | 'data-baseurl="' . htmlspecialchars(JavaScriptEscape( |
||
| 396 | strtr($this->flexible_start |
||
| 397 | ? $this->base_url |
||
| 398 | : strtr($this->base_url, ['%' => '%%']) . ';start=%1$d', ['{scripturl}' => ''] |
||
| 399 | ) |
||
| 400 | ), ENT_COMPAT, 'UTF-8') . |
||
| 401 | '" data-perpage="' . $this->num_per_page . |
||
| 402 | '" data-firstpage="' . $firstpage . |
||
| 403 | '" data-lastpage="' . $lastpage . '"', |
||
| 404 | $settings['page_index_template']['expand_pages'] |
||
| 405 | ); |
||
| 406 | } |
||
| 407 | |||
| 408 | /** |
||
| 409 | * The maximum number of pages for this index |
||
| 410 | * |
||
| 411 | * @return int |
||
| 412 | */ |
||
| 413 | private function tmpMaxPages() |
||
| 414 | { |
||
| 415 | return (int) (($this->max_value - 1) / $this->num_per_page) * $this->num_per_page; |
||
| 416 | } |
||
| 417 | |||
| 418 | /** |
||
| 419 | * Simply returns the maxpages for the index |
||
| 420 | * |
||
| 421 | * @return int |
||
| 422 | */ |
||
| 423 | private function getMaxPages() |
||
| 424 | { |
||
| 425 | $this->maxPages = $this->maxPages ?? $this->tmpMaxPages(); |
||
| 426 | |||
| 427 | return $this->maxPages; |
||
| 428 | } |
||
| 429 | |||
| 430 | /** |
||
| 431 | * The numbered pages before the current one. (prev page 1 ... >6 7< [8] 9 10 ... 15 next page) |
||
| 432 | * |
||
| 433 | * @param $PageContiguous |
||
| 434 | * @return string |
||
| 435 | */ |
||
| 436 | private function compactBeforeCurrent($PageContiguous): string |
||
| 449 | } |
||
| 450 | |||
| 451 | /** |
||
| 452 | * The current page. (prev page 1 ... 6 7 >[8]< 9 10 ... 15 next page) |
||
| 453 | * Uses ['page_index_template']['current_page'] template |
||
| 454 | * |
||
| 455 | * @return string |
||
| 456 | */ |
||
| 457 | private function compactCurrent(): string |
||
| 467 | } |
||
| 468 | |||
| 469 | /** |
||
| 470 | * The pages after the current one... (prev page 1 ... 6 7 [8] >9 10< ... 15 next page) |
||
| 471 | * |
||
| 472 | * @param $PageContiguous |
||
| 473 | * @return string |
||
| 474 | */ |
||
| 475 | private function compactAfterCurrent($PageContiguous): string |
||
| 476 | { |
||
| 477 | $pageindex = ''; |
||
| 478 | for ($nCont = 1; $nCont <= $PageContiguous; $nCont++) |
||
| 479 | { |
||
| 480 | if ($this->start + $this->num_per_page * $nCont <= $this->getMaxPages()) |
||
| 481 | { |
||
| 482 | $tmpStart = $this->start + $this->num_per_page * $nCont; |
||
| 483 | $pageindex .= sprintf($this->base_link, $tmpStart, $tmpStart / $this->num_per_page + 1); |
||
| 484 | } |
||
| 485 | } |
||
| 486 | |||
| 487 | return $pageindex; |
||
| 488 | } |
||
| 489 | |||
| 490 | /** |
||
| 491 | * Show the "next page" link. (prev page 1 ... 6 7 [8] 9 10 ... 15 >next page<) |
||
| 492 | * Uses ['page_index_template']['next_page'] template |
||
| 493 | * |
||
| 494 | * @return string |
||
| 495 | */ |
||
| 496 | private function compactNextNavigation(): string |
||
| 508 | } |
||
| 509 | |||
| 510 | /** |
||
| 511 | * The show-all button if requested/ |
||
| 512 | * Uses 'page_index_template']['current_page'] template |
||
| 513 | * |
||
| 514 | * @param $pageindex |
||
| 515 | * @return mixed|string |
||
| 516 | */ |
||
| 517 | private function showAll($pageindex) |
||
| 538 |