Complex classes like FlipPage 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 FlipPage, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
323 | class FlipPage extends WebPage |
||
324 | { |
||
325 | /** The currently logged in user or null if no user is logged in */ |
||
326 | public $user; |
||
327 | /** An array of links to put in the header */ |
||
328 | public $links; |
||
329 | /** An array of notifications to draw on the page */ |
||
330 | public $notifications; |
||
331 | /** Should we draw the header? */ |
||
332 | public $header; |
||
333 | /** The login page URL */ |
||
334 | public $loginUrl; |
||
335 | /** The logout page URL */ |
||
336 | public $logoutUrl; |
||
337 | /** Should we use minified JS/CSS? */ |
||
338 | protected $minified = null; |
||
339 | /** Should we use local JS/CSS or Content Delivery Networks? */ |
||
340 | protected $cdn = null; |
||
341 | /** Draw the analytics scripts */ |
||
342 | protected $analytics = true; |
||
343 | |||
344 | /** |
||
345 | * Create a webpage with JQuery, Bootstrap, etc |
||
346 | * |
||
347 | * @param string $title The webpage title |
||
348 | * @param boolean $header Draw the header bar? |
||
349 | * |
||
350 | * @SuppressWarnings("StaticAccess") |
||
351 | */ |
||
352 | public function __construct($title, $header = true) |
||
353 | { |
||
354 | parent::__construct($title); |
||
355 | $this->setupVars(); |
||
356 | $this->add_js(JS_JQUERY, false); |
||
357 | $this->add_js(JS_FLIPSIDE, false); |
||
358 | $this->addBootstrap(); |
||
359 | $this->header = $header; |
||
360 | $this->links = array(); |
||
361 | $this->notifications = array(); |
||
362 | $this->loginUrl = 'login.php'; |
||
363 | $this->logoutUrl = 'logout.php'; |
||
364 | if(isset(FlipsideSettings::$global)) |
||
365 | { |
||
366 | if(isset(FlipsideSettings::$global['login_url'])) |
||
367 | { |
||
368 | $this->loginUrl = FlipsideSettings::$global['login_url']; |
||
369 | } |
||
370 | if(isset(FlipsideSettings::$global['logout_url'])) |
||
371 | { |
||
372 | $this->logoutUrl = FlipsideSettings::$global['logout_url']; |
||
373 | } |
||
374 | } |
||
375 | $this->user = FlipSession::getUser(); |
||
376 | $this->addAllLinks(); |
||
377 | } |
||
378 | |||
379 | /** |
||
380 | * Get the external site links for this page |
||
381 | * |
||
382 | */ |
||
383 | protected function getSites() |
||
391 | |||
392 | /** |
||
393 | * Add the links to be used in the header |
||
394 | * |
||
395 | * @SuppressWarnings("Superglobals") |
||
396 | * |
||
397 | * @todo Consider pulling the about menu from the settings file or a DB |
||
398 | */ |
||
399 | protected function addAllLinks() |
||
400 | { |
||
401 | if($this->user === false || $this->user === null) |
||
402 | { |
||
403 | if(isset($_SERVER['REQUEST_URI']) && strstr($_SERVER['REQUEST_URI'], 'logout.php') === false) |
||
404 | { |
||
405 | $this->addLink('Login', $this->loginUrl); |
||
406 | } |
||
407 | } |
||
408 | else |
||
409 | { |
||
410 | $this->add_links(); |
||
411 | $this->addLink('Logout', $this->logoutUrl); |
||
412 | } |
||
413 | $about_menu = array( |
||
414 | 'Burning Flipside'=>'https://www.burningflipside.com/about/event', |
||
415 | 'AAR, LLC'=>'https://www.burningflipside.com/organization/aar', |
||
416 | 'Privacy Policy'=>'https://www.burningflipside.com/about/privacy' |
||
417 | ); |
||
418 | $this->addLink('About', 'http://www.burningflipside.com/about', $about_menu); |
||
|
|||
419 | } |
||
420 | |||
421 | /** |
||
422 | * Setup minified and cdn class varibles from defaults or the settings file |
||
423 | */ |
||
424 | private function setupVars() |
||
425 | { |
||
426 | if($this->minified !== null && $this->cdn !== null) return; |
||
427 | $this->minified = 'min'; |
||
428 | $this->cdn = 'cdn'; |
||
429 | if(isset(FlipsideSettings::$global)) |
||
430 | { |
||
431 | if(isset(FlipsideSettings::$global['use_minified']) && !FlipsideSettings::$global['use_minified']) |
||
432 | { |
||
433 | $this->minified = 'no'; |
||
434 | } |
||
435 | if(isset(FlipsideSettings::$global['use_cdn']) && !FlipsideSettings::$global['use_cdn']) |
||
436 | { |
||
437 | $this->cdn = 'no'; |
||
438 | } |
||
439 | } |
||
440 | } |
||
441 | |||
442 | /** |
||
443 | * Add a JavaScript file from its src URI |
||
444 | * |
||
445 | * @param string $src The webpath to the JavaScript file |
||
446 | * @param boolean $async Can the JavaScript be loaded asynchronously? |
||
447 | * |
||
448 | * @deprecated 2.0.0 Please use addJSByURI() instead |
||
449 | */ |
||
450 | public function add_js_from_src($src, $async = true) |
||
451 | { |
||
452 | $this->addJSByURI($src, $async); |
||
453 | } |
||
454 | |||
455 | /** |
||
456 | * Add a JavaScript file from its src URI |
||
457 | * |
||
458 | * @param string $uri The webpath to the JavaScript file |
||
459 | * @param boolean $async Can the JavaScript be loaded asynchronously? |
||
460 | */ |
||
461 | public function addJSByURI($uri, $async = true) |
||
462 | { |
||
463 | $attributes = array('src'=>$uri, 'type'=>'text/javascript'); |
||
464 | if($async === true) |
||
465 | { |
||
466 | $attributes['async'] = true; |
||
467 | } |
||
468 | $jsTag = $this->createOpenTag('script', $attributes); |
||
469 | $closeTag = $this->createCloseTag('script'); |
||
470 | $this->addHeadTag($jsTag); |
||
471 | $this->addHeadTag($closeTag); |
||
472 | } |
||
473 | |||
474 | /** |
||
475 | * Add a Cascading Style Sheet file from its src URI |
||
476 | * |
||
477 | * @param string $src The webpath to the Cascading Style Sheet file |
||
478 | * @param boolean $import Can the CSS be loaded asynchronously? |
||
479 | * |
||
480 | * @deprecated 2.0.0 Please use addCSSByURI() instead |
||
481 | */ |
||
482 | public function add_css_from_src($src, $import = false) |
||
483 | { |
||
484 | $this->addCSSByURI($src, $import); |
||
485 | } |
||
486 | |||
487 | /** |
||
488 | * Add a Cascading Style Sheet file from its src URI |
||
489 | * |
||
490 | * @param string $src The webpath to the Cascading Style Sheet file |
||
491 | * @param boolean $async Can the CSS be loaded asynchronously? |
||
492 | */ |
||
493 | public function addCSSByURI($uri, $async = false) |
||
494 | { |
||
495 | $attributes = array('rel'=>'stylesheet', 'href'=>$uri, 'type'=>'text/css'); |
||
496 | if($async === true && $this->importSupport === true) |
||
497 | { |
||
498 | $attributes['rel'] = 'import'; |
||
499 | } |
||
500 | $cssTag = $this->createOpenTag('link', $attributes, true); |
||
501 | $this->addHeadTag($cssTag); |
||
502 | } |
||
503 | |||
504 | /** |
||
505 | * Add a JavaScript file from a set of files known to the framework |
||
506 | * |
||
507 | * @param string $type the ID of the JS file |
||
508 | * @param boolean $async Can the JS file be loaded asynchronously? |
||
509 | * |
||
510 | * @deprecated 2.0.0 Please use addWellKnownJS() instead |
||
511 | */ |
||
512 | public function addJS($type, $async = true) |
||
513 | { |
||
514 | $this->addWellKnownJS($type, $async); |
||
515 | } |
||
516 | |||
517 | public function add_js($type, $async = true) |
||
518 | { |
||
519 | $this->addWellKnownJS($type, $async); |
||
520 | } |
||
521 | |||
522 | /** |
||
523 | * Add a JavaScript file from a set of files known to the framework |
||
524 | * |
||
525 | * @param string $jsFileID the ID of the JS file |
||
526 | * @param boolean $async Can the JS file be loaded asynchronously? |
||
527 | */ |
||
528 | public function addWellKnownJS($jsFileID, $async = true) |
||
529 | { |
||
530 | global $jsArray; |
||
531 | $this->setupVars(); |
||
532 | $src = $jsArray[$jsFileID][$this->cdn][$this->minified]; |
||
533 | $this->addJSByURI($src, $async); |
||
534 | } |
||
535 | |||
536 | /** |
||
537 | * Add a CSS file from a set of files known to the framework |
||
538 | * |
||
539 | * @param string $type the ID of the CSS file |
||
540 | * @param boolean $import Can the CSS file be loaded asynchronously? |
||
541 | * |
||
542 | * @deprecated 2.0.0 Please use addWellKnownCSS() instead |
||
543 | */ |
||
544 | public function add_css($type, $import = false) |
||
545 | { |
||
546 | $this->addWellKnownCSS($type, $import); |
||
547 | } |
||
548 | |||
549 | /** |
||
550 | * Add a CSS file from a set of files known to the framework |
||
551 | * |
||
552 | * @param string $cssFileID the ID of the CSS file |
||
553 | * @param boolean $async Can the CSS file be loaded asynchronously? |
||
554 | */ |
||
555 | public function addWellKnownCSS($cssFileID, $async = true) |
||
556 | { |
||
557 | global $cssArray; |
||
558 | $this->setupVars(); |
||
559 | $src = $cssArray[$cssFileID][$this->cdn][$this->minified]; |
||
560 | $this->addCSSByURI($src, $async); |
||
561 | } |
||
562 | |||
563 | /** |
||
564 | * Add files needed by the Bootstrap framework |
||
565 | */ |
||
566 | private function addBootstrap() |
||
567 | { |
||
568 | $this->add_js(JS_BOOTSTRAP, false); |
||
569 | $this->addWellKnownCSS(CSS_BOOTSTRAP); |
||
570 | $this->addWellKnownCSS(CSS_FONTAWESOME); |
||
571 | } |
||
572 | |||
573 | protected function getSiteLinksForHeader() |
||
584 | |||
585 | protected function getHrefForDropdown(&$link) |
||
595 | |||
596 | protected function getDropdown($link, $name) |
||
597 | { |
||
598 | $ret = '<li class="dropdown">'; |
||
599 | $href = $this->getHrefForDropdown($link); |
||
600 | $ret .= '<a href="'.$href.'" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">'.$name.' <span class="caret"></span></a>'; |
||
601 | $ret .= '<ul class="dropdown-menu">'; |
||
602 | $subNames = array_keys($link); |
||
603 | foreach($subNames as $subName) |
||
604 | { |
||
605 | $ret .= $this->getLinkByName($subName, $link); |
||
606 | } |
||
607 | $ret .= '</ul></li>'; |
||
608 | return $ret; |
||
609 | } |
||
610 | |||
611 | protected function getLinkByName($name, $links) |
||
623 | |||
624 | protected function getLinksMenus() |
||
634 | |||
635 | /** |
||
636 | * Draw the header for the page |
||
637 | */ |
||
638 | protected function addHeader() |
||
639 | { |
||
640 | $sites = $this->getSiteLinksForHeader(); |
||
641 | $links = $this->getLinksMenus(); |
||
642 | $header = '<nav class="navbar navbar-default navbar-fixed-top"> |
||
643 | <div class="container-fluid"> |
||
644 | <!-- Brand and toggle get grouped for better mobile display --> |
||
645 | <div class="navbar-header"> |
||
646 | <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse" aria-expanded="false"> |
||
647 | <span class="sr-only">Toggle navigation</span> |
||
648 | <span class="icon-bar"></span> |
||
649 | <span class="icon-bar"></span> |
||
650 | <span class="icon-bar"></span> |
||
651 | </button> |
||
652 | <a class="navbar-brand" href="#"> |
||
653 | <picture> |
||
654 | <source srcset="/img/common/logo.svg" style="width: 30px; height:30px"/> |
||
655 | <img alt="Burning Flipside" src="/img/common/logo.png" style="width: 30px; height:30px"/> |
||
656 | </picture> |
||
657 | </a> |
||
658 | </div> |
||
659 | <!-- Collect the nav links, forms, and other content for toggling --> |
||
660 | <div class="collapse navbar-collapse" id="navbar-collapse"> |
||
661 | <ul id="site_nav" class="nav navbar-nav"> |
||
662 | '.$sites.' |
||
663 | </ul> |
||
664 | <ul class="nav navbar-nav navbar-right"> |
||
665 | '.$links.' |
||
666 | </ul> |
||
667 | </div> |
||
668 | </div> |
||
669 | </nav>'; |
||
670 | $this->body = $header.$this->body; |
||
671 | $this->body_tags .= 'style="padding-top: 60px;"'; |
||
672 | } |
||
673 | |||
674 | /** Notification that is green for success */ |
||
675 | const NOTIFICATION_SUCCESS = 'alert-success'; |
||
676 | /** Notification that is blue for infomrational messages */ |
||
677 | const NOTIFICATION_INFO = 'alert-info'; |
||
678 | /** Notification that is yellow for warning */ |
||
679 | const NOTIFICATION_WARNING = 'alert-warning'; |
||
680 | /** Notification that is red for error */ |
||
681 | const NOTIFICATION_FAILED = 'alert-danger'; |
||
682 | |||
683 | /** |
||
684 | * Add a notification to the page |
||
685 | * |
||
686 | * @param string $msg The message to show in the notifcation |
||
687 | * @param string $sev The severity of the notifcation |
||
688 | * @param boolean $dismissible Can the user dismiss the notificaton? |
||
689 | * |
||
690 | * @deprecated 2.0.0 Use the addNotification function instead |
||
691 | */ |
||
692 | public function add_notification($msg, $sev = self::NOTIFICATION_INFO, $dismissible = 1) |
||
693 | { |
||
694 | $notice = array('msg'=>$msg, 'sev'=>$sev, 'dismissible'=>$dismissible); |
||
695 | array_push($this->notifications, $notice); |
||
696 | } |
||
697 | |||
698 | /** |
||
699 | * Add a notification to the page |
||
700 | * |
||
701 | * @param string $message The message to show in the notifcation |
||
702 | * @param string $sevity The severity of the notifcation |
||
703 | * @param boolean $dismissible Can the user dismiss the notificaton? |
||
704 | */ |
||
705 | public function addNotification($message, $severity = self::NOTIFICATION_INFO, $dismissible = true) |
||
706 | { |
||
707 | array_push($this->notifications, array('msg'=>$message, 'sev'=>$severity, 'dismissible'=>$dismissible)); |
||
708 | } |
||
709 | |||
710 | /** |
||
711 | * Draw all notifications to the page |
||
712 | */ |
||
713 | private function renderNotifications() |
||
714 | { |
||
715 | $count = count($this->notifications); |
||
716 | if($count === 0) |
||
717 | { |
||
718 | return; |
||
719 | } |
||
720 | for($i = 0; $i < $count; $i++) |
||
721 | { |
||
722 | $class = 'alert '.$this->notifications[$i]['sev']; |
||
723 | $button = ''; |
||
724 | if($this->notifications[$i]['dismissible']) |
||
725 | { |
||
726 | $class .= ' alert-dismissible'; |
||
727 | $button = '<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>'; |
||
728 | } |
||
729 | $prefix = ''; |
||
730 | switch($this->notifications[$i]['sev']) |
||
731 | { |
||
732 | case self::NOTIFICATION_INFO: |
||
733 | $prefix = '<strong>Notice:</strong> '; |
||
734 | break; |
||
735 | case self::NOTIFICATION_WARNING: |
||
736 | $prefix = '<strong>Warning!</strong> '; |
||
737 | break; |
||
738 | case self::NOTIFICATION_FAILED: |
||
739 | $prefix = '<strong>Warning!</strong> '; |
||
740 | break; |
||
741 | } |
||
742 | $style = ''; |
||
743 | if(($i + 1) < count($this->notifications)) |
||
744 | { |
||
745 | //Not the last notification, remove the end margin |
||
746 | $style = 'style="margin: 0px;"'; |
||
747 | } |
||
748 | $this->body = ' |
||
749 | <div class="'.$class.'" role="alert" '.$style.'> |
||
750 | '.$button.$prefix.$this->notifications[$i]['msg'].' |
||
751 | </div> |
||
752 | '.$this->body; |
||
753 | } |
||
754 | } |
||
755 | |||
756 | /** |
||
757 | * Add the no script block |
||
758 | */ |
||
759 | private function addNoScript() |
||
768 | |||
769 | /** |
||
770 | * Add the analytics script block |
||
771 | */ |
||
772 | private function addAnalyticsBlock() |
||
789 | |||
790 | /** |
||
791 | * Draw the page |
||
792 | * |
||
793 | * @param boolean $header Draw the header |
||
794 | * @param boolean $analytics Include analytics on the page |
||
795 | */ |
||
796 | public function printPage($header = true) |
||
797 | { |
||
798 | $this->renderNotifications(); |
||
799 | $this->addNoScript(); |
||
800 | $this->addAnalyticsBlock(); |
||
801 | if($this->header || $header) |
||
802 | { |
||
803 | $this->addHeader(); |
||
804 | } |
||
805 | parent::printPage(); |
||
806 | } |
||
807 | |||
808 | /** |
||
809 | * Add a link to the header |
||
810 | * |
||
811 | * @param string $name The name of the link |
||
812 | * @param false|string $url The URL to link to |
||
813 | * @param false|array $subment Any submenu items for the dropdown |
||
814 | * |
||
815 | * @deprecated 1.0.0 Use addLink instead |
||
816 | */ |
||
817 | public function add_link($name, $url = false, $submenu = false) |
||
818 | { |
||
819 | $this->addLink($name, $url, $submenu); |
||
820 | } |
||
821 | |||
822 | /** |
||
823 | * Add a link to the header |
||
824 | * |
||
825 | * @param string $name The name of the link |
||
826 | * @param false|string $url The URL to link to |
||
827 | * @param false|array $subment Any submenu items for the dropdown |
||
828 | */ |
||
829 | public function addLink($name, $url = false, $submenu = false) |
||
830 | { |
||
831 | if(is_array($submenu)) |
||
832 | { |
||
833 | $submenu['_'] = $url; |
||
834 | $this->links[$name] = $submenu; |
||
835 | } |
||
836 | else |
||
837 | { |
||
838 | $this->links[$name] = $url; |
||
839 | } |
||
840 | } |
||
841 | |||
842 | /** |
||
843 | * Add the login form to the page |
||
844 | * |
||
845 | * @SuppressWarnings("StaticAccess") |
||
846 | */ |
||
847 | public function add_login_form() |
||
884 | |||
885 | /** |
||
886 | * Add additional links |
||
887 | */ |
||
888 | public function add_links() |
||
891 | } |
||
892 | /* vim: set tabstop=4 shiftwidth=4 expandtab: */ |
||
893 |
It seems like the type of the argument is not accepted by the function/method which you are calling.
In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.
We suggest to add an explicit type cast like in the following example: