MediaWiki  master
DatabaseUpdater.php
Go to the documentation of this file.
1 <?php
26 
27 require_once __DIR__ . '/../../maintenance/Maintenance.php';
28 
36 abstract class DatabaseUpdater {
38 
44  protected $updates = [];
45 
51  protected $updatesSkipped = [];
52 
57  protected $extensionUpdates = [];
58 
64  protected $db;
65 
69  protected $maintenance;
70 
71  protected $shared = false;
72 
91  ];
92 
98  protected $fileHandle = null;
99 
105  protected $skipSchema = false;
106 
110  protected $holdContentHandlerUseDB = true;
111 
117  protected function __construct(
119  $shared,
121  ) {
122  $this->db = $db;
123  $this->db->setFlag( DBO_DDLMODE ); // For Oracle's handling of schema files
124  $this->shared = $shared;
125  if ( $maintenance ) {
126  $this->maintenance = $maintenance;
127  $this->fileHandle = $maintenance->fileHandle;
128  } else {
129  $this->maintenance = new FakeMaintenance;
130  }
131  $this->maintenance->setDB( $db );
132  $this->initOldGlobals();
133  $this->loadExtensions();
134  Hooks::run( 'LoadExtensionSchemaUpdates', [ $this ] );
135  }
136 
141  private function initOldGlobals() {
142  global $wgExtNewTables, $wgExtNewFields, $wgExtPGNewFields,
143  $wgExtPGAlteredFields, $wgExtNewIndexes, $wgExtModifiedFields;
144 
145  # For extensions only, should be populated via hooks
146  # $wgDBtype should be checked to specify the proper file
147  $wgExtNewTables = []; // table, dir
148  $wgExtNewFields = []; // table, column, dir
149  $wgExtPGNewFields = []; // table, column, column attributes; for PostgreSQL
150  $wgExtPGAlteredFields = []; // table, column, new type, conversion method; for PostgreSQL
151  $wgExtNewIndexes = []; // table, index, dir
152  $wgExtModifiedFields = []; // table, index, dir
153  }
154 
159  private function loadExtensions() {
160  if ( !defined( 'MEDIAWIKI_INSTALL' ) || defined( 'MW_EXTENSIONS_LOADED' ) ) {
161  return; // already loaded
162  }
164 
165  $registry = ExtensionRegistry::getInstance();
166  $queue = $registry->getQueue();
167  // Don't accidentally load extensions in the future
168  $registry->clearQueue();
169 
170  // This will automatically add "AutoloadClasses" to $wgAutoloadClasses
171  $data = $registry->readFromQueue( $queue );
172  $hooks = $data['globals']['wgHooks']['LoadExtensionSchemaUpdates'] ?? [];
173  if ( $vars && isset( $vars['wgHooks']['LoadExtensionSchemaUpdates'] ) ) {
174  $hooks = array_merge_recursive( $hooks, $vars['wgHooks']['LoadExtensionSchemaUpdates'] );
175  }
177  $wgHooks['LoadExtensionSchemaUpdates'] = $hooks;
178  if ( $vars && isset( $vars['wgAutoloadClasses'] ) ) {
179  $wgAutoloadClasses += $vars['wgAutoloadClasses'];
180  }
181  }
182 
191  public static function newForDB(
193  $shared = false,
195  ) {
196  $type = $db->getType();
197  if ( in_array( $type, Installer::getDBTypes() ) ) {
198  $class = ucfirst( $type ) . 'Updater';
199 
200  return new $class( $db, $shared, $maintenance );
201  } else {
202  throw new MWException( __METHOD__ . ' called for unsupported $wgDBtype' );
203  }
204  }
205 
211  public function getDB() {
212  return $this->db;
213  }
214 
221  public function output( $str ) {
222  if ( $this->maintenance->isQuiet() ) {
223  return;
224  }
225  global $wgCommandLineMode;
226  if ( !$wgCommandLineMode ) {
227  $str = htmlspecialchars( $str );
228  }
229  echo $str;
230  flush();
231  }
232 
245  public function addExtensionUpdate( array $update ) {
246  $this->extensionUpdates[] = $update;
247  }
248 
258  public function addExtensionTable( $tableName, $sqlPath ) {
259  $this->extensionUpdates[] = [ 'addTable', $tableName, $sqlPath, true ];
260  }
261 
269  public function addExtensionIndex( $tableName, $indexName, $sqlPath ) {
270  $this->extensionUpdates[] = [ 'addIndex', $tableName, $indexName, $sqlPath, true ];
271  }
272 
281  public function addExtensionField( $tableName, $columnName, $sqlPath ) {
282  $this->extensionUpdates[] = [ 'addField', $tableName, $columnName, $sqlPath, true ];
283  }
284 
293  public function dropExtensionField( $tableName, $columnName, $sqlPath ) {
294  $this->extensionUpdates[] = [ 'dropField', $tableName, $columnName, $sqlPath, true ];
295  }
296 
306  public function dropExtensionIndex( $tableName, $indexName, $sqlPath ) {
307  $this->extensionUpdates[] = [ 'dropIndex', $tableName, $indexName, $sqlPath, true ];
308  }
309 
317  public function dropExtensionTable( $tableName, $sqlPath ) {
318  $this->extensionUpdates[] = [ 'dropTable', $tableName, $sqlPath, true ];
319  }
320 
333  public function renameExtensionIndex( $tableName, $oldIndexName, $newIndexName,
334  $sqlPath, $skipBothIndexExistWarning = false
335  ) {
336  $this->extensionUpdates[] = [
337  'renameIndex',
338  $tableName,
339  $oldIndexName,
340  $newIndexName,
341  $skipBothIndexExistWarning,
342  $sqlPath,
343  true
344  ];
345  }
346 
354  public function modifyExtensionField( $tableName, $fieldName, $sqlPath ) {
355  $this->extensionUpdates[] = [ 'modifyField', $tableName, $fieldName, $sqlPath, true ];
356  }
357 
364  public function modifyExtensionTable( $tableName, $sqlPath ) {
365  $this->extensionUpdates[] = [ 'modifyTable', $tableName, $sqlPath, true ];
366  }
367 
375  public function tableExists( $tableName ) {
376  return ( $this->db->tableExists( $tableName, __METHOD__ ) );
377  }
378 
388  public function addPostDatabaseUpdateMaintenance( $class ) {
389  $this->postDatabaseUpdateMaintenance[] = $class;
390  }
391 
397  protected function getExtensionUpdates() {
399  }
400 
408  }
409 
416  private function writeSchemaUpdateFile( array $schemaUpdate = [] ) {
418  $this->updatesSkipped = [];
419 
420  foreach ( $updates as $funcList ) {
421  list( $func, $args, $origParams ) = $funcList;
422  $func( ...$args );
423  flush();
424  $this->updatesSkipped[] = $origParams;
425  }
426  }
427 
438  public function getSchemaVars() {
439  return []; // DB-type specific
440  }
441 
447  public function doUpdates( array $what = [ 'core', 'extensions', 'stats' ] ) {
448  $this->db->setSchemaVars( $this->getSchemaVars() );
449 
450  $what = array_flip( $what );
451  $this->skipSchema = isset( $what['noschema'] ) || $this->fileHandle !== null;
452  if ( isset( $what['core'] ) ) {
453  $this->runUpdates( $this->getCoreUpdateList(), false );
454  }
455  if ( isset( $what['extensions'] ) ) {
456  $this->runUpdates( $this->getOldGlobalUpdates(), false );
457  $this->runUpdates( $this->getExtensionUpdates(), true );
458  }
459 
460  if ( isset( $what['stats'] ) ) {
461  $this->checkStats();
462  }
463 
464  if ( $this->fileHandle ) {
465  $this->skipSchema = false;
466  $this->writeSchemaUpdateFile();
467  }
468  }
469 
476  private function runUpdates( array $updates, $passSelf ) {
477  $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
478 
479  $updatesDone = [];
480  $updatesSkipped = [];
481  foreach ( $updates as $params ) {
482  $origParams = $params;
483  $func = array_shift( $params );
484  if ( !is_array( $func ) && method_exists( $this, $func ) ) {
485  $func = [ $this, $func ];
486  } elseif ( $passSelf ) {
487  array_unshift( $params, $this );
488  }
489  $ret = $func( ...$params );
490  flush();
491  if ( $ret !== false ) {
492  $updatesDone[] = $origParams;
493  $lbFactory->waitForReplication( [ 'timeout' => self::REPLICATION_WAIT_TIMEOUT ] );
494  } else {
495  $updatesSkipped[] = [ $func, $params, $origParams ];
496  }
497  }
498  $this->updatesSkipped = array_merge( $this->updatesSkipped, $updatesSkipped );
499  $this->updates = array_merge( $this->updates, $updatesDone );
500  }
501 
509  public function updateRowExists( $key ) {
510  $row = $this->db->selectRow(
511  'updatelog',
512  # T67813
513  '1 AS X',
514  [ 'ul_key' => $key ],
515  __METHOD__
516  );
517 
518  return (bool)$row;
519  }
520 
528  public function insertUpdateRow( $key, $val = null ) {
529  $this->db->clearFlag( DBO_DDLMODE );
530  $values = [ 'ul_key' => $key ];
531  if ( $val && $this->canUseNewUpdatelog() ) {
532  $values['ul_value'] = $val;
533  }
534  $this->db->insert( 'updatelog', $values, __METHOD__, 'IGNORE' );
535  $this->db->setFlag( DBO_DDLMODE );
536  }
537 
546  protected function canUseNewUpdatelog() {
547  return $this->db->tableExists( 'updatelog', __METHOD__ ) &&
548  $this->db->fieldExists( 'updatelog', 'ul_value', __METHOD__ );
549  }
550 
559  protected function doTable( $name ) {
561 
562  // Don't bother to check $wgSharedTables if there isn't a shared database
563  // or the user actually also wants to do updates on the shared database.
564  if ( $wgSharedDB === null || $this->shared ) {
565  return true;
566  }
567 
568  if ( in_array( $name, $wgSharedTables ) ) {
569  $this->output( "...skipping update to shared table $name.\n" );
570  return false;
571  } else {
572  return true;
573  }
574  }
575 
584  protected function getOldGlobalUpdates() {
585  global $wgExtNewFields, $wgExtNewTables, $wgExtModifiedFields,
586  $wgExtNewIndexes;
587 
588  $updates = [];
589 
590  foreach ( $wgExtNewTables as $tableRecord ) {
591  $updates[] = [
592  'addTable', $tableRecord[0], $tableRecord[1], true
593  ];
594  }
595 
596  foreach ( $wgExtNewFields as $fieldRecord ) {
597  $updates[] = [
598  'addField', $fieldRecord[0], $fieldRecord[1],
599  $fieldRecord[2], true
600  ];
601  }
602 
603  foreach ( $wgExtNewIndexes as $fieldRecord ) {
604  $updates[] = [
605  'addIndex', $fieldRecord[0], $fieldRecord[1],
606  $fieldRecord[2], true
607  ];
608  }
609 
610  foreach ( $wgExtModifiedFields as $fieldRecord ) {
611  $updates[] = [
612  'modifyField', $fieldRecord[0], $fieldRecord[1],
613  $fieldRecord[2], true
614  ];
615  }
616 
617  return $updates;
618  }
619 
628  abstract protected function getCoreUpdateList();
629 
635  public function copyFile( $filename ) {
636  $this->db->sourceFile(
637  $filename,
638  null,
639  null,
640  __METHOD__,
641  [ $this, 'appendLine' ]
642  );
643  }
644 
655  public function appendLine( $line ) {
656  $line = rtrim( $line ) . ";\n";
657  if ( fwrite( $this->fileHandle, $line ) === false ) {
658  throw new MWException( "trouble writing file" );
659  }
660 
661  return false;
662  }
663 
672  protected function applyPatch( $path, $isFullPath = false, $msg = null ) {
673  if ( $msg === null ) {
674  $msg = "Applying $path patch";
675  }
676  if ( $this->skipSchema ) {
677  $this->output( "...skipping schema change ($msg).\n" );
678 
679  return false;
680  }
681 
682  $this->output( "$msg ..." );
683 
684  if ( !$isFullPath ) {
685  $path = $this->patchPath( $this->db, $path );
686  }
687  if ( $this->fileHandle !== null ) {
688  $this->copyFile( $path );
689  } else {
690  $this->db->sourceFile( $path );
691  }
692  $this->output( "done.\n" );
693 
694  return true;
695  }
696 
706  public function patchPath( IDatabase $db, $patch ) {
707  global $IP;
708 
709  $dbType = $db->getType();
710  if ( file_exists( "$IP/maintenance/$dbType/archives/$patch" ) ) {
711  return "$IP/maintenance/$dbType/archives/$patch";
712  } else {
713  return "$IP/maintenance/archives/$patch";
714  }
715  }
716 
725  protected function addTable( $name, $patch, $fullpath = false ) {
726  if ( !$this->doTable( $name ) ) {
727  return true;
728  }
729 
730  if ( $this->db->tableExists( $name, __METHOD__ ) ) {
731  $this->output( "...$name table already exists.\n" );
732  } else {
733  return $this->applyPatch( $patch, $fullpath, "Creating $name table" );
734  }
735 
736  return true;
737  }
738 
748  protected function addField( $table, $field, $patch, $fullpath = false ) {
749  if ( !$this->doTable( $table ) ) {
750  return true;
751  }
752 
753  if ( !$this->db->tableExists( $table, __METHOD__ ) ) {
754  $this->output( "...$table table does not exist, skipping new field patch.\n" );
755  } elseif ( $this->db->fieldExists( $table, $field, __METHOD__ ) ) {
756  $this->output( "...have $field field in $table table.\n" );
757  } else {
758  return $this->applyPatch( $patch, $fullpath, "Adding $field field to table $table" );
759  }
760 
761  return true;
762  }
763 
773  protected function addIndex( $table, $index, $patch, $fullpath = false ) {
774  if ( !$this->doTable( $table ) ) {
775  return true;
776  }
777 
778  if ( !$this->db->tableExists( $table, __METHOD__ ) ) {
779  $this->output( "...skipping: '$table' table doesn't exist yet.\n" );
780  } elseif ( $this->db->indexExists( $table, $index, __METHOD__ ) ) {
781  $this->output( "...index $index already set on $table table.\n" );
782  } else {
783  return $this->applyPatch( $patch, $fullpath, "Adding index $index to table $table" );
784  }
785 
786  return true;
787  }
788 
799  protected function addIndexIfNoneExist( $table, $indexes, $patch, $fullpath = false ) {
800  if ( !$this->doTable( $table ) ) {
801  return true;
802  }
803 
804  if ( !$this->db->tableExists( $table, __METHOD__ ) ) {
805  $this->output( "...skipping: '$table' table doesn't exist yet.\n" );
806  return true;
807  }
808 
809  $newIndex = $indexes[0];
810  foreach ( $indexes as $index ) {
811  if ( $this->db->indexExists( $table, $index, __METHOD__ ) ) {
812  $this->output(
813  "...skipping index $newIndex because index $index already set on $table table.\n"
814  );
815  return true;
816  }
817  }
818 
819  return $this->applyPatch( $patch, $fullpath, "Adding index $index to table $table" );
820  }
821 
831  protected function dropField( $table, $field, $patch, $fullpath = false ) {
832  if ( !$this->doTable( $table ) ) {
833  return true;
834  }
835 
836  if ( $this->db->fieldExists( $table, $field, __METHOD__ ) ) {
837  return $this->applyPatch( $patch, $fullpath, "Table $table contains $field field. Dropping" );
838  } else {
839  $this->output( "...$table table does not contain $field field.\n" );
840  }
841 
842  return true;
843  }
844 
854  protected function dropIndex( $table, $index, $patch, $fullpath = false ) {
855  if ( !$this->doTable( $table ) ) {
856  return true;
857  }
858 
859  if ( $this->db->indexExists( $table, $index, __METHOD__ ) ) {
860  return $this->applyPatch( $patch, $fullpath, "Dropping $index index from table $table" );
861  } else {
862  $this->output( "...$index key doesn't exist.\n" );
863  }
864 
865  return true;
866  }
867 
880  protected function renameIndex( $table, $oldIndex, $newIndex,
881  $skipBothIndexExistWarning, $patch, $fullpath = false
882  ) {
883  if ( !$this->doTable( $table ) ) {
884  return true;
885  }
886 
887  // First requirement: the table must exist
888  if ( !$this->db->tableExists( $table, __METHOD__ ) ) {
889  $this->output( "...skipping: '$table' table doesn't exist yet.\n" );
890 
891  return true;
892  }
893 
894  // Second requirement: the new index must be missing
895  if ( $this->db->indexExists( $table, $newIndex, __METHOD__ ) ) {
896  $this->output( "...index $newIndex already set on $table table.\n" );
897  if ( !$skipBothIndexExistWarning &&
898  $this->db->indexExists( $table, $oldIndex, __METHOD__ )
899  ) {
900  $this->output( "...WARNING: $oldIndex still exists, despite it has " .
901  "been renamed into $newIndex (which also exists).\n" .
902  " $oldIndex should be manually removed if not needed anymore.\n" );
903  }
904 
905  return true;
906  }
907 
908  // Third requirement: the old index must exist
909  if ( !$this->db->indexExists( $table, $oldIndex, __METHOD__ ) ) {
910  $this->output( "...skipping: index $oldIndex doesn't exist.\n" );
911 
912  return true;
913  }
914 
915  // Requirements have been satisfied, patch can be applied
916  return $this->applyPatch(
917  $patch,
918  $fullpath,
919  "Renaming index $oldIndex into $newIndex to table $table"
920  );
921  }
922 
934  public function dropTable( $table, $patch = false, $fullpath = false ) {
935  if ( !$this->doTable( $table ) ) {
936  return true;
937  }
938 
939  if ( $this->db->tableExists( $table, __METHOD__ ) ) {
940  $msg = "Dropping table $table";
941 
942  if ( $patch === false ) {
943  $this->output( "$msg ..." );
944  $this->db->dropTable( $table, __METHOD__ );
945  $this->output( "done.\n" );
946  } else {
947  return $this->applyPatch( $patch, $fullpath, $msg );
948  }
949  } else {
950  $this->output( "...$table doesn't exist.\n" );
951  }
952 
953  return true;
954  }
955 
965  public function modifyField( $table, $field, $patch, $fullpath = false ) {
966  if ( !$this->doTable( $table ) ) {
967  return true;
968  }
969 
970  $updateKey = "$table-$field-$patch";
971  if ( !$this->db->tableExists( $table, __METHOD__ ) ) {
972  $this->output( "...$table table does not exist, skipping modify field patch.\n" );
973  } elseif ( !$this->db->fieldExists( $table, $field, __METHOD__ ) ) {
974  $this->output( "...$field field does not exist in $table table, " .
975  "skipping modify field patch.\n" );
976  } elseif ( $this->updateRowExists( $updateKey ) ) {
977  $this->output( "...$field in table $table already modified by patch $patch.\n" );
978  } else {
979  $apply = $this->applyPatch( $patch, $fullpath, "Modifying $field field of table $table" );
980  if ( $apply ) {
981  $this->insertUpdateRow( $updateKey );
982  }
983  return $apply;
984  }
985  return true;
986  }
987 
997  public function modifyTable( $table, $patch, $fullpath = false ) {
998  if ( !$this->doTable( $table ) ) {
999  return true;
1000  }
1001 
1002  $updateKey = "$table-$patch";
1003  if ( !$this->db->tableExists( $table, __METHOD__ ) ) {
1004  $this->output( "...$table table does not exist, skipping modify table patch.\n" );
1005  } elseif ( $this->updateRowExists( $updateKey ) ) {
1006  $this->output( "...table $table already modified by patch $patch.\n" );
1007  } else {
1008  $apply = $this->applyPatch( $patch, $fullpath, "Modifying table $table" );
1009  if ( $apply ) {
1010  $this->insertUpdateRow( $updateKey );
1011  }
1012  return $apply;
1013  }
1014  return true;
1015  }
1016 
1032  public function runMaintenance( $class, $script ) {
1033  $this->output( "Running $script...\n" );
1034  $task = $this->maintenance->runChild( $class );
1035  $ok = $task->execute();
1036  if ( !$ok ) {
1037  throw new RuntimeException( "Execution of $script did not complete successfully." );
1038  }
1039  $this->output( "done.\n" );
1040  }
1041 
1047  public function setFileAccess() {
1048  $repo = RepoGroup::singleton()->getLocalRepo();
1049  $zonePath = $repo->getZonePath( 'temp' );
1050  if ( $repo->getBackend()->directoryExists( [ 'dir' => $zonePath ] ) ) {
1051  // If the directory was never made, then it will have the right ACLs when it is made
1052  $status = $repo->getBackend()->secure( [
1053  'dir' => $zonePath,
1054  'noAccess' => true,
1055  'noListing' => true
1056  ] );
1057  if ( $status->isOK() ) {
1058  $this->output( "Set the local repo temp zone container to be private.\n" );
1059  } else {
1060  $this->output( "Failed to set the local repo temp zone container to be private.\n" );
1061  }
1062  }
1063  }
1064 
1068  public function purgeCache() {
1069  global $wgLocalisationCacheConf;
1070  // We can't guarantee that the user will be able to use TRUNCATE,
1071  // but we know that DELETE is available to us
1072  $this->output( "Purging caches..." );
1073 
1074  // ObjectCache
1075  $this->db->delete( 'objectcache', '*', __METHOD__ );
1076 
1077  // LocalisationCache
1078  if ( $wgLocalisationCacheConf['manualRecache'] ) {
1079  $this->rebuildLocalisationCache();
1080  }
1081 
1082  // ResourceLoader: Message cache
1083  $blobStore = new MessageBlobStore(
1084  MediaWikiServices::getInstance()->getResourceLoader()
1085  );
1086  $blobStore->clear();
1087 
1088  // ResourceLoader: File-dependency cache
1089  $this->db->delete( 'module_deps', '*', __METHOD__ );
1090  $this->output( "done.\n" );
1091  }
1092 
1096  protected function checkStats() {
1097  $this->output( "...site_stats is populated..." );
1098  $row = $this->db->selectRow( 'site_stats', '*', [ 'ss_row_id' => 1 ], __METHOD__ );
1099  if ( $row === false ) {
1100  $this->output( "data is missing! rebuilding...\n" );
1101  } elseif ( isset( $row->site_stats ) && $row->ss_total_pages == -1 ) {
1102  $this->output( "missing ss_total_pages, rebuilding...\n" );
1103  } else {
1104  $this->output( "done.\n" );
1105 
1106  return;
1107  }
1108  SiteStatsInit::doAllAndCommit( $this->db );
1109  }
1110 
1111  # Common updater functions
1112 
1116  protected function doActiveUsersInit() {
1117  $activeUsers = $this->db->selectField( 'site_stats', 'ss_active_users', '', __METHOD__ );
1118  if ( $activeUsers == -1 ) {
1119  $activeUsers = $this->db->selectField( 'recentchanges',
1120  'COUNT( DISTINCT rc_user_text )',
1121  [ 'rc_user != 0', 'rc_bot' => 0, "rc_log_type != 'newusers'" ], __METHOD__
1122  );
1123  $this->db->update( 'site_stats',
1124  [ 'ss_active_users' => intval( $activeUsers ) ],
1125  [ 'ss_row_id' => 1 ], __METHOD__, [ 'LIMIT' => 1 ]
1126  );
1127  }
1128  $this->output( "...ss_active_users user count set...\n" );
1129  }
1130 
1134  protected function doLogUsertextPopulation() {
1135  if ( !$this->updateRowExists( 'populate log_usertext' ) ) {
1136  $this->output(
1137  "Populating log_user_text field, printing progress markers. For large\n" .
1138  "databases, you may want to hit Ctrl-C and do this manually with\n" .
1139  "maintenance/populateLogUsertext.php.\n"
1140  );
1141 
1142  $task = $this->maintenance->runChild( PopulateLogUsertext::class );
1143  $task->execute();
1144  $this->output( "done.\n" );
1145  }
1146  }
1147 
1151  protected function doLogSearchPopulation() {
1152  if ( !$this->updateRowExists( 'populate log_search' ) ) {
1153  $this->output(
1154  "Populating log_search table, printing progress markers. For large\n" .
1155  "databases, you may want to hit Ctrl-C and do this manually with\n" .
1156  "maintenance/populateLogSearch.php.\n" );
1157 
1158  $task = $this->maintenance->runChild( PopulateLogSearch::class );
1159  $task->execute();
1160  $this->output( "done.\n" );
1161  }
1162  }
1163 
1167  protected function doCollationUpdate() {
1168  global $wgCategoryCollation;
1169  if ( $this->db->fieldExists( 'categorylinks', 'cl_collation', __METHOD__ ) ) {
1170  if ( $this->db->selectField(
1171  'categorylinks',
1172  'COUNT(*)',
1173  'cl_collation != ' . $this->db->addQuotes( $wgCategoryCollation ),
1174  __METHOD__
1175  ) == 0
1176  ) {
1177  $this->output( "...collations up-to-date.\n" );
1178 
1179  return;
1180  }
1181 
1182  $this->output( "Updating category collations..." );
1183  $task = $this->maintenance->runChild( UpdateCollation::class );
1184  $task->execute();
1185  $this->output( "...done.\n" );
1186  }
1187  }
1188 
1192  protected function doMigrateUserOptions() {
1193  if ( $this->db->tableExists( 'user_properties' ) ) {
1194  $cl = $this->maintenance->runChild( ConvertUserOptions::class, 'convertUserOptions.php' );
1195  $cl->execute();
1196  $this->output( "done.\n" );
1197  }
1198  }
1199 
1203  protected function doEnableProfiling() {
1204  global $wgProfiler;
1205 
1206  if ( !$this->doTable( 'profiling' ) ) {
1207  return;
1208  }
1209 
1210  $profileToDb = false;
1211  if ( isset( $wgProfiler['output'] ) ) {
1212  $out = $wgProfiler['output'];
1213  if ( $out === 'db' ) {
1214  $profileToDb = true;
1215  } elseif ( is_array( $out ) && in_array( 'db', $out ) ) {
1216  $profileToDb = true;
1217  }
1218  }
1219 
1220  if ( $profileToDb && !$this->db->tableExists( 'profiling', __METHOD__ ) ) {
1221  $this->applyPatch( 'patch-profiling.sql', false, 'Add profiling table' );
1222  }
1223  }
1224 
1228  protected function rebuildLocalisationCache() {
1232  $cl = $this->maintenance->runChild(
1233  RebuildLocalisationCache::class, 'rebuildLocalisationCache.php'
1234  );
1235  $this->output( "Rebuilding localisation cache...\n" );
1236  $cl->setForce();
1237  $cl->execute();
1238  $this->output( "done.\n" );
1239  }
1240 
1245  protected function disableContentHandlerUseDB() {
1246  global $wgContentHandlerUseDB;
1247 
1248  if ( $wgContentHandlerUseDB ) {
1249  $this->output( "Turning off Content Handler DB fields for this part of upgrade.\n" );
1250  $this->holdContentHandlerUseDB = $wgContentHandlerUseDB;
1251  $wgContentHandlerUseDB = false;
1252  }
1253  }
1254 
1258  protected function enableContentHandlerUseDB() {
1259  global $wgContentHandlerUseDB;
1260 
1261  if ( $this->holdContentHandlerUseDB ) {
1262  $this->output( "Content Handler DB fields should be usable now.\n" );
1263  $wgContentHandlerUseDB = $this->holdContentHandlerUseDB;
1264  }
1265  }
1266 
1271  protected function migrateComments() {
1272  if ( !$this->updateRowExists( 'MigrateComments' ) ) {
1273  $this->output(
1274  "Migrating comments to the 'comments' table, printing progress markers. For large\n" .
1275  "databases, you may want to hit Ctrl-C and do this manually with\n" .
1276  "maintenance/migrateComments.php.\n"
1277  );
1278  $task = $this->maintenance->runChild( MigrateComments::class, 'migrateComments.php' );
1279  $ok = $task->execute();
1280  $this->output( $ok ? "done.\n" : "errors were encountered.\n" );
1281  }
1282  }
1283 
1288  protected function migrateImageCommentTemp() {
1289  if ( $this->tableExists( 'image_comment_temp' ) ) {
1290  $this->output( "Merging image_comment_temp into the image table\n" );
1291  $task = $this->maintenance->runChild(
1292  MigrateImageCommentTemp::class, 'migrateImageCommentTemp.php'
1293  );
1294  $task->setForce();
1295  $ok = $task->execute();
1296  $this->output( $ok ? "done.\n" : "errors were encountered.\n" );
1297  if ( $ok ) {
1298  $this->dropTable( 'image_comment_temp' );
1299  }
1300  }
1301  }
1302 
1307  protected function migrateActors() {
1309  if ( ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) &&
1310  !$this->updateRowExists( 'MigrateActors' )
1311  ) {
1312  $this->output(
1313  "Migrating actors to the 'actor' table, printing progress markers. For large\n" .
1314  "databases, you may want to hit Ctrl-C and do this manually with\n" .
1315  "maintenance/migrateActors.php.\n"
1316  );
1317  $task = $this->maintenance->runChild( 'MigrateActors', 'migrateActors.php' );
1318  $ok = $task->execute();
1319  $this->output( $ok ? "done.\n" : "errors were encountered.\n" );
1320  }
1321  }
1322 
1327  protected function migrateArchiveText() {
1328  if ( $this->db->fieldExists( 'archive', 'ar_text', __METHOD__ ) ) {
1329  $this->output( "Migrating archive ar_text to modern storage.\n" );
1330  $task = $this->maintenance->runChild( MigrateArchiveText::class, 'migrateArchiveText.php' );
1331  $task->setForce();
1332  if ( $task->execute() ) {
1333  $this->applyPatch( 'patch-drop-ar_text.sql', false,
1334  'Dropping ar_text and ar_flags columns' );
1335  }
1336  }
1337  }
1338 
1343  protected function populateArchiveRevId() {
1344  $info = $this->db->fieldInfo( 'archive', 'ar_rev_id', __METHOD__ );
1345  if ( !$info ) {
1346  throw new MWException( 'Missing ar_rev_id field of archive table. Should not happen.' );
1347  }
1348  if ( $info->isNullable() ) {
1349  $this->output( "Populating ar_rev_id.\n" );
1350  $task = $this->maintenance->runChild( 'PopulateArchiveRevId', 'populateArchiveRevId.php' );
1351  if ( $task->execute() ) {
1352  $this->applyPatch( 'patch-ar_rev_id-not-null.sql', false,
1353  'Making ar_rev_id not nullable' );
1354  }
1355  }
1356  }
1357 
1362  protected function populateExternallinksIndex60() {
1363  if ( !$this->updateRowExists( 'populate externallinks.el_index_60' ) ) {
1364  $this->output(
1365  "Populating el_index_60 field, printing progress markers. For large\n" .
1366  "databases, you may want to hit Ctrl-C and do this manually with\n" .
1367  "maintenance/populateExternallinksIndex60.php.\n"
1368  );
1369  $task = $this->maintenance->runChild( 'PopulateExternallinksIndex60',
1370  'populateExternallinksIndex60.php' );
1371  $task->execute();
1372  $this->output( "done.\n" );
1373  }
1374  }
1375 
1380  protected function populateContentTables() {
1382  if ( ( $wgMultiContentRevisionSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) &&
1383  !$this->updateRowExists( 'PopulateContentTables' )
1384  ) {
1385  $this->output(
1386  "Migrating revision data to the MCR 'slot' and 'content' tables, printing progress markers.\n" .
1387  "For large databases, you may want to hit Ctrl-C and do this manually with\n" .
1388  "maintenance/populateContentTables.php.\n"
1389  );
1390  $task = $this->maintenance->runChild(
1391  PopulateContentTables::class, 'populateContentTables.php'
1392  );
1393  $ok = $task->execute();
1394  $this->output( $ok ? "done.\n" : "errors were encountered.\n" );
1395  if ( $ok ) {
1396  $this->insertUpdateRow( 'PopulateContentTables' );
1397  }
1398  }
1399  }
1400 }
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
dropExtensionIndex( $tableName, $indexName, $sqlPath)
Drop an index from an extension table.
This class generates message blobs for use by ResourceLoader modules.
getSchemaVars()
Get appropriate schema variables in the current database connection.
array $extensionUpdates
List of extension-provided database updates.
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
$data
Utility to generate mapping file used in mw.Title (phpCharToUpper.json)
modifyField( $table, $field, $patch, $fullpath=false)
Modify an existing field.
getExtensionUpdates()
Get the list of extension-defined updates.
canUseNewUpdatelog()
Updatelog was changed in 1.17 to have a ul_value column so we can record more information about what ...
$IP
Definition: WebStart.php:41
IMaintainableDatabase $db
Handle to the database subclass.
int $wgMultiContentRevisionSchemaMigrationStage
RevisionStore table schema migration stage (content, slots, content_models & slot_roles tables)...
loadExtensions()
Loads LocalSettings.php, if needed, and initialises everything needed for LoadExtensionSchemaUpdates ...
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Definition: hooks.txt:1982
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
appendLine( $line)
Append a line to the open filehandle.
addExtensionTable( $tableName, $sqlPath)
Convenience wrapper for addExtensionUpdate() when adding a new table (which is the most common usage ...
copyFile( $filename)
Append an SQL fragment to the open file handle.
patchPath(IDatabase $db, $patch)
Get the full path of a patch file.
int $wgActorTableSchemaMigrationStage
Actor table schema migration stage.
Class for handling database updates.
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
Definition: maintenance.txt:39
insertUpdateRow( $key, $val=null)
Helper function: Add a key to the updatelog table Obviously, only use this for updates that occur aft...
modifyTable( $table, $patch, $fullpath=false)
Modify an existing table, similar to modifyField.
$wgSharedTables
resource $fileHandle
File handle for SQL output.
rebuildLocalisationCache()
Rebuilds the localisation cache.
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency MediaWikiServices
Definition: injection.txt:23
string [] $postDatabaseUpdateMaintenance
Scripts to run after database update Should be a subclass of LoggedUpdateMaintenance.
renameExtensionIndex( $tableName, $oldIndexName, $newIndexName, $sqlPath, $skipBothIndexExistWarning=false)
Rename an index on an extension table.
checkStats()
Check the site_stats table is not properly populated.
$wgCategoryCollation
Specify how category names should be sorted, when listed on a category page.
dropExtensionField( $tableName, $columnName, $sqlPath)
const DBO_DDLMODE
Definition: defines.php:16
bool $skipSchema
Flag specifying whether or not to skip schema (e.g.
writeSchemaUpdateFile(array $schemaUpdate=[])
if( $line===false) $args
Definition: cdb.php:64
$wgContentHandlerUseDB
Set to false to disable use of the database fields introduced by the ContentHandler facility...
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that When $user is not it can be in the form of< username >< more info > e g for bot passwords intended to be added to log contexts Fields it might only if the login was with a bot password it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output $out
Definition: hooks.txt:780
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return true
Definition: hooks.txt:1982
Fake maintenance wrapper, mostly used for the web installer/updater.
getDB()
Get a database connection to run updates.
Status::newGood()` to allow deletion, and then `return false` from the hook function. Ensure you consume the 'ChangeTagAfterDelete' hook to carry out custom deletion actions. $tag:name of the tag $user:user initiating the action & $status:Status object. See above. 'ChangeTagsListActive':Allows you to nominate which of the tags your extension uses are in active use. & $tags:list of all active tags. Append to this array. 'ChangeTagsAfterUpdateTags':Called after tags have been updated with the ChangeTags::updateTags function. Params:$addedTags:tags effectively added in the update $removedTags:tags effectively removed in the update $prevTags:tags that were present prior to the update $rc_id:recentchanges table id $rev_id:revision table id $log_id:logging table id $params:tag params $rc:RecentChange being tagged when the tagging accompanies the action, or null $user:User who performed the tagging when the tagging is subsequent to the action, or null 'ChangeTagsAllowedAdd':Called when checking if a user can add tags to a change. & $allowedTags:List of all the tags the user is allowed to add. Any tags the user wants to add( $addTags) that are not in this array will cause it to fail. You may add or remove tags to this array as required. $addTags:List of tags user intends to add. $user:User who is adding the tags. 'ChangeUserGroups':Called before user groups are changed. $performer:The User who will perform the change $user:The User whose groups will be changed & $add:The groups that will be added & $remove:The groups that will be removed 'Collation::factory':Called if $wgCategoryCollation is an unknown collation. $collationName:Name of the collation in question & $collationObject:Null. Replace with a subclass of the Collation class that implements the collation given in $collationName. 'ConfirmEmailComplete':Called after a user 's email has been confirmed successfully. $user:user(object) whose email is being confirmed 'ContentAlterParserOutput':Modify parser output for a given content object. Called by Content::getParserOutput after parsing has finished. Can be used for changes that depend on the result of the parsing but have to be done before LinksUpdate is called(such as adding tracking categories based on the rendered HTML). $content:The Content to render $title:Title of the page, as context $parserOutput:ParserOutput to manipulate 'ContentGetParserOutput':Customize parser output for a given content object, called by AbstractContent::getParserOutput. May be used to override the normal model-specific rendering of page content. $content:The Content to render $title:Title of the page, as context $revId:The revision ID, as context $options:ParserOptions for rendering. To avoid confusing the parser cache, the output can only depend on parameters provided to this hook function, not on global state. $generateHtml:boolean, indicating whether full HTML should be generated. If false, generation of HTML may be skipped, but other information should still be present in the ParserOutput object. & $output:ParserOutput, to manipulate or replace 'ContentHandlerDefaultModelFor':Called when the default content model is determined for a given title. May be used to assign a different model for that title. $title:the Title in question & $model:the model name. Use with CONTENT_MODEL_XXX constants. 'ContentHandlerForModelID':Called when a ContentHandler is requested for a given content model name, but no entry for that model exists in $wgContentHandlers. Note:if your extension implements additional models via this hook, please use GetContentModels hook to make them known to core. $modeName:the requested content model name & $handler:set this to a ContentHandler object, if desired. 'ContentModelCanBeUsedOn':Called to determine whether that content model can be used on a given page. This is especially useful to prevent some content models to be used in some special location. $contentModel:ID of the content model in question $title:the Title in question. & $ok:Output parameter, whether it is OK to use $contentModel on $title. Handler functions that modify $ok should generally return false to prevent further hooks from further modifying $ok. 'ContribsPager::getQueryInfo':Before the contributions query is about to run & $pager:Pager object for contributions & $queryInfo:The query for the contribs Pager 'ContribsPager::reallyDoQuery':Called before really executing the query for My Contributions & $data:an array of results of all contribs queries $pager:The ContribsPager object hooked into $offset:Index offset, inclusive $limit:Exact query limit $descending:Query direction, false for ascending, true for descending 'ContributionsLineEnding':Called before a contributions HTML line is finished $page:SpecialPage object for contributions & $ret:the HTML line $row:the DB row for this line & $classes:the classes to add to the surrounding< li > & $attribs:associative array of other HTML attributes for the< li > element. Currently only data attributes reserved to MediaWiki are allowed(see Sanitizer::isReservedDataAttribute). 'ContributionsToolLinks':Change tool links above Special:Contributions $id:User identifier $title:User page title & $tools:Array of tool links $specialPage:SpecialPage instance for context and services. Can be either SpecialContributions or DeletedContributionsPage. Extensions should type hint against a generic SpecialPage though. 'ConvertContent':Called by AbstractContent::convert when a conversion to another content model is requested. Handler functions that modify $result should generally return false to disable further attempts at conversion. $content:The Content object to be converted. $toModel:The ID of the content model to convert to. $lossy:boolean indicating whether lossy conversion is allowed. & $result:Output parameter, in case the handler function wants to provide a converted Content object. Note that $result->getContentModel() must return $toModel. 'ContentSecurityPolicyDefaultSource':Modify the allowed CSP load sources. This affects all directives except for the script directive. If you want to add a script source, see ContentSecurityPolicyScriptSource hook. & $defaultSrc:Array of Content-Security-Policy allowed sources $policyConfig:Current configuration for the Content-Security-Policy header $mode:ContentSecurityPolicy::REPORT_ONLY_MODE or ContentSecurityPolicy::FULL_MODE depending on type of header 'ContentSecurityPolicyDirectives':Modify the content security policy directives. Use this only if ContentSecurityPolicyDefaultSource and ContentSecurityPolicyScriptSource do not meet your needs. & $directives:Array of CSP directives $policyConfig:Current configuration for the CSP header $mode:ContentSecurityPolicy::REPORT_ONLY_MODE or ContentSecurityPolicy::FULL_MODE depending on type of header 'ContentSecurityPolicyScriptSource':Modify the allowed CSP script sources. Note that you also have to use ContentSecurityPolicyDefaultSource if you want non-script sources to be loaded from whatever you add. & $scriptSrc:Array of CSP directives $policyConfig:Current configuration for the CSP header $mode:ContentSecurityPolicy::REPORT_ONLY_MODE or ContentSecurityPolicy::FULL_MODE depending on type of header 'CustomEditor':When invoking the page editor Return true to allow the normal editor to be used, or false if implementing a custom editor, e.g. for a special namespace, etc. $article:Article being edited $user:User performing the edit 'DeletedContribsPager::reallyDoQuery':Called before really executing the query for Special:DeletedContributions Similar to ContribsPager::reallyDoQuery & $data:an array of results of all contribs queries $pager:The DeletedContribsPager object hooked into $offset:Index offset, inclusive $limit:Exact query limit $descending:Query direction, false for ascending, true for descending 'DeletedContributionsLineEnding':Called before a DeletedContributions HTML line is finished. Similar to ContributionsLineEnding $page:SpecialPage object for DeletedContributions & $ret:the HTML line $row:the DB row for this line & $classes:the classes to add to the surrounding< li > & $attribs:associative array of other HTML attributes for the< li > element. Currently only data attributes reserved to MediaWiki are allowed(see Sanitizer::isReservedDataAttribute). 'DeleteUnknownPreferences':Called by the cleanupPreferences.php maintenance script to build a WHERE clause with which to delete preferences that are not known about. This hook is used by extensions that have dynamically-named preferences that should not be deleted in the usual cleanup process. For example, the Gadgets extension creates preferences prefixed with 'gadget-', and so anything with that prefix is excluded from the deletion. &where:An array that will be passed as the $cond parameter to IDatabase::select() to determine what will be deleted from the user_properties table. $db:The IDatabase object, useful for accessing $db->buildLike() etc. 'DifferenceEngineAfterLoadNewText':called in DifferenceEngine::loadNewText() after the new revision 's content has been loaded into the class member variable $differenceEngine->mNewContent but before returning true from this function. $differenceEngine:DifferenceEngine object 'DifferenceEngineLoadTextAfterNewContentIsLoaded':called in DifferenceEngine::loadText() after the new revision 's content has been loaded into the class member variable $differenceEngine->mNewContent but before checking if the variable 's value is null. This hook can be used to inject content into said class member variable. $differenceEngine:DifferenceEngine object 'DifferenceEngineMarkPatrolledLink':Allows extensions to change the "mark as patrolled" link which is shown both on the diff header as well as on the bottom of a page, usually wrapped in a span element which has class="patrollink". $differenceEngine:DifferenceEngine object & $markAsPatrolledLink:The "mark as patrolled" link HTML(string) $rcid:Recent change ID(rc_id) for this change(int) 'DifferenceEngineMarkPatrolledRCID':Allows extensions to possibly change the rcid parameter. For example the rcid might be set to zero due to the user being the same as the performer of the change but an extension might still want to show it under certain conditions. & $rcid:rc_id(int) of the change or 0 $differenceEngine:DifferenceEngine object $change:RecentChange object $user:User object representing the current user 'DifferenceEngineNewHeader':Allows extensions to change the $newHeader variable, which contains information about the new revision, such as the revision 's author, whether the revision was marked as a minor edit or not, etc. $differenceEngine:DifferenceEngine object & $newHeader:The string containing the various #mw-diff-otitle[1-5] divs, which include things like revision author info, revision comment, RevisionDelete link and more $formattedRevisionTools:Array containing revision tools, some of which may have been injected with the DiffRevisionTools hook $nextlink:String containing the link to the next revision(if any) $status
Definition: hooks.txt:1263
populateArchiveRevId()
Populate ar_rev_id, then make it not nullable.
$wgHooks['ArticleShow'][]
Definition: hooks.txt:108
migrateImageCommentTemp()
Merge image_comment_temp into the image table.
addExtensionField( $tableName, $columnName, $sqlPath)
$wgLocalisationCacheConf
Localisation cache configuration.
disableContentHandlerUseDB()
Turns off content handler fields during parts of the upgrade where they aren&#39;t available.
initOldGlobals()
Initialize all of the old globals.
array $updates
Array of updates to perform on the database.
addIndex( $table, $index, $patch, $fullpath=false)
Add a new index to an existing table.
array $updatesSkipped
Array of updates that were skipped.
const SCHEMA_COMPAT_WRITE_NEW
Definition: Defines.php:286
static singleton()
Get a RepoGroup instance.
Definition: RepoGroup.php:61
dropExtensionTable( $tableName, $sqlPath)
populateContentTables()
Populates the MCR content tables.
static getExistingLocalSettings()
Determine if LocalSettings.php exists.
Definition: Installer.php:592
addTable( $name, $patch, $fullpath=false)
Add a new table to the database.
setDB(IDatabase $db)
Sets database object to be returned by getDB().
$params
migrateArchiveText()
Migrate ar_text to modern storage.
addIndexIfNoneExist( $table, $indexes, $patch, $fullpath=false)
Add a new index to an existing table if none of the given indexes exist.
purgeCache()
Purge various database caches.
const REPLICATION_WAIT_TIMEOUT
addExtensionIndex( $tableName, $indexName, $sqlPath)
$wgSharedDB
Shared database for multiple wikis.
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that When $user is not null
Definition: hooks.txt:780
addPostDatabaseUpdateMaintenance( $class)
Add a maintenance script to be run after the database updates are complete.
migrateActors()
Migrate actors to the new &#39;actor&#39; table.
modifyExtensionField( $tableName, $fieldName, $sqlPath)
doEnableProfiling()
Enable profiling table when it&#39;s turned on.
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
getCoreUpdateList()
Get an array of updates to perform on the database.
doActiveUsersInit()
Sets the number of active users in the site_stats table.
dropField( $table, $field, $patch, $fullpath=false)
Drop a field from an existing table.
setFlag( $flag, $remember=self::REMEMBER_NOTHING)
Set a flag for this connection.
renameIndex( $table, $oldIndex, $newIndex, $skipBothIndexExistWarning, $patch, $fullpath=false)
Rename an index from an existing table.
Maintenance $maintenance
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
getType()
Get the type of the DBMS, as it appears in $wgDBtype.
dropIndex( $table, $index, $patch, $fullpath=false)
Drop an index from an existing table.
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:38
you have access to all of the normal MediaWiki so you can get a DB use the etc For full docs on the Maintenance class
Definition: maintenance.txt:52
doMigrateUserOptions()
Migrates user options from the user table blob to user_properties.
Advanced database interface for IDatabase handles that include maintenance methods.
migrateComments()
Migrate comments to the new &#39;comment&#39; table.
output( $str)
Output some text.
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these updates(as a Java servelet could)
applyPatch( $path, $isFullPath=false, $msg=null)
Applies a SQL patch.
modifyExtensionTable( $tableName, $sqlPath)
dropTable( $table, $patch=false, $fullpath=false)
If the specified table exists, drop it, or execute the patch if one is provided.
$line
Definition: cdb.php:59
global $wgCommandLineMode
runMaintenance( $class, $script)
Run a maintenance script.
doUpdates(array $what=[ 'core', 'extensions', 'stats'])
Do all the updates.
static doAllAndCommit( $database, array $options=[])
Do all updates and commit them.
static newForDB(IMaintainableDatabase $db, $shared=false, Maintenance $maintenance=null)
populateExternallinksIndex60()
Populates the externallinks.el_index_60 field.
doLogSearchPopulation()
Migrate log params to new table and index for searching.
runUpdates(array $updates, $passSelf)
Helper function for doUpdates()
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:271
updateRowExists( $key)
Helper function: check if the given key is present in the updatelog table.
static getDBTypes()
Get a list of known DB types.
Definition: Installer.php:469
$wgAutoloadClasses
Array mapping class names to filenames, for autoloading.
__construct(IMaintainableDatabase &$db, $shared, Maintenance $maintenance=null)
$holdContentHandlerUseDB
Hold the value of $wgContentHandlerUseDB during the upgrade.
enableContentHandlerUseDB()
Turns content handler fields back on.
addField( $table, $field, $patch, $fullpath=false)
Add a new field to an existing table.
addExtensionUpdate(array $update)
Add a new update coming from an extension.
doTable( $name)
Returns whether updates should be executed on the database table $name.
$wgProfiler
Profiler configuration.
setFileAccess()
Set any .htaccess files or equivilent for storage repos.
static configuration should be added through ResourceLoaderGetConfigVars instead & $vars
Definition: hooks.txt:2217
doCollationUpdate()
Update CategoryLinks collation.
getOldGlobalUpdates()
Before 1.17, we used to handle updates via stuff like $wgExtNewTables/Fields/Indexes.
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:200
doLogUsertextPopulation()
Populates the log_user_text field in the logging table.
tableExists( $tableName)