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 DatabaseInstaller 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 DatabaseInstaller, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 30 | abstract class DatabaseInstaller { |
||
| 31 | |||
| 32 | /** |
||
| 33 | * The Installer object. |
||
| 34 | * |
||
| 35 | * @todo Naming this parent is confusing, 'installer' would be clearer. |
||
| 36 | * |
||
| 37 | * @var WebInstaller |
||
| 38 | */ |
||
| 39 | public $parent; |
||
| 40 | |||
| 41 | /** |
||
| 42 | * The database connection. |
||
| 43 | * |
||
| 44 | * @var Database |
||
| 45 | */ |
||
| 46 | public $db = null; |
||
| 47 | |||
| 48 | /** |
||
| 49 | * Internal variables for installation. |
||
| 50 | * |
||
| 51 | * @var array |
||
| 52 | */ |
||
| 53 | protected $internalDefaults = []; |
||
| 54 | |||
| 55 | /** |
||
| 56 | * Array of MW configuration globals this class uses. |
||
| 57 | * |
||
| 58 | * @var array |
||
| 59 | */ |
||
| 60 | protected $globalNames = []; |
||
| 61 | |||
| 62 | /** |
||
| 63 | * Return the internal name, e.g. 'mysql', or 'sqlite'. |
||
| 64 | */ |
||
| 65 | abstract public function getName(); |
||
| 66 | |||
| 67 | /** |
||
| 68 | * @return bool Returns true if the client library is compiled in. |
||
| 69 | */ |
||
| 70 | abstract public function isCompiled(); |
||
| 71 | |||
| 72 | /** |
||
| 73 | * Checks for installation prerequisites other than those checked by isCompiled() |
||
| 74 | * @since 1.19 |
||
| 75 | * @return Status |
||
| 76 | */ |
||
| 77 | public function checkPrerequisites() { |
||
| 80 | |||
| 81 | /** |
||
| 82 | * Get HTML for a web form that configures this database. Configuration |
||
| 83 | * at this time should be the minimum needed to connect and test |
||
| 84 | * whether install or upgrade is required. |
||
| 85 | * |
||
| 86 | * If this is called, $this->parent can be assumed to be a WebInstaller. |
||
| 87 | */ |
||
| 88 | abstract public function getConnectForm(); |
||
| 89 | |||
| 90 | /** |
||
| 91 | * Set variables based on the request array, assuming it was submitted |
||
| 92 | * via the form returned by getConnectForm(). Validate the connection |
||
| 93 | * settings by attempting to connect with them. |
||
| 94 | * |
||
| 95 | * If this is called, $this->parent can be assumed to be a WebInstaller. |
||
| 96 | * |
||
| 97 | * @return Status |
||
| 98 | */ |
||
| 99 | abstract public function submitConnectForm(); |
||
| 100 | |||
| 101 | /** |
||
| 102 | * Get HTML for a web form that retrieves settings used for installation. |
||
| 103 | * $this->parent can be assumed to be a WebInstaller. |
||
| 104 | * If the DB type has no settings beyond those already configured with |
||
| 105 | * getConnectForm(), this should return false. |
||
| 106 | * @return bool |
||
| 107 | */ |
||
| 108 | public function getSettingsForm() { |
||
| 111 | |||
| 112 | /** |
||
| 113 | * Set variables based on the request array, assuming it was submitted via |
||
| 114 | * the form return by getSettingsForm(). |
||
| 115 | * |
||
| 116 | * @return Status |
||
| 117 | */ |
||
| 118 | public function submitSettingsForm() { |
||
| 121 | |||
| 122 | /** |
||
| 123 | * Open a connection to the database using the administrative user/password |
||
| 124 | * currently defined in the session, without any caching. Returns a status |
||
| 125 | * object. On success, the status object will contain a Database object in |
||
| 126 | * its value member. |
||
| 127 | * |
||
| 128 | * @return Status |
||
| 129 | */ |
||
| 130 | abstract public function openConnection(); |
||
| 131 | |||
| 132 | /** |
||
| 133 | * Create the database and return a Status object indicating success or |
||
| 134 | * failure. |
||
| 135 | * |
||
| 136 | * @return Status |
||
| 137 | */ |
||
| 138 | abstract public function setupDatabase(); |
||
| 139 | |||
| 140 | /** |
||
| 141 | * Connect to the database using the administrative user/password currently |
||
| 142 | * defined in the session. Returns a status object. On success, the status |
||
| 143 | * object will contain a Database object in its value member. |
||
| 144 | * |
||
| 145 | * This will return a cached connection if one is available. |
||
| 146 | * |
||
| 147 | * @return Status |
||
| 148 | */ |
||
| 149 | public function getConnection() { |
||
| 164 | |||
| 165 | /** |
||
| 166 | * Apply a SQL source file to the database as part of running an installation step. |
||
| 167 | * |
||
| 168 | * @param string $sourceFileMethod |
||
| 169 | * @param string $stepName |
||
| 170 | * @param bool $archiveTableMustNotExist |
||
| 171 | * @return Status |
||
| 172 | */ |
||
| 173 | private function stepApplySourceFile( |
||
| 211 | |||
| 212 | /** |
||
| 213 | * Create database tables from scratch. |
||
| 214 | * |
||
| 215 | * @return Status |
||
| 216 | */ |
||
| 217 | public function createTables() { |
||
| 220 | |||
| 221 | /** |
||
| 222 | * Insert update keys into table to prevent running unneded updates. |
||
| 223 | * |
||
| 224 | * @return Status |
||
| 225 | */ |
||
| 226 | public function insertUpdateKeys() { |
||
| 229 | |||
| 230 | /** |
||
| 231 | * Return a path to the DBMS-specific SQL file if it exists, |
||
| 232 | * otherwise default SQL file |
||
| 233 | * |
||
| 234 | * @param IDatabase $db |
||
| 235 | * @param string $filename |
||
| 236 | * @return string |
||
| 237 | */ |
||
| 238 | View Code Duplication | private function getSqlFilePath( $db, $filename ) { |
|
| 248 | |||
| 249 | /** |
||
| 250 | * Return a path to the DBMS-specific schema file, |
||
| 251 | * otherwise default to tables.sql |
||
| 252 | * |
||
| 253 | * @param IDatabase $db |
||
| 254 | * @return string |
||
| 255 | */ |
||
| 256 | public function getSchemaPath( $db ) { |
||
| 259 | |||
| 260 | /** |
||
| 261 | * Return a path to the DBMS-specific update key file, |
||
| 262 | * otherwise default to update-keys.sql |
||
| 263 | * |
||
| 264 | * @param IDatabase $db |
||
| 265 | * @return string |
||
| 266 | */ |
||
| 267 | public function getUpdateKeysPath( $db ) { |
||
| 270 | |||
| 271 | /** |
||
| 272 | * Create the tables for each extension the user enabled |
||
| 273 | * @return Status |
||
| 274 | */ |
||
| 275 | public function createExtensionTables() { |
||
| 286 | |||
| 287 | /** |
||
| 288 | * Get the DBMS-specific options for LocalSettings.php generation. |
||
| 289 | * |
||
| 290 | * @return string |
||
| 291 | */ |
||
| 292 | abstract public function getLocalSettings(); |
||
| 293 | |||
| 294 | /** |
||
| 295 | * Override this to provide DBMS-specific schema variables, to be |
||
| 296 | * substituted into tables.sql and other schema files. |
||
| 297 | * @return array |
||
| 298 | */ |
||
| 299 | public function getSchemaVars() { |
||
| 302 | |||
| 303 | /** |
||
| 304 | * Set appropriate schema variables in the current database connection. |
||
| 305 | * |
||
| 306 | * This should be called after any request data has been imported, but before |
||
| 307 | * any write operations to the database. |
||
| 308 | */ |
||
| 309 | public function setupSchemaVars() { |
||
| 320 | |||
| 321 | /** |
||
| 322 | * Set up LBFactory so that wfGetDB() etc. works. |
||
| 323 | * We set up a special LBFactory instance which returns the current |
||
| 324 | * installer connection. |
||
| 325 | */ |
||
| 326 | public function enableLB() { |
||
| 340 | |||
| 341 | /** |
||
| 342 | * Perform database upgrades |
||
| 343 | * |
||
| 344 | * @return bool |
||
| 345 | */ |
||
| 346 | public function doUpgrade() { |
||
| 369 | |||
| 370 | /** |
||
| 371 | * Allow DB installers a chance to make last-minute changes before installation |
||
| 372 | * occurs. This happens before setupDatabase() or createTables() is called, but |
||
| 373 | * long after the constructor. Helpful for things like modifying setup steps :) |
||
| 374 | */ |
||
| 375 | public function preInstall() { |
||
| 377 | |||
| 378 | /** |
||
| 379 | * Allow DB installers a chance to make checks before upgrade. |
||
| 380 | */ |
||
| 381 | public function preUpgrade() { |
||
| 383 | |||
| 384 | /** |
||
| 385 | * Get an array of MW configuration globals that will be configured by this class. |
||
| 386 | * @return array |
||
| 387 | */ |
||
| 388 | public function getGlobalNames() { |
||
| 391 | |||
| 392 | /** |
||
| 393 | * Construct and initialise parent. |
||
| 394 | * This is typically only called from Installer::getDBInstaller() |
||
| 395 | * @param WebInstaller $parent |
||
| 396 | */ |
||
| 397 | public function __construct( $parent ) { |
||
| 400 | |||
| 401 | /** |
||
| 402 | * Convenience function. |
||
| 403 | * Check if a named extension is present. |
||
| 404 | * |
||
| 405 | * @param string $name |
||
| 406 | * @return bool |
||
| 407 | */ |
||
| 408 | protected static function checkExtension( $name ) { |
||
| 411 | |||
| 412 | /** |
||
| 413 | * Get the internationalised name for this DBMS. |
||
| 414 | * @return string |
||
| 415 | */ |
||
| 416 | public function getReadableName() { |
||
| 421 | |||
| 422 | /** |
||
| 423 | * Get a name=>value map of MW configuration globals for the default values. |
||
| 424 | * @return array |
||
| 425 | */ |
||
| 426 | public function getGlobalDefaults() { |
||
| 435 | |||
| 436 | /** |
||
| 437 | * Get a name=>value map of internal variables used during installation. |
||
| 438 | * @return array |
||
| 439 | */ |
||
| 440 | public function getInternalDefaults() { |
||
| 443 | |||
| 444 | /** |
||
| 445 | * Get a variable, taking local defaults into account. |
||
| 446 | * @param string $var |
||
| 447 | * @param mixed|null $default |
||
| 448 | * @return mixed |
||
| 449 | */ |
||
| 450 | public function getVar( $var, $default = null ) { |
||
| 461 | |||
| 462 | /** |
||
| 463 | * Convenience alias for $this->parent->setVar() |
||
| 464 | * @param string $name |
||
| 465 | * @param mixed $value |
||
| 466 | */ |
||
| 467 | public function setVar( $name, $value ) { |
||
| 470 | |||
| 471 | /** |
||
| 472 | * Get a labelled text box to configure a local variable. |
||
| 473 | * |
||
| 474 | * @param string $var |
||
| 475 | * @param string $label |
||
| 476 | * @param array $attribs |
||
| 477 | * @param string $helpData |
||
| 478 | * @return string |
||
| 479 | */ |
||
| 480 | View Code Duplication | public function getTextBox( $var, $label, $attribs = [], $helpData = "" ) { |
|
| 496 | |||
| 497 | /** |
||
| 498 | * Get a labelled password box to configure a local variable. |
||
| 499 | * Implements password hiding. |
||
| 500 | * |
||
| 501 | * @param string $var |
||
| 502 | * @param string $label |
||
| 503 | * @param array $attribs |
||
| 504 | * @param string $helpData |
||
| 505 | * @return string |
||
| 506 | */ |
||
| 507 | View Code Duplication | public function getPasswordBox( $var, $label, $attribs = [], $helpData = "" ) { |
|
| 523 | |||
| 524 | /** |
||
| 525 | * Get a labelled checkbox to configure a local boolean variable. |
||
| 526 | * |
||
| 527 | * @param string $var |
||
| 528 | * @param string $label |
||
| 529 | * @param array $attribs Optional. |
||
| 530 | * @param string $helpData Optional. |
||
| 531 | * @return string |
||
| 532 | */ |
||
| 533 | View Code Duplication | public function getCheckBox( $var, $label, $attribs = [], $helpData = "" ) { |
|
| 546 | |||
| 547 | /** |
||
| 548 | * Get a set of labelled radio buttons. |
||
| 549 | * |
||
| 550 | * @param array $params Parameters are: |
||
| 551 | * var: The variable to be configured (required) |
||
| 552 | * label: The message name for the label (required) |
||
| 553 | * itemLabelPrefix: The message name prefix for the item labels (required) |
||
| 554 | * values: List of allowed values (required) |
||
| 555 | * itemAttribs Array of attribute arrays, outer key is the value name (optional) |
||
| 556 | * |
||
| 557 | * @return string |
||
| 558 | */ |
||
| 559 | public function getRadioSet( $params ) { |
||
| 565 | |||
| 566 | /** |
||
| 567 | * Convenience function to set variables based on form data. |
||
| 568 | * Assumes that variables containing "password" in the name are (potentially |
||
| 569 | * fake) passwords. |
||
| 570 | * @param array $varNames |
||
| 571 | * @return array |
||
| 572 | */ |
||
| 573 | public function setVarsFromRequest( $varNames ) { |
||
| 576 | |||
| 577 | /** |
||
| 578 | * Determine whether an existing installation of MediaWiki is present in |
||
| 579 | * the configured administrative connection. Returns true if there is |
||
| 580 | * such a wiki, false if the database doesn't exist. |
||
| 581 | * |
||
| 582 | * Traditionally, this is done by testing for the existence of either |
||
| 583 | * the revision table or the cur table. |
||
| 584 | * |
||
| 585 | * @return bool |
||
| 586 | */ |
||
| 587 | public function needsUpgrade() { |
||
| 600 | |||
| 601 | /** |
||
| 602 | * Get a standard install-user fieldset. |
||
| 603 | * |
||
| 604 | * @return string |
||
| 605 | */ |
||
| 606 | public function getInstallUserBox() { |
||
| 623 | |||
| 624 | /** |
||
| 625 | * Submit a standard install user fieldset. |
||
| 626 | * @return Status |
||
| 627 | */ |
||
| 628 | public function submitInstallUserBox() { |
||
| 633 | |||
| 634 | /** |
||
| 635 | * Get a standard web-user fieldset |
||
| 636 | * @param string|bool $noCreateMsg Message to display instead of the creation checkbox. |
||
| 637 | * Set this to false to show a creation checkbox (default). |
||
| 638 | * |
||
| 639 | * @return string |
||
| 640 | */ |
||
| 641 | public function getWebUserBox( $noCreateMsg = false ) { |
||
| 662 | |||
| 663 | /** |
||
| 664 | * Submit the form from getWebUserBox(). |
||
| 665 | * |
||
| 666 | * @return Status |
||
| 667 | */ |
||
| 668 | public function submitWebUserBox() { |
||
| 684 | |||
| 685 | /** |
||
| 686 | * Common function for databases that don't understand the MySQLish syntax of interwiki.sql. |
||
| 687 | * |
||
| 688 | * @return Status |
||
| 689 | */ |
||
| 690 | public function populateInterwikiTable() { |
||
| 726 | |||
| 727 | public function outputHandler( $string ) { |
||
| 730 | } |
||
| 731 |
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.