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 WebInstaller 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 WebInstaller, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 30 | class WebInstaller extends Installer { |
||
| 31 | |||
| 32 | /** |
||
| 33 | * @var WebInstallerOutput |
||
| 34 | */ |
||
| 35 | public $output; |
||
| 36 | |||
| 37 | /** |
||
| 38 | * WebRequest object. |
||
| 39 | * |
||
| 40 | * @var WebRequest |
||
| 41 | */ |
||
| 42 | public $request; |
||
| 43 | |||
| 44 | /** |
||
| 45 | * Cached session array. |
||
| 46 | * |
||
| 47 | * @var array[] |
||
| 48 | */ |
||
| 49 | protected $session; |
||
| 50 | |||
| 51 | /** |
||
| 52 | * Captured PHP error text. Temporary. |
||
| 53 | * |
||
| 54 | * @var string[] |
||
| 55 | */ |
||
| 56 | protected $phpErrors; |
||
| 57 | |||
| 58 | /** |
||
| 59 | * The main sequence of page names. These will be displayed in turn. |
||
| 60 | * |
||
| 61 | * To add a new installer page: |
||
| 62 | * * Add it to this WebInstaller::$pageSequence property |
||
| 63 | * * Add a "config-page-<name>" message |
||
| 64 | * * Add a "WebInstaller<name>" class |
||
| 65 | * |
||
| 66 | * @var string[] |
||
| 67 | */ |
||
| 68 | public $pageSequence = [ |
||
| 69 | 'Language', |
||
| 70 | 'ExistingWiki', |
||
| 71 | 'Welcome', |
||
| 72 | 'DBConnect', |
||
| 73 | 'Upgrade', |
||
| 74 | 'DBSettings', |
||
| 75 | 'Name', |
||
| 76 | 'Options', |
||
| 77 | 'Install', |
||
| 78 | 'Complete', |
||
| 79 | ]; |
||
| 80 | |||
| 81 | /** |
||
| 82 | * Out of sequence pages, selectable by the user at any time. |
||
| 83 | * |
||
| 84 | * @var string[] |
||
| 85 | */ |
||
| 86 | protected $otherPages = [ |
||
| 87 | 'Restart', |
||
| 88 | 'Readme', |
||
| 89 | 'ReleaseNotes', |
||
| 90 | 'Copying', |
||
| 91 | 'UpgradeDoc', // Can't use Upgrade due to Upgrade step |
||
| 92 | ]; |
||
| 93 | |||
| 94 | /** |
||
| 95 | * Array of pages which have declared that they have been submitted, have validated |
||
| 96 | * their input, and need no further processing. |
||
| 97 | * |
||
| 98 | * @var bool[] |
||
| 99 | */ |
||
| 100 | protected $happyPages; |
||
| 101 | |||
| 102 | /** |
||
| 103 | * List of "skipped" pages. These are pages that will automatically continue |
||
| 104 | * to the next page on any GET request. To avoid breaking the "back" button, |
||
| 105 | * they need to be skipped during a back operation. |
||
| 106 | * |
||
| 107 | * @var bool[] |
||
| 108 | */ |
||
| 109 | protected $skippedPages; |
||
| 110 | |||
| 111 | /** |
||
| 112 | * Flag indicating that session data may have been lost. |
||
| 113 | * |
||
| 114 | * @var bool |
||
| 115 | */ |
||
| 116 | public $showSessionWarning = false; |
||
| 117 | |||
| 118 | /** |
||
| 119 | * Numeric index of the page we're on |
||
| 120 | * |
||
| 121 | * @var int |
||
| 122 | */ |
||
| 123 | protected $tabIndex = 1; |
||
| 124 | |||
| 125 | /** |
||
| 126 | * Name of the page we're on |
||
| 127 | * |
||
| 128 | * @var string |
||
| 129 | */ |
||
| 130 | protected $currentPageName; |
||
| 131 | |||
| 132 | /** |
||
| 133 | * Constructor. |
||
| 134 | * |
||
| 135 | * @param WebRequest $request |
||
| 136 | */ |
||
| 137 | public function __construct( WebRequest $request ) { |
||
| 147 | |||
| 148 | /** |
||
| 149 | * Main entry point. |
||
| 150 | * |
||
| 151 | * @param array[] $session Initial session array |
||
| 152 | * |
||
| 153 | * @return array[] New session array |
||
| 154 | */ |
||
| 155 | public function execute( array $session ) { |
||
| 317 | |||
| 318 | /** |
||
| 319 | * Find the next page in sequence that hasn't been completed |
||
| 320 | * @return int |
||
| 321 | */ |
||
| 322 | public function getLowestUnhappy() { |
||
| 329 | |||
| 330 | /** |
||
| 331 | * Start the PHP session. This may be called before execute() to start the PHP session. |
||
| 332 | * |
||
| 333 | * @throws Exception |
||
| 334 | * @return bool |
||
| 335 | */ |
||
| 336 | public function startSession() { |
||
| 359 | |||
| 360 | /** |
||
| 361 | * Get a hash of data identifying this MW installation. |
||
| 362 | * |
||
| 363 | * This is used by mw-config/index.php to prevent multiple installations of MW |
||
| 364 | * on the same cookie domain from interfering with each other. |
||
| 365 | * |
||
| 366 | * @return string |
||
| 367 | */ |
||
| 368 | public function getFingerprint() { |
||
| 387 | |||
| 388 | /** |
||
| 389 | * Show an error message in a box. Parameters are like wfMessage(), or |
||
| 390 | * alternatively, pass a Message object in. |
||
| 391 | * @param string|Message $msg |
||
| 392 | */ |
||
| 393 | public function showError( $msg /*...*/ ) { |
||
| 403 | |||
| 404 | /** |
||
| 405 | * Temporary error handler for session start debugging. |
||
| 406 | * |
||
| 407 | * @param int $errno Unused |
||
| 408 | * @param string $errstr |
||
| 409 | */ |
||
| 410 | public function errorHandler( $errno, $errstr ) { |
||
| 413 | |||
| 414 | /** |
||
| 415 | * Clean up from execute() |
||
| 416 | * |
||
| 417 | * @return array[] |
||
| 418 | */ |
||
| 419 | public function finish() { |
||
| 428 | |||
| 429 | /** |
||
| 430 | * We're restarting the installation, reset the session, happyPages, etc |
||
| 431 | */ |
||
| 432 | public function reset() { |
||
| 437 | |||
| 438 | /** |
||
| 439 | * Get a URL for submission back to the same script. |
||
| 440 | * |
||
| 441 | * @param string[] $query |
||
| 442 | * |
||
| 443 | * @return string |
||
| 444 | */ |
||
| 445 | public function getUrl( $query = [] ) { |
||
| 456 | |||
| 457 | /** |
||
| 458 | * Get a WebInstallerPage by name. |
||
| 459 | * |
||
| 460 | * @param string $pageName |
||
| 461 | * @return WebInstallerPage |
||
| 462 | */ |
||
| 463 | public function getPageByName( $pageName ) { |
||
| 468 | |||
| 469 | /** |
||
| 470 | * Get a session variable. |
||
| 471 | * |
||
| 472 | * @param string $name |
||
| 473 | * @param array $default |
||
| 474 | * |
||
| 475 | * @return array |
||
| 476 | */ |
||
| 477 | View Code Duplication | public function getSession( $name, $default = null ) { |
|
| 484 | |||
| 485 | /** |
||
| 486 | * Set a session variable. |
||
| 487 | * |
||
| 488 | * @param string $name Key for the variable |
||
| 489 | * @param mixed $value |
||
| 490 | */ |
||
| 491 | public function setSession( $name, $value ) { |
||
| 494 | |||
| 495 | /** |
||
| 496 | * Get the next tabindex attribute value. |
||
| 497 | * |
||
| 498 | * @return int |
||
| 499 | */ |
||
| 500 | public function nextTabIndex() { |
||
| 503 | |||
| 504 | /** |
||
| 505 | * Initializes language-related variables. |
||
| 506 | */ |
||
| 507 | public function setupLanguage() { |
||
| 521 | |||
| 522 | /** |
||
| 523 | * Retrieves MediaWiki language from Accept-Language HTTP header. |
||
| 524 | * |
||
| 525 | * @return string |
||
| 526 | */ |
||
| 527 | public function getAcceptLanguage() { |
||
| 541 | |||
| 542 | /** |
||
| 543 | * Called by execute() before page output starts, to show a page list. |
||
| 544 | * |
||
| 545 | * @param string $currentPageName |
||
| 546 | */ |
||
| 547 | private function startPageWrapper( $currentPageName ) { |
||
| 581 | |||
| 582 | /** |
||
| 583 | * Get a list item for the page list. |
||
| 584 | * |
||
| 585 | * @param string $pageName |
||
| 586 | * @param bool $enabled |
||
| 587 | * @param string $currentPageName |
||
| 588 | * |
||
| 589 | * @return string |
||
| 590 | */ |
||
| 591 | private function getPageListItem( $pageName, $enabled, $currentPageName ) { |
||
| 637 | |||
| 638 | /** |
||
| 639 | * Output some stuff after a page is finished. |
||
| 640 | */ |
||
| 641 | private function endPageWrapper() { |
||
| 648 | |||
| 649 | /** |
||
| 650 | * Get HTML for an error box with an icon. |
||
| 651 | * |
||
| 652 | * @param string $text Wikitext, get this with wfMessage()->plain() |
||
| 653 | * |
||
| 654 | * @return string |
||
| 655 | */ |
||
| 656 | public function getErrorBox( $text ) { |
||
| 659 | |||
| 660 | /** |
||
| 661 | * Get HTML for a warning box with an icon. |
||
| 662 | * |
||
| 663 | * @param string $text Wikitext, get this with wfMessage()->plain() |
||
| 664 | * |
||
| 665 | * @return string |
||
| 666 | */ |
||
| 667 | public function getWarningBox( $text ) { |
||
| 670 | |||
| 671 | /** |
||
| 672 | * Get HTML for an info box with an icon. |
||
| 673 | * |
||
| 674 | * @param string $text Wikitext, get this with wfMessage()->plain() |
||
| 675 | * @param string|bool $icon Icon name, file in mw-config/images. Default: false |
||
| 676 | * @param string|bool $class Additional class name to add to the wrapper div. Default: false. |
||
| 677 | * |
||
| 678 | * @return string |
||
| 679 | */ |
||
| 680 | public function getInfoBox( $text, $icon = false, $class = false ) { |
||
| 689 | |||
| 690 | /** |
||
| 691 | * Get small text indented help for a preceding form field. |
||
| 692 | * Parameters like wfMessage(). |
||
| 693 | * |
||
| 694 | * @param string $msg |
||
| 695 | * @return string |
||
| 696 | */ |
||
| 697 | public function getHelpBox( $msg /*, ... */ ) { |
||
| 711 | |||
| 712 | /** |
||
| 713 | * Output a help box. |
||
| 714 | * @param string $msg Key for wfMessage() |
||
| 715 | */ |
||
| 716 | public function showHelpBox( $msg /*, ... */ ) { |
||
| 721 | |||
| 722 | /** |
||
| 723 | * Show a short informational message. |
||
| 724 | * Output looks like a list. |
||
| 725 | * |
||
| 726 | * @param string $msg |
||
| 727 | */ |
||
| 728 | public function showMessage( $msg /*, ... */ ) { |
||
| 736 | |||
| 737 | /** |
||
| 738 | * @param Status $status |
||
| 739 | */ |
||
| 740 | public function showStatusMessage( Status $status ) { |
||
| 746 | |||
| 747 | /** |
||
| 748 | * Label a control by wrapping a config-input div around it and putting a |
||
| 749 | * label before it. |
||
| 750 | * |
||
| 751 | * @param string $msg |
||
| 752 | * @param string $forId |
||
| 753 | * @param string $contents |
||
| 754 | * @param string $helpData |
||
| 755 | * @return string |
||
| 756 | */ |
||
| 757 | public function label( $msg, $forId, $contents, $helpData = "" ) { |
||
| 783 | |||
| 784 | /** |
||
| 785 | * Get a labelled text box to configure a variable. |
||
| 786 | * |
||
| 787 | * @param mixed[] $params |
||
| 788 | * Parameters are: |
||
| 789 | * var: The variable to be configured (required) |
||
| 790 | * label: The message name for the label (required) |
||
| 791 | * attribs: Additional attributes for the input element (optional) |
||
| 792 | * controlName: The name for the input element (optional) |
||
| 793 | * value: The current value of the variable (optional) |
||
| 794 | * help: The html for the help text (optional) |
||
| 795 | * |
||
| 796 | * @return string |
||
| 797 | */ |
||
| 798 | View Code Duplication | public function getTextBox( $params ) { |
|
| 830 | |||
| 831 | /** |
||
| 832 | * Get a labelled textarea to configure a variable |
||
| 833 | * |
||
| 834 | * @param mixed[] $params |
||
| 835 | * Parameters are: |
||
| 836 | * var: The variable to be configured (required) |
||
| 837 | * label: The message name for the label (required) |
||
| 838 | * attribs: Additional attributes for the input element (optional) |
||
| 839 | * controlName: The name for the input element (optional) |
||
| 840 | * value: The current value of the variable (optional) |
||
| 841 | * help: The html for the help text (optional) |
||
| 842 | * |
||
| 843 | * @return string |
||
| 844 | */ |
||
| 845 | View Code Duplication | public function getTextArea( $params ) { |
|
| 878 | |||
| 879 | /** |
||
| 880 | * Get a labelled password box to configure a variable. |
||
| 881 | * |
||
| 882 | * Implements password hiding |
||
| 883 | * @param mixed[] $params |
||
| 884 | * Parameters are: |
||
| 885 | * var: The variable to be configured (required) |
||
| 886 | * label: The message name for the label (required) |
||
| 887 | * attribs: Additional attributes for the input element (optional) |
||
| 888 | * controlName: The name for the input element (optional) |
||
| 889 | * value: The current value of the variable (optional) |
||
| 890 | * help: The html for the help text (optional) |
||
| 891 | * |
||
| 892 | * @return string |
||
| 893 | */ |
||
| 894 | public function getPasswordBox( $params ) { |
||
| 908 | |||
| 909 | /** |
||
| 910 | * Get a labelled checkbox to configure a boolean variable. |
||
| 911 | * |
||
| 912 | * @param mixed[] $params |
||
| 913 | * Parameters are: |
||
| 914 | * var: The variable to be configured (required) |
||
| 915 | * label: The message name for the label (required) |
||
| 916 | * attribs: Additional attributes for the input element (optional) |
||
| 917 | * controlName: The name for the input element (optional) |
||
| 918 | * value: The current value of the variable (optional) |
||
| 919 | * help: The html for the help text (optional) |
||
| 920 | * |
||
| 921 | * @return string |
||
| 922 | */ |
||
| 923 | public function getCheckBox( $params ) { |
||
| 959 | |||
| 960 | /** |
||
| 961 | * Get a set of labelled radio buttons. |
||
| 962 | * |
||
| 963 | * @param mixed[] $params |
||
| 964 | * Parameters are: |
||
| 965 | * var: The variable to be configured (required) |
||
| 966 | * label: The message name for the label (required) |
||
| 967 | * itemLabelPrefix: The message name prefix for the item labels (required) |
||
| 968 | * itemLabels: List of message names to use for the item labels instead |
||
| 969 | * of itemLabelPrefix, keyed by values |
||
| 970 | * values: List of allowed values (required) |
||
| 971 | * itemAttribs: Array of attribute arrays, outer key is the value name (optional) |
||
| 972 | * commonAttribs: Attribute array applied to all items |
||
| 973 | * controlName: The name for the input element (optional) |
||
| 974 | * value: The current value of the variable (optional) |
||
| 975 | * help: The html for the help text (optional) |
||
| 976 | * |
||
| 977 | * @return string |
||
| 978 | */ |
||
| 979 | public function getRadioSet( $params ) { |
||
| 1004 | |||
| 1005 | /** |
||
| 1006 | * Get a set of labelled radio buttons. You probably want to use getRadioSet(), not this. |
||
| 1007 | * |
||
| 1008 | * @see getRadioSet |
||
| 1009 | * |
||
| 1010 | * @return array |
||
| 1011 | */ |
||
| 1012 | public function getRadioElements( $params ) { |
||
| 1051 | |||
| 1052 | /** |
||
| 1053 | * Output an error or warning box using a Status object. |
||
| 1054 | * |
||
| 1055 | * @param Status $status |
||
| 1056 | */ |
||
| 1057 | public function showStatusBox( $status ) { |
||
| 1070 | |||
| 1071 | /** |
||
| 1072 | * Convenience function to set variables based on form data. |
||
| 1073 | * Assumes that variables containing "password" in the name are (potentially |
||
| 1074 | * fake) passwords. |
||
| 1075 | * |
||
| 1076 | * @param string[] $varNames |
||
| 1077 | * @param string $prefix The prefix added to variables to obtain form names |
||
| 1078 | * |
||
| 1079 | * @return string[] |
||
| 1080 | */ |
||
| 1081 | public function setVarsFromRequest( $varNames, $prefix = 'config_' ) { |
||
| 1106 | |||
| 1107 | /** |
||
| 1108 | * Helper for Installer::docLink() |
||
| 1109 | * |
||
| 1110 | * @param string $page |
||
| 1111 | * |
||
| 1112 | * @return string |
||
| 1113 | */ |
||
| 1114 | protected function getDocUrl( $page ) { |
||
| 1123 | |||
| 1124 | /** |
||
| 1125 | * Extension tag hook for a documentation link. |
||
| 1126 | * |
||
| 1127 | * @param string $linkText |
||
| 1128 | * @param string[] $attribs |
||
| 1129 | * @param Parser $parser Unused |
||
| 1130 | * |
||
| 1131 | * @return string |
||
| 1132 | */ |
||
| 1133 | public function docLink( $linkText, $attribs, $parser ) { |
||
| 1140 | |||
| 1141 | /** |
||
| 1142 | * Helper for "Download LocalSettings" link on WebInstall_Complete |
||
| 1143 | * |
||
| 1144 | * @param string $text Unused |
||
| 1145 | * @param string[] $attribs Unused |
||
| 1146 | * @param Parser $parser Unused |
||
| 1147 | * |
||
| 1148 | * @return string Html for download link |
||
| 1149 | */ |
||
| 1150 | public function downloadLinkHook( $text, $attribs, $parser ) { |
||
| 1158 | |||
| 1159 | /** |
||
| 1160 | * If the software package wants the LocalSettings.php file |
||
| 1161 | * to be placed in a specific location, override this function |
||
| 1162 | * (see mw-config/overrides/README) to return the path of |
||
| 1163 | * where the file should be saved, or false for a generic |
||
| 1164 | * "in the base of your install" |
||
| 1165 | * |
||
| 1166 | * @since 1.27 |
||
| 1167 | * @return string|bool |
||
| 1168 | */ |
||
| 1169 | public function getLocalSettingsLocation() { |
||
| 1170 | return false; |
||
| 1171 | } |
||
| 1172 | |||
| 1173 | /** |
||
| 1174 | * @return bool |
||
| 1175 | */ |
||
| 1176 | public function envCheckPath() { |
||
| 1193 | |||
| 1194 | public function envPrepPath() { |
||
| 1219 | |||
| 1220 | /** |
||
| 1221 | * @return string |
||
| 1222 | */ |
||
| 1223 | protected function envGetDefaultServer() { |
||
| 1226 | |||
| 1227 | /** |
||
| 1228 | * Output stylesheet for web installer pages |
||
| 1229 | */ |
||
| 1230 | public function outputCss() { |
||
| 1234 | |||
| 1235 | /** |
||
| 1236 | * @return string[] |
||
| 1237 | */ |
||
| 1238 | public function getPhpErrors() { |
||
| 1241 | |||
| 1242 | } |
||
| 1243 |
In PHP, under loose comparison (like
==, or!=, orswitchconditions), values of different types might be equal.For
stringvalues, the empty string''is a special case, in particular the following results might be unexpected: