Merge "Remove @param comments that literally repeat what the code says"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Thu, 11 Jan 2018 23:48:03 +0000 (23:48 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Thu, 11 Jan 2018 23:48:03 +0000 (23:48 +0000)
16 files changed:
1  2 
includes/EditPage.php
includes/GlobalFunctions.php
includes/Linker.php
includes/OutputPage.php
includes/Preferences.php
includes/Xml.php
includes/actions/InfoAction.php
includes/api/ApiBase.php
includes/cache/CacheDependency.php
includes/libs/objectcache/MemcachedClient.php
includes/parser/Parser.php
includes/resourceloader/ResourceLoaderModule.php
includes/search/SearchExactMatchRescorer.php
includes/specials/SpecialRecentchanges.php
includes/user/User.php
maintenance/generateSitemap.php

diff --combined includes/EditPage.php
@@@ -780,7 -780,7 +780,7 @@@ class EditPage 
  
        /**
         * Display a read-only View Source page
-        * @param Content $content content object
+        * @param Content $content
         * @param string $errorMessage additional wikitext error message to display
         */
        protected function displayViewSourcePage( Content $content, $errorMessage = '' ) {
                        // and fallback to the raw wpTextbox1 since editconflicts can't be
                        // resolved between page source edits and custom ui edits using the
                        // custom edit ui.
 -                      $this->showTextbox1();
 +                      $conflictTextBoxAttribs = [];
 +                      if ( $this->wasDeletedSinceLastEdit() ) {
 +                              $conflictTextBoxAttribs['style'] = 'display:none;';
 +                      } elseif ( $this->isOldRev ) {
 +                              $conflictTextBoxAttribs['class'] = 'mw-textarea-oldrev';
 +                      }
 +
 +                      $out->addHTML( $editConflictHelper->getEditConflictMainTextBox( $conflictTextBoxAttribs ) );
                        $out->addHTML( $editConflictHelper->getEditFormHtmlAfterContent() );
                } else {
                        $this->showContentForm();
                if ( $this->wasDeletedSinceLastEdit() && $this->formtype == 'save' ) {
                        $attribs = [ 'style' => 'display:none;' ];
                } else {
 -                      $classes = []; // Textarea CSS
 -                      if ( $this->mTitle->isProtected( 'edit' ) &&
 -                              MWNamespace::getRestrictionLevels( $this->mTitle->getNamespace() ) !== [ '' ]
 -                      ) {
 -                              # Is the title semi-protected?
 -                              if ( $this->mTitle->isSemiProtected() ) {
 -                                      $classes[] = 'mw-textarea-sprotected';
 -                              } else {
 -                                      # Then it must be protected based on static groups (regular)
 -                                      $classes[] = 'mw-textarea-protected';
 -                              }
 -                              # Is the title cascade-protected?
 -                              if ( $this->mTitle->isCascadeProtected() ) {
 -                                      $classes[] = 'mw-textarea-cprotected';
 -                              }
 -                      }
 +                      $builder = new TextboxBuilder();
 +                      $classes = $builder->getTextboxProtectionCSSClasses( $this->getTitle() );
 +
                        # Is an old revision being edited?
                        if ( $this->isOldRev ) {
                                $classes[] = 'mw-textarea-oldrev';
                                $attribs += $customAttribs;
                        }
  
 -                      if ( count( $classes ) ) {
 -                              if ( isset( $attribs['class'] ) ) {
 -                                      $classes[] = $attribs['class'];
 -                              }
 -                              $attribs['class'] = implode( ' ', $classes );
 -                      }
 +                      $attribs = $builder->mergeClassesIntoAttributes( $classes, $attribs );
                }
  
                $this->showTextbox(
         * @return string HTML
         */
        public static function getPreviewLimitReport( $output ) {
 +              global $wgLang;
 +
                if ( !$output || !$output->getLimitReportData() ) {
                        return '';
                }
                                if ( !$keyMsg->isDisabled() && !$valueMsg->isDisabled() ) {
                                        $limitReport .= Html::openElement( 'tr' ) .
                                                Html::rawElement( 'th', null, $keyMsg->parse() ) .
 -                                              Html::rawElement( 'td', null, $valueMsg->params( $value )->parse() ) .
 +                                              Html::rawElement( 'td', null,
 +                                                      $wgLang->formatNum( $valueMsg->params( $value )->parse() )
 +                                              ) .
                                                Html::closeElement( 'tr' );
                                }
                        }
                $out->addHTML( implode( $this->getEditButtons( $tabindex ), "\n" ) . "\n" );
  
                $cancel = $this->getCancelLink();
 -              if ( $cancel !== '' ) {
 -                      $cancel .= Html::element( 'span',
 -                              [ 'class' => 'mw-editButtons-pipe-separator' ],
 -                              $this->context->msg( 'pipe-separator' )->text() );
 -              }
  
                $message = $this->context->msg( 'edithelppage' )->inContentLanguage()->text();
                $edithelpurl = Skin::makeInternalOrExternalUrl( $message );
@@@ -24,6 -24,7 +24,6 @@@ if ( !defined( 'MEDIAWIKI' ) ) 
        die( "This file is part of MediaWiki, it is not a valid entry point" );
  }
  
 -use Liuggio\StatsdClient\Sender\SocketSender;
  use MediaWiki\Logger\LoggerFactory;
  use MediaWiki\ProcOpenError;
  use MediaWiki\Session\SessionManager;
@@@ -1010,7 -1011,7 +1010,7 @@@ function wfMakeUrlIndexes( $url ) 
  
  /**
   * Check whether a given URL has a domain that occurs in a given set of domains
-  * @param string $url URL
+  * @param string $url
   * @param array $domains Array of domains (strings)
   * @return bool True if the host part of $url ends in one of the strings in $domains
   */
@@@ -1230,7 -1231,6 +1230,7 @@@ function wfErrorLog( $text, $file, arra
  
  /**
   * @todo document
 + * @todo Move logic to MediaWiki.php
   */
  function wfLogProfilingData() {
        global $wgDebugLogGroups, $wgDebugRawPage;
        $profiler->setContext( $context );
        $profiler->logData();
  
 -      $config = $context->getConfig();
 -      $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
 -      if ( $config->get( 'StatsdServer' ) && $stats->hasData() ) {
 -              try {
 -                      $statsdServer = explode( ':', $config->get( 'StatsdServer' ) );
 -                      $statsdHost = $statsdServer[0];
 -                      $statsdPort = isset( $statsdServer[1] ) ? $statsdServer[1] : 8125;
 -                      $statsdSender = new SocketSender( $statsdHost, $statsdPort );
 -                      $statsdClient = new SamplingStatsdClient( $statsdSender, true, false );
 -                      $statsdClient->setSamplingRates( $config->get( 'StatsdSamplingRates' ) );
 -                      $statsdClient->send( $stats->getData() );
 -              } catch ( Exception $ex ) {
 -                      MWExceptionHandler::logException( $ex );
 -              }
 -      }
 +      // Send out any buffered statsd metrics as needed
 +      MediaWiki::emitBufferedStatsdData(
 +              MediaWikiServices::getInstance()->getStatsdDataFactory(),
 +              $context->getConfig()
 +      );
  
 -      # Profiling must actually be enabled...
 +      // Profiling must actually be enabled...
        if ( $profiler instanceof ProfilerStub ) {
                return;
        }
@@@ -2088,16 -2098,6 +2088,16 @@@ function wfIsHHVM() 
        return defined( 'HHVM_VERSION' );
  }
  
 +/**
 + * Check if we are running from the commandline
 + *
 + * @since 1.31
 + * @return bool
 + */
 +function wfIsCLI() {
 +      return PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg';
 +}
 +
  /**
   * Tries to get the system directory for temporary files. First
   * $wgTmpDirectory is checked, and then the TMPDIR, TMP, and TEMP
@@@ -2920,7 -2920,7 +2920,7 @@@ function wfGetLBFactory() 
   * Find a file.
   * Shortcut for RepoGroup::singleton()->findFile()
   *
 - * @param string $title String or Title object
 + * @param string|Title $title String or Title object
   * @param array $options Associative array of options (see RepoGroup::findFile)
   * @return File|bool File, or false if the file does not exist
   */
@@@ -3041,7 -3041,7 +3041,7 @@@ function wfWaitForSlaves
        $ifWritesSince = null, $wiki = false, $cluster = false, $timeout = null
  ) {
        if ( $timeout === null ) {
 -              $timeout = ( PHP_SAPI === 'cli' ) ? 86400 : 10;
 +              $timeout = wfIsCLI() ? 86400 : 10;
        }
  
        if ( $cluster === '*' ) {
diff --combined includes/Linker.php
@@@ -1023,7 -1023,7 +1023,7 @@@ class Linker 
  
        /**
         * @since 1.16.3
-        * @param int $userId Userid
+        * @param int $userId
         * @param string $userText User name in database.
         * @return string HTML fragment with block link
         */
        }
  
        /**
-        * @param int $userId Userid
+        * @param int $userId
         * @param string $userText User name in database.
         * @return string HTML fragment with e-mail user link
         */
         *
         * @since 1.16.3 $msgParams added in 1.27
         * @param string $name Id of the element, minus prefixes.
 -       * @param string|null $options Null or the string 'withaccess' to add an access-
 -       *   key hint
 +       * @param string|array|null $options Null, string or array with some of the following options:
 +       *   - 'withaccess' to add an access-key hint
 +       *   - 'nonexisting' to add an accessibility hint that page does not exist
         * @param array $msgParams Parameters to pass to the message
         *
         * @return string Contents of the title attribute (which you must HTML-
                        }
                }
  
 -              if ( $options == 'withaccess' ) {
 +              $options = (array)$options;
 +
 +              if ( in_array( 'nonexisting', $options ) ) {
 +                      $tooltip = wfMessage( 'red-link-title', $tooltip ?: '' )->text();
 +              }
 +              if ( in_array( 'withaccess', $options ) ) {
                        $accesskey = self::accesskey( $name );
                        if ( $accesskey !== false ) {
                                // Should be build the same as in jquery.accessKeyLabel.js
                return Xml::tags( 'span', [ 'class' => 'mw-revdelundel-link' ], $htmlParentheses );
        }
  
 -      /* Deprecated methods */
 -
        /**
         * Returns the attributes for the tooltip and access key.
         *
         * @since 1.16.3. $msgParams introduced in 1.27
         * @param string $name
         * @param array $msgParams Params for constructing the message
 +       * @param string|array|null $options Options to be passed to titleAttrib.
 +       *
 +       * @see Linker::titleAttrib for what options could be passed to $options.
         *
         * @return array
         */
 -      public static function tooltipAndAccesskeyAttribs( $name, array $msgParams = [] ) {
 +      public static function tooltipAndAccesskeyAttribs(
 +              $name,
 +              array $msgParams = [],
 +              $options = null
 +      ) {
 +              $options = (array)$options;
 +              $options[] = 'withaccess';
 +
                $attribs = [
 -                      'title' => self::titleAttrib( $name, 'withaccess', $msgParams ),
 +                      'title' => self::titleAttrib( $name, $options, $msgParams ),
                        'accesskey' => self::accesskey( $name )
                ];
                if ( $attribs['title'] === false ) {
diff --combined includes/OutputPage.php
@@@ -323,7 -323,7 +323,7 @@@ class OutputPage extends ContextSource 
        /**
         * Redirect to $url rather than displaying the normal page
         *
-        * @param string $url URL
+        * @param string $url
         * @param string $responsecode HTTP status code
         */
        public function redirect( $url, $responsecode = '302' ) {
         * Add a new "<meta>" tag
         * To add an http-equiv meta tag, precede the name with "http:"
         *
 -       * @param string $name Tag name
 -       * @param string $val Tag value
 +       * @param string $name Name of the meta tag
 +       * @param string $val Value of the meta tag
         */
        function addMeta( $name, $val ) {
                array_push( $this->mMetatags, [ $name, $val ] );
diff --combined includes/Preferences.php
   *
   * @file
   */
 +
  use MediaWiki\Auth\AuthManager;
 -use MediaWiki\Auth\PasswordAuthenticationRequest;
  use MediaWiki\MediaWikiServices;
 +use MediaWiki\Preferences\DefaultPreferencesFactory;
  
  /**
 - * We're now using the HTMLForm object with some customisation to generate the
 - * Preferences form. This object handles generic submission, CSRF protection,
 - * layout and other logic in a reusable manner. We subclass it as a PreferencesForm
 - * to make some minor customisations.
 - *
 - * In order to generate the form, the HTMLForm object needs an array structure
 - * detailing the form fields available, and that's what this class is for. Each
 - * element of the array is a basic property-list, including the type of field,
 - * the label it is to be given in the form, callbacks for validation and
 - * 'filtering', and other pertinent information. Note that the 'default' field
 - * is named for generic forms, and does not represent the preference's default
 - * (which is stored in $wgDefaultUserOptions), but the default for the form
 - * field, which should be whatever the user has set for that preference. There
 - * is no need to override it unless you have some special storage logic (for
 - * instance, those not presently stored as options, but which are best set from
 - * the user preferences view).
 - *
 - * Field types are implemented as subclasses of the generic HTMLFormField
 - * object, and typically implement at least getInputHTML, which generates the
 - * HTML for the input field to be placed in the table.
 + * This class has been replaced by the PreferencesFactory service.
   *
 - * Once fields have been retrieved and validated, submission logic is handed
 - * over to the tryUISubmit static method of this class.
 + * @deprecated since 1.31 use the PreferencesFactory service instead.
   */
  class Preferences {
 -      /** @var array */
 -      protected static $saveFilters = [
 -              'timecorrection' => [ 'Preferences', 'filterTimezoneInput' ],
 -              'rclimit' => [ 'Preferences', 'filterIntval' ],
 -              'wllimit' => [ 'Preferences', 'filterIntval' ],
 -              'searchlimit' => [ 'Preferences', 'filterIntval' ],
 -      ];
  
 -      // Stuff that shouldn't be saved as a preference.
 -      private static $saveBlacklist = [
 -              'realname',
 -              'emailaddress',
 -      ];
 +      /**
 +       * A shim to maintain backwards-compatibility of this class, basically replicating the
 +       * default behaviour of the PreferencesFactory service but not permitting overriding.
 +       * @return DefaultPreferencesFactory
 +       */
 +      protected static function getDefaultPreferencesFactory() {
 +              global $wgContLang;
 +              $authManager = AuthManager::singleton();
 +              $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
 +              $config = MediaWikiServices::getInstance()->getMainConfig();
 +              $preferencesFactory = new DefaultPreferencesFactory(
 +                      $config, $wgContLang, $authManager, $linkRenderer
 +              );
 +              return $preferencesFactory;
 +      }
  
        /**
         * @return array
         */
 -      static function getSaveBlacklist() {
 -              return self::$saveBlacklist;
 +      public static function getSaveBlacklist() {
 +              throw new Exception( __METHOD__ . '() is deprecated and does nothing' );
        }
  
        /**
         * @param IContextSource $context
         * @return array|null
         */
 -      static function getPreferences( $user, IContextSource $context ) {
 -              $defaultPreferences = [];
 -
 -              self::profilePreferences( $user, $context, $defaultPreferences );
 -              self::skinPreferences( $user, $context, $defaultPreferences );
 -              self::datetimePreferences( $user, $context, $defaultPreferences );
 -              self::filesPreferences( $user, $context, $defaultPreferences );
 -              self::renderingPreferences( $user, $context, $defaultPreferences );
 -              self::editingPreferences( $user, $context, $defaultPreferences );
 -              self::rcPreferences( $user, $context, $defaultPreferences );
 -              self::watchlistPreferences( $user, $context, $defaultPreferences );
 -              self::searchPreferences( $user, $context, $defaultPreferences );
 -              self::miscPreferences( $user, $context, $defaultPreferences );
 -
 -              Hooks::run( 'GetPreferences', [ $user, &$defaultPreferences ] );
 -
 -              self::loadPreferenceValues( $user, $context, $defaultPreferences );
 -              return $defaultPreferences;
 +      public static function getPreferences( $user, IContextSource $context ) {
 +              $preferencesFactory = self::getDefaultPreferencesFactory();
 +              return $preferencesFactory->getFormDescriptor( $user, $context );
        }
  
        /**
         * @param array &$defaultPreferences Array to load values for
         * @return array|null
         */
 -      static function loadPreferenceValues( $user, $context, &$defaultPreferences ) {
 -              # # Remove preferences that wikis don't want to use
 -              foreach ( $context->getConfig()->get( 'HiddenPrefs' ) as $pref ) {
 -                      if ( isset( $defaultPreferences[$pref] ) ) {
 -                              unset( $defaultPreferences[$pref] );
 -                      }
 -              }
 -
 -              # # Make sure that form fields have their parent set. See T43337.
 -              $dummyForm = new HTMLForm( [], $context );
 -
 -              $disable = !$user->isAllowed( 'editmyoptions' );
 -
 -              $defaultOptions = User::getDefaultOptions();
 -              # # Prod in defaults from the user
 -              foreach ( $defaultPreferences as $name => &$info ) {
 -                      $prefFromUser = self::getOptionFromUser( $name, $info, $user );
 -                      if ( $disable && !in_array( $name, self::$saveBlacklist ) ) {
 -                              $info['disabled'] = 'disabled';
 -                      }
 -                      $field = HTMLForm::loadInputFromParameters( $name, $info, $dummyForm ); // For validation
 -                      $globalDefault = isset( $defaultOptions[$name] )
 -                              ? $defaultOptions[$name]
 -                              : null;
 -
 -                      // If it validates, set it as the default
 -                      if ( isset( $info['default'] ) ) {
 -                              // Already set, no problem
 -                              continue;
 -                      } elseif ( !is_null( $prefFromUser ) && // Make sure we're not just pulling nothing
 -                                      $field->validate( $prefFromUser, $user->getOptions() ) === true ) {
 -                              $info['default'] = $prefFromUser;
 -                      } elseif ( $field->validate( $globalDefault, $user->getOptions() ) === true ) {
 -                              $info['default'] = $globalDefault;
 -                      } else {
 -                              throw new MWException( "Global default '$globalDefault' is invalid for field $name" );
 -                      }
 -              }
 -
 -              return $defaultPreferences;
 +      public static function loadPreferenceValues( $user, $context, &$defaultPreferences ) {
 +              throw new Exception( __METHOD__ . '() is deprecated and does nothing' );
        }
  
        /**
         * @param User $user
         * @return array|string
         */
 -      static function getOptionFromUser( $name, $info, $user ) {
 -              $val = $user->getOption( $name );
 -
 -              // Handling for multiselect preferences
 -              if ( ( isset( $info['type'] ) && $info['type'] == 'multiselect' ) ||
 -                              ( isset( $info['class'] ) && $info['class'] == 'HTMLMultiSelectField' ) ) {
 -                      $options = HTMLFormField::flattenOptions( $info['options'] );
 -                      $prefix = isset( $info['prefix'] ) ? $info['prefix'] : $name;
 -                      $val = [];
 -
 -                      foreach ( $options as $value ) {
 -                              if ( $user->getOption( "$prefix$value" ) ) {
 -                                      $val[] = $value;
 -                              }
 -                      }
 -              }
 -
 -              // Handling for checkmatrix preferences
 -              if ( ( isset( $info['type'] ) && $info['type'] == 'checkmatrix' ) ||
 -                              ( isset( $info['class'] ) && $info['class'] == 'HTMLCheckMatrix' ) ) {
 -                      $columns = HTMLFormField::flattenOptions( $info['columns'] );
 -                      $rows = HTMLFormField::flattenOptions( $info['rows'] );
 -                      $prefix = isset( $info['prefix'] ) ? $info['prefix'] : $name;
 -                      $val = [];
 -
 -                      foreach ( $columns as $column ) {
 -                              foreach ( $rows as $row ) {
 -                                      if ( $user->getOption( "$prefix$column-$row" ) ) {
 -                                              $val[] = "$column-$row";
 -                                      }
 -                              }
 -                      }
 -              }
 -
 -              return $val;
 +      public static function getOptionFromUser( $name, $info, $user ) {
 +              throw new Exception( __METHOD__ . '() is deprecated and does nothing' );
        }
  
        /**
         * @param array &$defaultPreferences
         * @return void
         */
 -      static function profilePreferences( $user, IContextSource $context, &$defaultPreferences ) {
 -              global $wgContLang, $wgParser;
 -
 -              $authManager = AuthManager::singleton();
 -              $config = $context->getConfig();
 -              // retrieving user name for GENDER and misc.
 -              $userName = $user->getName();
 -
 -              # # User info #####################################
 -              // Information panel
 -              $defaultPreferences['username'] = [
 -                      'type' => 'info',
 -                      'label-message' => [ 'username', $userName ],
 -                      'default' => $userName,
 -                      'section' => 'personal/info',
 -              ];
 -
 -              $lang = $context->getLanguage();
 -
 -              # Get groups to which the user belongs
 -              $userEffectiveGroups = $user->getEffectiveGroups();
 -              $userGroupMemberships = $user->getGroupMemberships();
 -              $userGroups = $userMembers = $userTempGroups = $userTempMembers = [];
 -              foreach ( $userEffectiveGroups as $ueg ) {
 -                      if ( $ueg == '*' ) {
 -                              // Skip the default * group, seems useless here
 -                              continue;
 -                      }
 -
 -                      if ( isset( $userGroupMemberships[$ueg] ) ) {
 -                              $groupStringOrObject = $userGroupMemberships[$ueg];
 -                      } else {
 -                              $groupStringOrObject = $ueg;
 -                      }
 -
 -                      $userG = UserGroupMembership::getLink( $groupStringOrObject, $context, 'html' );
 -                      $userM = UserGroupMembership::getLink( $groupStringOrObject, $context, 'html',
 -                              $userName );
 -
 -                      // Store expiring groups separately, so we can place them before non-expiring
 -                      // groups in the list. This is to avoid the ambiguity of something like
 -                      // "administrator, bureaucrat (until X date)" -- users might wonder whether the
 -                      // expiry date applies to both groups, or just the last one
 -                      if ( $groupStringOrObject instanceof UserGroupMembership &&
 -                              $groupStringOrObject->getExpiry()
 -                      ) {
 -                              $userTempGroups[] = $userG;
 -                              $userTempMembers[] = $userM;
 -                      } else {
 -                              $userGroups[] = $userG;
 -                              $userMembers[] = $userM;
 -                      }
 -              }
 -              sort( $userGroups );
 -              sort( $userMembers );
 -              sort( $userTempGroups );
 -              sort( $userTempMembers );
 -              $userGroups = array_merge( $userTempGroups, $userGroups );
 -              $userMembers = array_merge( $userTempMembers, $userMembers );
 -
 -              $defaultPreferences['usergroups'] = [
 -                      'type' => 'info',
 -                      'label' => $context->msg( 'prefs-memberingroups' )->numParams(
 -                              count( $userGroups ) )->params( $userName )->parse(),
 -                      'default' => $context->msg( 'prefs-memberingroups-type' )
 -                              ->rawParams( $lang->commaList( $userGroups ), $lang->commaList( $userMembers ) )
 -                              ->escaped(),
 -                      'raw' => true,
 -                      'section' => 'personal/info',
 -              ];
 -
 -              $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
 -
 -              $editCount = $linkRenderer->makeLink( SpecialPage::getTitleFor( "Contributions", $userName ),
 -                      $lang->formatNum( $user->getEditCount() ) );
 -
 -              $defaultPreferences['editcount'] = [
 -                      'type' => 'info',
 -                      'raw' => true,
 -                      'label-message' => 'prefs-edits',
 -                      'default' => $editCount,
 -                      'section' => 'personal/info',
 -              ];
 -
 -              if ( $user->getRegistration() ) {
 -                      $displayUser = $context->getUser();
 -                      $userRegistration = $user->getRegistration();
 -                      $defaultPreferences['registrationdate'] = [
 -                              'type' => 'info',
 -                              'label-message' => 'prefs-registration',
 -                              'default' => $context->msg(
 -                                      'prefs-registration-date-time',
 -                                      $lang->userTimeAndDate( $userRegistration, $displayUser ),
 -                                      $lang->userDate( $userRegistration, $displayUser ),
 -                                      $lang->userTime( $userRegistration, $displayUser )
 -                              )->parse(),
 -                              'section' => 'personal/info',
 -                      ];
 -              }
 -
 -              $canViewPrivateInfo = $user->isAllowed( 'viewmyprivateinfo' );
 -              $canEditPrivateInfo = $user->isAllowed( 'editmyprivateinfo' );
 -
 -              // Actually changeable stuff
 -              $defaultPreferences['realname'] = [
 -                      // (not really "private", but still shouldn't be edited without permission)
 -                      'type' => $canEditPrivateInfo && $authManager->allowsPropertyChange( 'realname' )
 -                              ? 'text' : 'info',
 -                      'default' => $user->getRealName(),
 -                      'section' => 'personal/info',
 -                      'label-message' => 'yourrealname',
 -                      'help-message' => 'prefs-help-realname',
 -              ];
 -
 -              if ( $canEditPrivateInfo && $authManager->allowsAuthenticationDataChange(
 -                      new PasswordAuthenticationRequest(), false )->isGood()
 -              ) {
 -                      $link = $linkRenderer->makeLink( SpecialPage::getTitleFor( 'ChangePassword' ),
 -                              $context->msg( 'prefs-resetpass' )->text(), [],
 -                              [ 'returnto' => SpecialPage::getTitleFor( 'Preferences' )->getPrefixedText() ] );
 -
 -                      $defaultPreferences['password'] = [
 -                              'type' => 'info',
 -                              'raw' => true,
 -                              'default' => $link,
 -                              'label-message' => 'yourpassword',
 -                              'section' => 'personal/info',
 -                      ];
 -              }
 -              // Only show prefershttps if secure login is turned on
 -              if ( $config->get( 'SecureLogin' ) && wfCanIPUseHTTPS( $context->getRequest()->getIP() ) ) {
 -                      $defaultPreferences['prefershttps'] = [
 -                              'type' => 'toggle',
 -                              'label-message' => 'tog-prefershttps',
 -                              'help-message' => 'prefs-help-prefershttps',
 -                              'section' => 'personal/info'
 -                      ];
 -              }
 -
 -              // Language
 -              $languages = Language::fetchLanguageNames( null, 'mw' );
 -              $languageCode = $config->get( 'LanguageCode' );
 -              if ( !array_key_exists( $languageCode, $languages ) ) {
 -                      $languages[$languageCode] = $languageCode;
 -              }
 -              ksort( $languages );
 -
 -              $options = [];
 -              foreach ( $languages as $code => $name ) {
 -                      $display = LanguageCode::bcp47( $code ) . ' - ' . $name;
 -                      $options[$display] = $code;
 -              }
 -              $defaultPreferences['language'] = [
 -                      'type' => 'select',
 -                      'section' => 'personal/i18n',
 -                      'options' => $options,
 -                      'label-message' => 'yourlanguage',
 -              ];
 -
 -              $defaultPreferences['gender'] = [
 -                      'type' => 'radio',
 -                      'section' => 'personal/i18n',
 -                      'options' => [
 -                              $context->msg( 'parentheses' )
 -                                      ->params( $context->msg( 'gender-unknown' )->plain() )
 -                                      ->escaped() => 'unknown',
 -                              $context->msg( 'gender-female' )->escaped() => 'female',
 -                              $context->msg( 'gender-male' )->escaped() => 'male',
 -                      ],
 -                      'label-message' => 'yourgender',
 -                      'help-message' => 'prefs-help-gender',
 -              ];
 -
 -              // see if there are multiple language variants to choose from
 -              if ( !$config->get( 'DisableLangConversion' ) ) {
 -                      foreach ( LanguageConverter::$languagesWithVariants as $langCode ) {
 -                              if ( $langCode == $wgContLang->getCode() ) {
 -                                      $variants = $wgContLang->getVariants();
 -
 -                                      if ( count( $variants ) <= 1 ) {
 -                                              continue;
 -                                      }
 -
 -                                      $variantArray = [];
 -                                      foreach ( $variants as $v ) {
 -                                              $v = str_replace( '_', '-', strtolower( $v ) );
 -                                              $variantArray[$v] = $lang->getVariantname( $v, false );
 -                                      }
 -
 -                                      $options = [];
 -                                      foreach ( $variantArray as $code => $name ) {
 -                                              $display = LanguageCode::bcp47( $code ) . ' - ' . $name;
 -                                              $options[$display] = $code;
 -                                      }
 -
 -                                      $defaultPreferences['variant'] = [
 -                                              'label-message' => 'yourvariant',
 -                                              'type' => 'select',
 -                                              'options' => $options,
 -                                              'section' => 'personal/i18n',
 -                                              'help-message' => 'prefs-help-variant',
 -                                      ];
 -                              } else {
 -                                      $defaultPreferences["variant-$langCode"] = [
 -                                              'type' => 'api',
 -                                      ];
 -                              }
 -                      }
 -              }
 -
 -              // Stuff from Language::getExtraUserToggles()
 -              // FIXME is this dead code? $extraUserToggles doesn't seem to be defined for any language
 -              $toggles = $wgContLang->getExtraUserToggles();
 -
 -              foreach ( $toggles as $toggle ) {
 -                      $defaultPreferences[$toggle] = [
 -                              'type' => 'toggle',
 -                              'section' => 'personal/i18n',
 -                              'label-message' => "tog-$toggle",
 -                      ];
 -              }
 -
 -              // show a preview of the old signature first
 -              $oldsigWikiText = $wgParser->preSaveTransform(
 -                      '~~~',
 -                      $context->getTitle(),
 -                      $user,
 -                      ParserOptions::newFromContext( $context )
 -              );
 -              $oldsigHTML = $context->getOutput()->parseInline( $oldsigWikiText, true, true );
 -              $defaultPreferences['oldsig'] = [
 -                      'type' => 'info',
 -                      'raw' => true,
 -                      'label-message' => 'tog-oldsig',
 -                      'default' => $oldsigHTML,
 -                      'section' => 'personal/signature',
 -              ];
 -              $defaultPreferences['nickname'] = [
 -                      'type' => $authManager->allowsPropertyChange( 'nickname' ) ? 'text' : 'info',
 -                      'maxlength' => $config->get( 'MaxSigChars' ),
 -                      'label-message' => 'yournick',
 -                      'validation-callback' => [ 'Preferences', 'validateSignature' ],
 -                      'section' => 'personal/signature',
 -                      'filter-callback' => [ 'Preferences', 'cleanSignature' ],
 -              ];
 -              $defaultPreferences['fancysig'] = [
 -                      'type' => 'toggle',
 -                      'label-message' => 'tog-fancysig',
 -                      // show general help about signature at the bottom of the section
 -                      'help-message' => 'prefs-help-signature',
 -                      'section' => 'personal/signature'
 -              ];
 -
 -              # # Email stuff
 -
 -              if ( $config->get( 'EnableEmail' ) ) {
 -                      if ( $canViewPrivateInfo ) {
 -                              $helpMessages[] = $config->get( 'EmailConfirmToEdit' )
 -                                              ? 'prefs-help-email-required'
 -                                              : 'prefs-help-email';
 -
 -                              if ( $config->get( 'EnableUserEmail' ) ) {
 -                                      // additional messages when users can send email to each other
 -                                      $helpMessages[] = 'prefs-help-email-others';
 -                              }
 -
 -                              $emailAddress = $user->getEmail() ? htmlspecialchars( $user->getEmail() ) : '';
 -                              if ( $canEditPrivateInfo && $authManager->allowsPropertyChange( 'emailaddress' ) ) {
 -                                      $link = $linkRenderer->makeLink(
 -                                              SpecialPage::getTitleFor( 'ChangeEmail' ),
 -                                              $context->msg( $user->getEmail() ? 'prefs-changeemail' : 'prefs-setemail' )->text(),
 -                                              [],
 -                                              [ 'returnto' => SpecialPage::getTitleFor( 'Preferences' )->getPrefixedText() ] );
 -
 -                                      $emailAddress .= $emailAddress == '' ? $link : (
 -                                              $context->msg( 'word-separator' )->escaped()
 -                                              . $context->msg( 'parentheses' )->rawParams( $link )->escaped()
 -                                      );
 -                              }
 -
 -                              $defaultPreferences['emailaddress'] = [
 -                                      'type' => 'info',
 -                                      'raw' => true,
 -                                      'default' => $emailAddress,
 -                                      'label-message' => 'youremail',
 -                                      'section' => 'personal/email',
 -                                      'help-messages' => $helpMessages,
 -                                      # 'cssclass' chosen below
 -                              ];
 -                      }
 -
 -                      $disableEmailPrefs = false;
 -
 -                      if ( $config->get( 'EmailAuthentication' ) ) {
 -                              $emailauthenticationclass = 'mw-email-not-authenticated';
 -                              if ( $user->getEmail() ) {
 -                                      if ( $user->getEmailAuthenticationTimestamp() ) {
 -                                              // date and time are separate parameters to facilitate localisation.
 -                                              // $time is kept for backward compat reasons.
 -                                              // 'emailauthenticated' is also used in SpecialConfirmemail.php
 -                                              $displayUser = $context->getUser();
 -                                              $emailTimestamp = $user->getEmailAuthenticationTimestamp();
 -                                              $time = $lang->userTimeAndDate( $emailTimestamp, $displayUser );
 -                                              $d = $lang->userDate( $emailTimestamp, $displayUser );
 -                                              $t = $lang->userTime( $emailTimestamp, $displayUser );
 -                                              $emailauthenticated = $context->msg( 'emailauthenticated',
 -                                                      $time, $d, $t )->parse() . '<br />';
 -                                              $disableEmailPrefs = false;
 -                                              $emailauthenticationclass = 'mw-email-authenticated';
 -                                      } else {
 -                                              $disableEmailPrefs = true;
 -                                              $emailauthenticated = $context->msg( 'emailnotauthenticated' )->parse() . '<br />' .
 -                                                      $linkRenderer->makeKnownLink(
 -                                                              SpecialPage::getTitleFor( 'Confirmemail' ),
 -                                                              $context->msg( 'emailconfirmlink' )->text()
 -                                                      ) . '<br />';
 -                                              $emailauthenticationclass = "mw-email-not-authenticated";
 -                                      }
 -                              } else {
 -                                      $disableEmailPrefs = true;
 -                                      $emailauthenticated = $context->msg( 'noemailprefs' )->escaped();
 -                                      $emailauthenticationclass = 'mw-email-none';
 -                              }
 -
 -                              if ( $canViewPrivateInfo ) {
 -                                      $defaultPreferences['emailauthentication'] = [
 -                                              'type' => 'info',
 -                                              'raw' => true,
 -                                              'section' => 'personal/email',
 -                                              'label-message' => 'prefs-emailconfirm-label',
 -                                              'default' => $emailauthenticated,
 -                                              # Apply the same CSS class used on the input to the message:
 -                                              'cssclass' => $emailauthenticationclass,
 -                                      ];
 -                              }
 -                      }
 -
 -                      if ( $config->get( 'EnableUserEmail' ) && $user->isAllowed( 'sendemail' ) ) {
 -                              $defaultPreferences['disablemail'] = [
 -                                      'id' => 'wpAllowEmail',
 -                                      'type' => 'toggle',
 -                                      'invert' => true,
 -                                      'section' => 'personal/email',
 -                                      'label-message' => 'allowemail',
 -                                      'disabled' => $disableEmailPrefs,
 -                              ];
 -
 -                              $defaultPreferences['email-allow-new-users'] = [
 -                                      'id' => 'wpAllowEmailFromNewUsers',
 -                                      'type' => 'toggle',
 -                                      'section' => 'personal/email',
 -                                      'label-message' => 'email-allow-new-users-label',
 -                                      'disabled' => $disableEmailPrefs,
 -                              ];
 -
 -                              $defaultPreferences['ccmeonemails'] = [
 -                                      'type' => 'toggle',
 -                                      'section' => 'personal/email',
 -                                      'label-message' => 'tog-ccmeonemails',
 -                                      'disabled' => $disableEmailPrefs,
 -                              ];
 -
 -                              if ( $config->get( 'EnableUserEmailBlacklist' ) ) {
 -                                      $lookup = CentralIdLookup::factory();
 -                                      $ids = $user->getOption( 'email-blacklist', [] );
 -                                      $names = $ids ? $lookup->namesFromCentralIds( $ids, $user ) : [];
 -
 -                                      $defaultPreferences['email-blacklist'] = [
 -                                              'type' => 'usersmultiselect',
 -                                              'label-message' => 'email-blacklist-label',
 -                                              'section' => 'personal/email',
 -                                              'default' => implode( "\n", $names ),
 -                                              'disabled' => $disableEmailPrefs,
 -                                      ];
 -                              }
 -                      }
 -
 -                      if ( $config->get( 'EnotifWatchlist' ) ) {
 -                              $defaultPreferences['enotifwatchlistpages'] = [
 -                                      'type' => 'toggle',
 -                                      'section' => 'personal/email',
 -                                      'label-message' => 'tog-enotifwatchlistpages',
 -                                      'disabled' => $disableEmailPrefs,
 -                              ];
 -                      }
 -                      if ( $config->get( 'EnotifUserTalk' ) ) {
 -                              $defaultPreferences['enotifusertalkpages'] = [
 -                                      'type' => 'toggle',
 -                                      'section' => 'personal/email',
 -                                      'label-message' => 'tog-enotifusertalkpages',
 -                                      'disabled' => $disableEmailPrefs,
 -                              ];
 -                      }
 -                      if ( $config->get( 'EnotifUserTalk' ) || $config->get( 'EnotifWatchlist' ) ) {
 -                              if ( $config->get( 'EnotifMinorEdits' ) ) {
 -                                      $defaultPreferences['enotifminoredits'] = [
 -                                              'type' => 'toggle',
 -                                              'section' => 'personal/email',
 -                                              'label-message' => 'tog-enotifminoredits',
 -                                              'disabled' => $disableEmailPrefs,
 -                                      ];
 -                              }
 -
 -                              if ( $config->get( 'EnotifRevealEditorAddress' ) ) {
 -                                      $defaultPreferences['enotifrevealaddr'] = [
 -                                              'type' => 'toggle',
 -                                              'section' => 'personal/email',
 -                                              'label-message' => 'tog-enotifrevealaddr',
 -                                              'disabled' => $disableEmailPrefs,
 -                                      ];
 -                              }
 -                      }
 -              }
 +      public static function profilePreferences(
 +              $user, IContextSource $context, &$defaultPreferences
 +      ) {
 +              wfDeprecated( __METHOD__, '1.31' );
 +              $defaultPreferences = self::getPreferences( $user, $context );
        }
  
        /**
         * @param array &$defaultPreferences
         * @return void
         */
 -      static function skinPreferences( $user, IContextSource $context, &$defaultPreferences ) {
 -              # # Skin #####################################
 -
 -              // Skin selector, if there is at least one valid skin
 -              $skinOptions = self::generateSkinOptions( $user, $context );
 -              if ( $skinOptions ) {
 -                      $defaultPreferences['skin'] = [
 -                              'type' => 'radio',
 -                              'options' => $skinOptions,
 -                              'section' => 'rendering/skin',
 -                      ];
 -              }
 -
 -              $config = $context->getConfig();
 -              $allowUserCss = $config->get( 'AllowUserCss' );
 -              $allowUserJs = $config->get( 'AllowUserJs' );
 -              # Create links to user CSS/JS pages for all skins
 -              # This code is basically copied from generateSkinOptions().  It'd
 -              # be nice to somehow merge this back in there to avoid redundancy.
 -              if ( $allowUserCss || $allowUserJs ) {
 -                      $linkTools = [];
 -                      $userName = $user->getName();
 -
 -                      $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
 -                      if ( $allowUserCss ) {
 -                              $cssPage = Title::makeTitleSafe( NS_USER, $userName . '/common.css' );
 -                              $linkTools[] = $linkRenderer->makeLink( $cssPage, $context->msg( 'prefs-custom-css' )->text() );
 -                      }
 -
 -                      if ( $allowUserJs ) {
 -                              $jsPage = Title::makeTitleSafe( NS_USER, $userName . '/common.js' );
 -                              $linkTools[] = $linkRenderer->makeLink( $jsPage, $context->msg( 'prefs-custom-js' )->text() );
 -                      }
 -
 -                      $defaultPreferences['commoncssjs'] = [
 -                              'type' => 'info',
 -                              'raw' => true,
 -                              'default' => $context->getLanguage()->pipeList( $linkTools ),
 -                              'label-message' => 'prefs-common-css-js',
 -                              'section' => 'rendering/skin',
 -                      ];
 -              }
 +      public static function skinPreferences( $user, IContextSource $context, &$defaultPreferences ) {
 +              wfDeprecated( __METHOD__, '1.31' );
 +              $defaultPreferences = self::getPreferences( $user, $context );
        }
  
        /**
         * @param IContextSource $context
         * @param array &$defaultPreferences
         */
 -      static function filesPreferences( $user, IContextSource $context, &$defaultPreferences ) {
 -              # # Files #####################################
 -              $defaultPreferences['imagesize'] = [
 -                      'type' => 'select',
 -                      'options' => self::getImageSizes( $context ),
 -                      'label-message' => 'imagemaxsize',
 -                      'section' => 'rendering/files',
 -              ];
 -              $defaultPreferences['thumbsize'] = [
 -                      'type' => 'select',
 -                      'options' => self::getThumbSizes( $context ),
 -                      'label-message' => 'thumbsize',
 -                      'section' => 'rendering/files',
 -              ];
 +      public static function filesPreferences(
 +              $user, IContextSource $context, &$defaultPreferences
 +      ) {
 +              wfDeprecated( __METHOD__, '1.31' );
 +              $defaultPreferences = self::getPreferences( $user, $context );
        }
  
        /**
         * @param array &$defaultPreferences
         * @return void
         */
 -      static function datetimePreferences( $user, IContextSource $context, &$defaultPreferences ) {
 -              # # Date and time #####################################
 -              $dateOptions = self::getDateOptions( $context );
 -              if ( $dateOptions ) {
 -                      $defaultPreferences['date'] = [
 -                              'type' => 'radio',
 -                              'options' => $dateOptions,
 -                              'section' => 'rendering/dateformat',
 -                      ];
 -              }
 -
 -              // Info
 -              $now = wfTimestampNow();
 -              $lang = $context->getLanguage();
 -              $nowlocal = Xml::element( 'span', [ 'id' => 'wpLocalTime' ],
 -                      $lang->userTime( $now, $user ) );
 -              $nowserver = $lang->userTime( $now, $user,
 -                              [ 'format' => false, 'timecorrection' => false ] ) .
 -                      Html::hidden( 'wpServerTime', (int)substr( $now, 8, 2 ) * 60 + (int)substr( $now, 10, 2 ) );
 -
 -              $defaultPreferences['nowserver'] = [
 -                      'type' => 'info',
 -                      'raw' => 1,
 -                      'label-message' => 'servertime',
 -                      'default' => $nowserver,
 -                      'section' => 'rendering/timeoffset',
 -              ];
 -
 -              $defaultPreferences['nowlocal'] = [
 -                      'type' => 'info',
 -                      'raw' => 1,
 -                      'label-message' => 'localtime',
 -                      'default' => $nowlocal,
 -                      'section' => 'rendering/timeoffset',
 -              ];
 -
 -              // Grab existing pref.
 -              $tzOffset = $user->getOption( 'timecorrection' );
 -              $tz = explode( '|', $tzOffset, 3 );
 -
 -              $tzOptions = self::getTimezoneOptions( $context );
 -
 -              $tzSetting = $tzOffset;
 -              if ( count( $tz ) > 1 && $tz[0] == 'ZoneInfo' &&
 -                      !in_array( $tzOffset, HTMLFormField::flattenOptions( $tzOptions ) )
 -              ) {
 -                      // Timezone offset can vary with DST
 -                      try {
 -                              $userTZ = new DateTimeZone( $tz[2] );
 -                              $minDiff = floor( $userTZ->getOffset( new DateTime( 'now' ) ) / 60 );
 -                              $tzSetting = "ZoneInfo|$minDiff|{$tz[2]}";
 -                      } catch ( Exception $e ) {
 -                              // User has an invalid time zone set. Fall back to just using the offset
 -                              $tz[0] = 'Offset';
 -                      }
 -              }
 -              if ( count( $tz ) > 1 && $tz[0] == 'Offset' ) {
 -                      $minDiff = $tz[1];
 -                      $tzSetting = sprintf( '%+03d:%02d', floor( $minDiff / 60 ), abs( $minDiff ) % 60 );
 -              }
 -
 -              $defaultPreferences['timecorrection'] = [
 -                      'class' => 'HTMLSelectOrOtherField',
 -                      'label-message' => 'timezonelegend',
 -                      'options' => $tzOptions,
 -                      'default' => $tzSetting,
 -                      'size' => 20,
 -                      'section' => 'rendering/timeoffset',
 -              ];
 +      public static function datetimePreferences(
 +              $user, IContextSource $context, &$defaultPreferences
 +      ) {
 +              wfDeprecated( __METHOD__, '1.31' );
 +              $defaultPreferences = self::getPreferences( $user, $context );
        }
  
        /**
         * @param IContextSource $context
         * @param array &$defaultPreferences
         */
 -      static function renderingPreferences( $user, IContextSource $context, &$defaultPreferences ) {
 -              # # Diffs ####################################
 -              $defaultPreferences['diffonly'] = [
 -                      'type' => 'toggle',
 -                      'section' => 'rendering/diffs',
 -                      'label-message' => 'tog-diffonly',
 -              ];
 -              $defaultPreferences['norollbackdiff'] = [
 -                      'type' => 'toggle',
 -                      'section' => 'rendering/diffs',
 -                      'label-message' => 'tog-norollbackdiff',
 -              ];
 -
 -              # # Page Rendering ##############################
 -              if ( $context->getConfig()->get( 'AllowUserCssPrefs' ) ) {
 -                      $defaultPreferences['underline'] = [
 -                              'type' => 'select',
 -                              'options' => [
 -                                      $context->msg( 'underline-never' )->text() => 0,
 -                                      $context->msg( 'underline-always' )->text() => 1,
 -                                      $context->msg( 'underline-default' )->text() => 2,
 -                              ],
 -                              'label-message' => 'tog-underline',
 -                              'section' => 'rendering/advancedrendering',
 -                      ];
 -              }
 -
 -              $stubThresholdValues = [ 50, 100, 500, 1000, 2000, 5000, 10000 ];
 -              $stubThresholdOptions = [ $context->msg( 'stub-threshold-disabled' )->text() => 0 ];
 -              foreach ( $stubThresholdValues as $value ) {
 -                      $stubThresholdOptions[$context->msg( 'size-bytes', $value )->text()] = $value;
 -              }
 -
 -              $defaultPreferences['stubthreshold'] = [
 -                      'type' => 'select',
 -                      'section' => 'rendering/advancedrendering',
 -                      'options' => $stubThresholdOptions,
 -                      // This is not a raw HTML message; label-raw is needed for the manual <a></a>
 -                      'label-raw' => $context->msg( 'stub-threshold' )->rawParams(
 -                              '<a href="#" class="stub">' .
 -                              $context->msg( 'stub-threshold-sample-link' )->parse() .
 -                              '</a>' )->parse(),
 -              ];
 -
 -              $defaultPreferences['showhiddencats'] = [
 -                      'type' => 'toggle',
 -                      'section' => 'rendering/advancedrendering',
 -                      'label-message' => 'tog-showhiddencats'
 -              ];
 -
 -              $defaultPreferences['numberheadings'] = [
 -                      'type' => 'toggle',
 -                      'section' => 'rendering/advancedrendering',
 -                      'label-message' => 'tog-numberheadings',
 -              ];
 +      public static function renderingPreferences(
 +              $user, IContextSource $context, &$defaultPreferences
 +      ) {
 +              wfDeprecated( __METHOD__, '1.31' );
 +              $defaultPreferences = self::getPreferences( $user, $context );
        }
  
        /**
         * @param IContextSource $context
         * @param array &$defaultPreferences
         */
 -      static function editingPreferences( $user, IContextSource $context, &$defaultPreferences ) {
 -              # # Editing #####################################
 -              $defaultPreferences['editsectiononrightclick'] = [
 -                      'type' => 'toggle',
 -                      'section' => 'editing/advancedediting',
 -                      'label-message' => 'tog-editsectiononrightclick',
 -              ];
 -              $defaultPreferences['editondblclick'] = [
 -                      'type' => 'toggle',
 -                      'section' => 'editing/advancedediting',
 -                      'label-message' => 'tog-editondblclick',
 -              ];
 -
 -              if ( $context->getConfig()->get( 'AllowUserCssPrefs' ) ) {
 -                      $defaultPreferences['editfont'] = [
 -                              'type' => 'select',
 -                              'section' => 'editing/editor',
 -                              'label-message' => 'editfont-style',
 -                              'options' => [
 -                                      $context->msg( 'editfont-monospace' )->text() => 'monospace',
 -                                      $context->msg( 'editfont-sansserif' )->text() => 'sans-serif',
 -                                      $context->msg( 'editfont-serif' )->text() => 'serif',
 -                              ]
 -                      ];
 -              }
 -
 -              if ( $user->isAllowed( 'minoredit' ) ) {
 -                      $defaultPreferences['minordefault'] = [
 -                              'type' => 'toggle',
 -                              'section' => 'editing/editor',
 -                              'label-message' => 'tog-minordefault',
 -                      ];
 -              }
 -
 -              $defaultPreferences['forceeditsummary'] = [
 -                      'type' => 'toggle',
 -                      'section' => 'editing/editor',
 -                      'label-message' => 'tog-forceeditsummary',
 -              ];
 -              $defaultPreferences['useeditwarning'] = [
 -                      'type' => 'toggle',
 -                      'section' => 'editing/editor',
 -                      'label-message' => 'tog-useeditwarning',
 -              ];
 -              $defaultPreferences['showtoolbar'] = [
 -                      'type' => 'toggle',
 -                      'section' => 'editing/editor',
 -                      'label-message' => 'tog-showtoolbar',
 -              ];
 -
 -              $defaultPreferences['previewonfirst'] = [
 -                      'type' => 'toggle',
 -                      'section' => 'editing/preview',
 -                      'label-message' => 'tog-previewonfirst',
 -              ];
 -              $defaultPreferences['previewontop'] = [
 -                      'type' => 'toggle',
 -                      'section' => 'editing/preview',
 -                      'label-message' => 'tog-previewontop',
 -              ];
 -              $defaultPreferences['uselivepreview'] = [
 -                      'type' => 'toggle',
 -                      'section' => 'editing/preview',
 -                      'label-message' => 'tog-uselivepreview',
 -              ];
 +      public static function editingPreferences(
 +              $user, IContextSource $context, &$defaultPreferences
 +      ) {
 +              wfDeprecated( __METHOD__, '1.31' );
 +              $defaultPreferences = self::getPreferences( $user, $context );
        }
  
        /**
         * @param IContextSource $context
         * @param array &$defaultPreferences
         */
 -      static function rcPreferences( $user, IContextSource $context, &$defaultPreferences ) {
 -              $config = $context->getConfig();
 -              $rcMaxAge = $config->get( 'RCMaxAge' );
 -              # # RecentChanges #####################################
 -              $defaultPreferences['rcdays'] = [
 -                      'type' => 'float',
 -                      'label-message' => 'recentchangesdays',
 -                      'section' => 'rc/displayrc',
 -                      'min' => 1,
 -                      'max' => ceil( $rcMaxAge / ( 3600 * 24 ) ),
 -                      'help' => $context->msg( 'recentchangesdays-max' )->numParams(
 -                              ceil( $rcMaxAge / ( 3600 * 24 ) ) )->escaped()
 -              ];
 -              $defaultPreferences['rclimit'] = [
 -                      'type' => 'int',
 -                      'min' => 0,
 -                      'max' => 1000,
 -                      'label-message' => 'recentchangescount',
 -                      'help-message' => 'prefs-help-recentchangescount',
 -                      'section' => 'rc/displayrc',
 -              ];
 -              $defaultPreferences['usenewrc'] = [
 -                      'type' => 'toggle',
 -                      'label-message' => 'tog-usenewrc',
 -                      'section' => 'rc/advancedrc',
 -              ];
 -              $defaultPreferences['hideminor'] = [
 -                      'type' => 'toggle',
 -                      'label-message' => 'tog-hideminor',
 -                      'section' => 'rc/advancedrc',
 -              ];
 -              $defaultPreferences['rcfilters-saved-queries'] = [
 -                      'type' => 'api',
 -              ];
 -              $defaultPreferences['rcfilters-wl-saved-queries'] = [
 -                      'type' => 'api',
 -              ];
 -              // Override RCFilters preferences for RecentChanges 'limit'
 -              $defaultPreferences['rcfilters-limit'] = [
 -                      'type' => 'api',
 -              ];
 -              $defaultPreferences['rcfilters-saved-queries-versionbackup'] = [
 -                      'type' => 'api',
 -              ];
 -              $defaultPreferences['rcfilters-wl-saved-queries-versionbackup'] = [
 -                      'type' => 'api',
 -              ];
 -              if ( $config->get( 'RCWatchCategoryMembership' ) ) {
 -                      $defaultPreferences['hidecategorization'] = [
 -                              'type' => 'toggle',
 -                              'label-message' => 'tog-hidecategorization',
 -                              'section' => 'rc/advancedrc',
 -                      ];
 -              }
 -
 -              if ( $user->useRCPatrol() ) {
 -                      $defaultPreferences['hidepatrolled'] = [
 -                              'type' => 'toggle',
 -                              'section' => 'rc/advancedrc',
 -                              'label-message' => 'tog-hidepatrolled',
 -                      ];
 -              }
 -
 -              if ( $user->useNPPatrol() ) {
 -                      $defaultPreferences['newpageshidepatrolled'] = [
 -                              'type' => 'toggle',
 -                              'section' => 'rc/advancedrc',
 -                              'label-message' => 'tog-newpageshidepatrolled',
 -                      ];
 -              }
 -
 -              if ( $config->get( 'RCShowWatchingUsers' ) ) {
 -                      $defaultPreferences['shownumberswatching'] = [
 -                              'type' => 'toggle',
 -                              'section' => 'rc/advancedrc',
 -                              'label-message' => 'tog-shownumberswatching',
 -                      ];
 -              }
 -
 -              if ( $config->get( 'StructuredChangeFiltersShowPreference' ) ) {
 -                      $defaultPreferences['rcenhancedfilters-disable'] = [
 -                              'type' => 'toggle',
 -                              'section' => 'rc/opt-out',
 -                              'label-message' => 'rcfilters-preference-label',
 -                              'help-message' => 'rcfilters-preference-help',
 -                      ];
 -              }
 +      public static function rcPreferences( $user, IContextSource $context, &$defaultPreferences ) {
 +              wfDeprecated( __METHOD__, '1.31' );
 +              $defaultPreferences = self::getPreferences( $user, $context );
        }
  
        /**
         * @param IContextSource $context
         * @param array &$defaultPreferences
         */
 -      static function watchlistPreferences( $user, IContextSource $context, &$defaultPreferences ) {
 -              $config = $context->getConfig();
 -              $watchlistdaysMax = ceil( $config->get( 'RCMaxAge' ) / ( 3600 * 24 ) );
 -
 -              # # Watchlist #####################################
 -              if ( $user->isAllowed( 'editmywatchlist' ) ) {
 -                      $editWatchlistLinks = [];
 -                      $editWatchlistModes = [
 -                              'edit' => [ 'EditWatchlist', false ],
 -                              'raw' => [ 'EditWatchlist', 'raw' ],
 -                              'clear' => [ 'EditWatchlist', 'clear' ],
 -                      ];
 -                      $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
 -                      foreach ( $editWatchlistModes as $editWatchlistMode => $mode ) {
 -                              // Messages: prefs-editwatchlist-edit, prefs-editwatchlist-raw, prefs-editwatchlist-clear
 -                              $editWatchlistLinks[] = $linkRenderer->makeKnownLink(
 -                                      SpecialPage::getTitleFor( $mode[0], $mode[1] ),
 -                                      new HtmlArmor( $context->msg( "prefs-editwatchlist-{$editWatchlistMode}" )->parse() )
 -                              );
 -                      }
 -
 -                      $defaultPreferences['editwatchlist'] = [
 -                              'type' => 'info',
 -                              'raw' => true,
 -                              'default' => $context->getLanguage()->pipeList( $editWatchlistLinks ),
 -                              'label-message' => 'prefs-editwatchlist-label',
 -                              'section' => 'watchlist/editwatchlist',
 -                      ];
 -              }
 -
 -              $defaultPreferences['watchlistdays'] = [
 -                      'type' => 'float',
 -                      'min' => 0,
 -                      'max' => $watchlistdaysMax,
 -                      'section' => 'watchlist/displaywatchlist',
 -                      'help' => $context->msg( 'prefs-watchlist-days-max' )->numParams(
 -                              $watchlistdaysMax )->escaped(),
 -                      'label-message' => 'prefs-watchlist-days',
 -              ];
 -              $defaultPreferences['wllimit'] = [
 -                      'type' => 'int',
 -                      'min' => 0,
 -                      'max' => 1000,
 -                      'label-message' => 'prefs-watchlist-edits',
 -                      'help' => $context->msg( 'prefs-watchlist-edits-max' )->escaped(),
 -                      'section' => 'watchlist/displaywatchlist',
 -              ];
 -              $defaultPreferences['extendwatchlist'] = [
 -                      'type' => 'toggle',
 -                      'section' => 'watchlist/advancedwatchlist',
 -                      'label-message' => 'tog-extendwatchlist',
 -              ];
 -              $defaultPreferences['watchlisthideminor'] = [
 -                      'type' => 'toggle',
 -                      'section' => 'watchlist/advancedwatchlist',
 -                      'label-message' => 'tog-watchlisthideminor',
 -              ];
 -              $defaultPreferences['watchlisthidebots'] = [
 -                      'type' => 'toggle',
 -                      'section' => 'watchlist/advancedwatchlist',
 -                      'label-message' => 'tog-watchlisthidebots',
 -              ];
 -              $defaultPreferences['watchlisthideown'] = [
 -                      'type' => 'toggle',
 -                      'section' => 'watchlist/advancedwatchlist',
 -                      'label-message' => 'tog-watchlisthideown',
 -              ];
 -              $defaultPreferences['watchlisthideanons'] = [
 -                      'type' => 'toggle',
 -                      'section' => 'watchlist/advancedwatchlist',
 -                      'label-message' => 'tog-watchlisthideanons',
 -              ];
 -              $defaultPreferences['watchlisthideliu'] = [
 -                      'type' => 'toggle',
 -                      'section' => 'watchlist/advancedwatchlist',
 -                      'label-message' => 'tog-watchlisthideliu',
 -              ];
 -              $defaultPreferences['watchlistreloadautomatically'] = [
 -                      'type' => 'toggle',
 -                      'section' => 'watchlist/advancedwatchlist',
 -                      'label-message' => 'tog-watchlistreloadautomatically',
 -              ];
 -              $defaultPreferences['watchlistunwatchlinks'] = [
 -                      'type' => 'toggle',
 -                      'section' => 'watchlist/advancedwatchlist',
 -                      'label-message' => 'tog-watchlistunwatchlinks',
 -              ];
 -
 -              if ( $config->get( 'RCWatchCategoryMembership' ) ) {
 -                      $defaultPreferences['watchlisthidecategorization'] = [
 -                              'type' => 'toggle',
 -                              'section' => 'watchlist/advancedwatchlist',
 -                              'label-message' => 'tog-watchlisthidecategorization',
 -                      ];
 -              }
 -
 -              if ( $user->useRCPatrol() ) {
 -                      $defaultPreferences['watchlisthidepatrolled'] = [
 -                              'type' => 'toggle',
 -                              'section' => 'watchlist/advancedwatchlist',
 -                              'label-message' => 'tog-watchlisthidepatrolled',
 -                      ];
 -              }
 -
 -              $watchTypes = [
 -                      'edit' => 'watchdefault',
 -                      'move' => 'watchmoves',
 -                      'delete' => 'watchdeletion'
 -              ];
 -
 -              // Kinda hacky
 -              if ( $user->isAllowed( 'createpage' ) || $user->isAllowed( 'createtalk' ) ) {
 -                      $watchTypes['read'] = 'watchcreations';
 -              }
 -
 -              if ( $user->isAllowed( 'rollback' ) ) {
 -                      $watchTypes['rollback'] = 'watchrollback';
 -              }
 -
 -              if ( $user->isAllowed( 'upload' ) ) {
 -                      $watchTypes['upload'] = 'watchuploads';
 -              }
 -
 -              foreach ( $watchTypes as $action => $pref ) {
 -                      if ( $user->isAllowed( $action ) ) {
 -                              // Messages:
 -                              // tog-watchdefault, tog-watchmoves, tog-watchdeletion, tog-watchcreations, tog-watchuploads
 -                              // tog-watchrollback
 -                              $defaultPreferences[$pref] = [
 -                                      'type' => 'toggle',
 -                                      'section' => 'watchlist/advancedwatchlist',
 -                                      'label-message' => "tog-$pref",
 -                              ];
 -                      }
 -              }
 -
 -              if ( $config->get( 'EnableAPI' ) ) {
 -                      $defaultPreferences['watchlisttoken'] = [
 -                              'type' => 'api',
 -                      ];
 -                      $defaultPreferences['watchlisttoken-info'] = [
 -                              'type' => 'info',
 -                              'section' => 'watchlist/tokenwatchlist',
 -                              'label-message' => 'prefs-watchlist-token',
 -                              'default' => $user->getTokenFromOption( 'watchlisttoken' ),
 -                              'help-message' => 'prefs-help-watchlist-token2',
 -                      ];
 -              }
 +      public static function watchlistPreferences(
 +              $user, IContextSource $context, &$defaultPreferences
 +      ) {
 +              wfDeprecated( __METHOD__, '1.31' );
 +              $defaultPreferences = self::getPreferences( $user, $context );
        }
  
        /**
         * @param IContextSource $context
         * @param array &$defaultPreferences
         */
 -      static function searchPreferences( $user, IContextSource $context, &$defaultPreferences ) {
 -              foreach ( MWNamespace::getValidNamespaces() as $n ) {
 -                      $defaultPreferences['searchNs' . $n] = [
 -                              'type' => 'api',
 -                      ];
 -              }
 +      public static function searchPreferences(
 +              $user, IContextSource $context, &$defaultPreferences
 +      ) {
 +              wfDeprecated( __METHOD__, '1.31' );
 +              $defaultPreferences = self::getPreferences( $user, $context );
        }
  
        /**
         * @param IContextSource $context
         * @param array &$defaultPreferences
         */
 -      static function miscPreferences( $user, IContextSource $context, &$defaultPreferences ) {
 +      public static function miscPreferences( $user, IContextSource $context, &$defaultPreferences ) {
        }
  
        /**
-        * @param User $user The User object
+        * @param User $user
         * @param IContextSource $context
         * @return array Text/links to display as key; $skinkey as value
         */
 -      static function generateSkinOptions( $user, IContextSource $context ) {
 -              $ret = [];
 -
 -              $mptitle = Title::newMainPage();
 -              $previewtext = $context->msg( 'skin-preview' )->escaped();
 -
 -              $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
 -
 -              # Only show skins that aren't disabled in $wgSkipSkins
 -              $validSkinNames = Skin::getAllowedSkins();
 -
 -              foreach ( $validSkinNames as $skinkey => &$skinname ) {
 -                      $msg = $context->msg( "skinname-{$skinkey}" );
 -                      if ( $msg->exists() ) {
 -                              $skinname = htmlspecialchars( $msg->text() );
 -                      }
 -              }
 -
 -              $config = $context->getConfig();
 -              $defaultSkin = $config->get( 'DefaultSkin' );
 -              $allowUserCss = $config->get( 'AllowUserCss' );
 -              $allowUserJs = $config->get( 'AllowUserJs' );
 -
 -              # Sort by the internal name, so that the ordering is the same for each display language,
 -              # especially if some skin names are translated to use a different alphabet and some are not.
 -              uksort( $validSkinNames, function ( $a, $b ) use ( $defaultSkin ) {
 -                      # Display the default first in the list by comparing it as lesser than any other.
 -                      if ( strcasecmp( $a, $defaultSkin ) === 0 ) {
 -                              return -1;
 -                      }
 -                      if ( strcasecmp( $b, $defaultSkin ) === 0 ) {
 -                              return 1;
 -                      }
 -                      return strcasecmp( $a, $b );
 -              } );
 -
 -              $foundDefault = false;
 -              foreach ( $validSkinNames as $skinkey => $sn ) {
 -                      $linkTools = [];
 -
 -                      # Mark the default skin
 -                      if ( strcasecmp( $skinkey, $defaultSkin ) === 0 ) {
 -                              $linkTools[] = $context->msg( 'default' )->escaped();
 -                              $foundDefault = true;
 -                      }
 -
 -                      # Create preview link
 -                      $mplink = htmlspecialchars( $mptitle->getLocalURL( [ 'useskin' => $skinkey ] ) );
 -                      $linkTools[] = "<a target='_blank' href=\"$mplink\">$previewtext</a>";
 -
 -                      # Create links to user CSS/JS pages
 -                      if ( $allowUserCss ) {
 -                              $cssPage = Title::makeTitleSafe( NS_USER, $user->getName() . '/' . $skinkey . '.css' );
 -                              $linkTools[] = $linkRenderer->makeLink( $cssPage, $context->msg( 'prefs-custom-css' )->text() );
 -                      }
 -
 -                      if ( $allowUserJs ) {
 -                              $jsPage = Title::makeTitleSafe( NS_USER, $user->getName() . '/' . $skinkey . '.js' );
 -                              $linkTools[] = $linkRenderer->makeLink( $jsPage, $context->msg( 'prefs-custom-js' )->text() );
 -                      }
 -
 -                      $display = $sn . ' ' . $context->msg( 'parentheses' )
 -                              ->rawParams( $context->getLanguage()->pipeList( $linkTools ) )
 -                              ->escaped();
 -                      $ret[$display] = $skinkey;
 -              }
 -
 -              if ( !$foundDefault ) {
 -                      // If the default skin is not available, things are going to break horribly because the
 -                      // default value for skin selector will not be a valid value. Let's just not show it then.
 -                      return [];
 -              }
 -
 -              return $ret;
 +      public static function generateSkinOptions( $user, IContextSource $context ) {
 +              wfDeprecated( __METHOD__, '1.31' );
 +              return self::getPreferences( $user, $context );
        }
  
        /**
         * @return array
         */
        static function getDateOptions( IContextSource $context ) {
 -              $lang = $context->getLanguage();
 -              $dateopts = $lang->getDatePreferences();
 -
 -              $ret = [];
 -
 -              if ( $dateopts ) {
 -                      if ( !in_array( 'default', $dateopts ) ) {
 -                              $dateopts[] = 'default'; // Make sure default is always valid T21237
 -                      }
 -
 -                      // FIXME KLUGE: site default might not be valid for user language
 -                      global $wgDefaultUserOptions;
 -                      if ( !in_array( $wgDefaultUserOptions['date'], $dateopts ) ) {
 -                              $wgDefaultUserOptions['date'] = 'default';
 -                      }
 -
 -                      $epoch = wfTimestampNow();
 -                      foreach ( $dateopts as $key ) {
 -                              if ( $key == 'default' ) {
 -                                      $formatted = $context->msg( 'datedefault' )->escaped();
 -                              } else {
 -                                      $formatted = htmlspecialchars( $lang->timeanddate( $epoch, false, $key ) );
 -                              }
 -                              $ret[$formatted] = $key;
 -                      }
 -              }
 -              return $ret;
 +              throw new Exception( __METHOD__ . '() is deprecated and does nothing' );
        }
  
        /**
         * @param IContextSource $context
         * @return array
         */
 -      static function getImageSizes( IContextSource $context ) {
 -              $ret = [];
 -              $pixels = $context->msg( 'unit-pixel' )->text();
 -
 -              foreach ( $context->getConfig()->get( 'ImageLimits' ) as $index => $limits ) {
 -                      // Note: A left-to-right marker (\u200e) is inserted, see T144386
 -                      $display = "{$limits[0]}" . json_decode( '"\u200e"' ) . "×{$limits[1]}" . $pixels;
 -                      $ret[$display] = $index;
 -              }
 -
 -              return $ret;
 +      public static function getImageSizes( IContextSource $context ) {
 +              throw new Exception( __METHOD__ . '() is deprecated and does nothing' );
        }
  
        /**
         * @param IContextSource $context
         * @return array
         */
 -      static function getThumbSizes( IContextSource $context ) {
 -              $ret = [];
 -              $pixels = $context->msg( 'unit-pixel' )->text();
 -
 -              foreach ( $context->getConfig()->get( 'ThumbLimits' ) as $index => $size ) {
 -                      $display = $size . $pixels;
 -                      $ret[$display] = $index;
 -              }
 -
 -              return $ret;
 +      public static function getThumbSizes( IContextSource $context ) {
 +              throw new Exception( __METHOD__ . '() is deprecated and does nothing' );
        }
  
        /**
         * @param HTMLForm $form
         * @return bool|string
         */
 -      static function validateSignature( $signature, $alldata, $form ) {
 -              global $wgParser;
 -              $maxSigChars = $form->getConfig()->get( 'MaxSigChars' );
 -              if ( mb_strlen( $signature ) > $maxSigChars ) {
 -                      return Xml::element( 'span', [ 'class' => 'error' ],
 -                              $form->msg( 'badsiglength' )->numParams( $maxSigChars )->text() );
 -              } elseif ( isset( $alldata['fancysig'] ) &&
 -                              $alldata['fancysig'] &&
 -                              $wgParser->validateSig( $signature ) === false
 -              ) {
 -                      return Xml::element(
 -                              'span',
 -                              [ 'class' => 'error' ],
 -                              $form->msg( 'badsig' )->text()
 -                      );
 -              } else {
 -                      return true;
 -              }
 +      public static function validateSignature( $signature, $alldata, $form ) {
 +              throw new Exception( __METHOD__ . '() is deprecated and does nothing' );
        }
  
        /**
         * @param HTMLForm $form
         * @return string
         */
 -      static function cleanSignature( $signature, $alldata, $form ) {
 -              if ( isset( $alldata['fancysig'] ) && $alldata['fancysig'] ) {
 -                      global $wgParser;
 -                      $signature = $wgParser->cleanSig( $signature );
 -              } else {
 -                      // When no fancy sig used, make sure ~{3,5} get removed.
 -                      $signature = Parser::cleanSigInSig( $signature );
 -              }
 -
 -              return $signature;
 +      public static function cleanSignature( $signature, $alldata, $form ) {
 +              throw new Exception( __METHOD__ . '() is deprecated and does nothing now' );
        }
  
        /**
         * @param array $remove Array of items to remove
         * @return PreferencesForm|HTMLForm
         */
 -      static function getFormObject(
 +      public static function getFormObject(
                $user,
                IContextSource $context,
                $formClass = 'PreferencesForm',
                array $remove = []
        ) {
 -              $formDescriptor = self::getPreferences( $user, $context );
 -              if ( count( $remove ) ) {
 -                      $removeKeys = array_flip( $remove );
 -                      $formDescriptor = array_diff_key( $formDescriptor, $removeKeys );
 -              }
 -
 -              // Remove type=api preferences. They are not intended for rendering in the form.
 -              foreach ( $formDescriptor as $name => $info ) {
 -                      if ( isset( $info['type'] ) && $info['type'] === 'api' ) {
 -                              unset( $formDescriptor[$name] );
 -                      }
 -              }
 -
 -              /**
 -               * @var $htmlForm PreferencesForm
 -               */
 -              $htmlForm = new $formClass( $formDescriptor, $context, 'prefs' );
 -
 -              $htmlForm->setModifiedUser( $user );
 -              $htmlForm->setId( 'mw-prefs-form' );
 -              $htmlForm->setAutocomplete( 'off' );
 -              $htmlForm->setSubmitText( $context->msg( 'saveprefs' )->text() );
 -              # Used message keys: 'accesskey-preferences-save', 'tooltip-preferences-save'
 -              $htmlForm->setSubmitTooltip( 'preferences-save' );
 -              $htmlForm->setSubmitID( 'prefcontrol' );
 -              $htmlForm->setSubmitCallback( [ 'Preferences', 'tryFormSubmit' ] );
 -
 -              return $htmlForm;
 +              $preferencesFactory = self::getDefaultPreferencesFactory();
 +              return $preferencesFactory->getForm( $user, $context, $formClass, $remove );
        }
  
        /**
         * @param IContextSource $context
         * @return array
         */
 -      static function getTimezoneOptions( IContextSource $context ) {
 -              $opt = [];
 -
 -              $localTZoffset = $context->getConfig()->get( 'LocalTZoffset' );
 -              $timeZoneList = self::getTimeZoneList( $context->getLanguage() );
 -
 -              $timestamp = MWTimestamp::getLocalInstance();
 -              // Check that the LocalTZoffset is the same as the local time zone offset
 -              if ( $localTZoffset == $timestamp->format( 'Z' ) / 60 ) {
 -                      $timezoneName = $timestamp->getTimezone()->getName();
 -                      // Localize timezone
 -                      if ( isset( $timeZoneList[$timezoneName] ) ) {
 -                              $timezoneName = $timeZoneList[$timezoneName]['name'];
 -                      }
 -                      $server_tz_msg = $context->msg(
 -                              'timezoneuseserverdefault',
 -                              $timezoneName
 -                      )->text();
 -              } else {
 -                      $tzstring = sprintf(
 -                              '%+03d:%02d',
 -                              floor( $localTZoffset / 60 ),
 -                              abs( $localTZoffset ) % 60
 -                      );
 -                      $server_tz_msg = $context->msg( 'timezoneuseserverdefault', $tzstring )->text();
 -              }
 -              $opt[$server_tz_msg] = "System|$localTZoffset";
 -              $opt[$context->msg( 'timezoneuseoffset' )->text()] = 'other';
 -              $opt[$context->msg( 'guesstimezone' )->text()] = 'guess';
 -
 -              foreach ( $timeZoneList as $timeZoneInfo ) {
 -                      $region = $timeZoneInfo['region'];
 -                      if ( !isset( $opt[$region] ) ) {
 -                              $opt[$region] = [];
 -                      }
 -                      $opt[$region][$timeZoneInfo['name']] = $timeZoneInfo['timecorrection'];
 -              }
 -              return $opt;
 +      public static function getTimezoneOptions( IContextSource $context ) {
 +              throw new Exception( __METHOD__ . '() is deprecated and does nothing' );
        }
  
        /**
         * @param array $alldata
         * @return int
         */
 -      static function filterIntval( $value, $alldata ) {
 -              return intval( $value );
 +      public static function filterIntval( $value, $alldata ) {
 +              throw new Exception( __METHOD__ . '() is deprecated and does nothing' );
        }
  
        /**
         * @param array $alldata
         * @return string
         */
 -      static function filterTimezoneInput( $tz, $alldata ) {
 -              $data = explode( '|', $tz, 3 );
 -              switch ( $data[0] ) {
 -                      case 'ZoneInfo':
 -                              $valid = false;
 -
 -                              if ( count( $data ) === 3 ) {
 -                                      // Make sure this timezone exists
 -                                      try {
 -                                              new DateTimeZone( $data[2] );
 -                                              // If the constructor didn't throw, we know it's valid
 -                                              $valid = true;
 -                                      } catch ( Exception $e ) {
 -                                              // Not a valid timezone
 -                                      }
 -                              }
 -
 -                              if ( !$valid ) {
 -                                      // If the supplied timezone doesn't exist, fall back to the encoded offset
 -                                      return 'Offset|' . intval( $tz[1] );
 -                              }
 -                              return $tz;
 -                      case 'System':
 -                              return $tz;
 -                      default:
 -                              $data = explode( ':', $tz, 2 );
 -                              if ( count( $data ) == 2 ) {
 -                                      $data[0] = intval( $data[0] );
 -                                      $data[1] = intval( $data[1] );
 -                                      $minDiff = abs( $data[0] ) * 60 + $data[1];
 -                                      if ( $data[0] < 0 ) {
 -                                              $minDiff = - $minDiff;
 -                                      }
 -                              } else {
 -                                      $minDiff = intval( $data[0] ) * 60;
 -                              }
 -
 -                              # Max is +14:00 and min is -12:00, see:
 -                              # https://en.wikipedia.org/wiki/Timezone
 -                              $minDiff = min( $minDiff, 840 );  # 14:00
 -                              $minDiff = max( $minDiff, -720 ); # -12:00
 -                              return 'Offset|' . $minDiff;
 -              }
 +      public static function filterTimezoneInput( $tz, $alldata ) {
 +              throw new Exception( __METHOD__ . '() is deprecated and does nothing' );
        }
  
        /**
         * @param PreferencesForm $form
         * @return bool|Status|string
         */
 -      static function tryFormSubmit( $formData, $form ) {
 -              $user = $form->getModifiedUser();
 -              $hiddenPrefs = $form->getConfig()->get( 'HiddenPrefs' );
 -              $result = true;
 -
 -              if ( !$user->isAllowedAny( 'editmyprivateinfo', 'editmyoptions' ) ) {
 -                      return Status::newFatal( 'mypreferencesprotected' );
 -              }
 -
 -              // Filter input
 -              foreach ( array_keys( $formData ) as $name ) {
 -                      if ( isset( self::$saveFilters[$name] ) ) {
 -                              $formData[$name] =
 -                                      call_user_func( self::$saveFilters[$name], $formData[$name], $formData );
 -                      }
 -              }
 -
 -              // Fortunately, the realname field is MUCH simpler
 -              // (not really "private", but still shouldn't be edited without permission)
 -
 -              if ( !in_array( 'realname', $hiddenPrefs )
 -                      && $user->isAllowed( 'editmyprivateinfo' )
 -                      && array_key_exists( 'realname', $formData )
 -              ) {
 -                      $realName = $formData['realname'];
 -                      $user->setRealName( $realName );
 -              }
 -
 -              if ( $user->isAllowed( 'editmyoptions' ) ) {
 -                      $oldUserOptions = $user->getOptions();
 -
 -                      foreach ( self::$saveBlacklist as $b ) {
 -                              unset( $formData[$b] );
 -                      }
 -
 -                      # If users have saved a value for a preference which has subsequently been disabled
 -                      # via $wgHiddenPrefs, we don't want to destroy that setting in case the preference
 -                      # is subsequently re-enabled
 -                      foreach ( $hiddenPrefs as $pref ) {
 -                              # If the user has not set a non-default value here, the default will be returned
 -                              # and subsequently discarded
 -                              $formData[$pref] = $user->getOption( $pref, null, true );
 -                      }
 -
 -                      // If the user changed the rclimit preference, also change the rcfilters-rclimit preference
 -                      if (
 -                              isset( $formData['rclimit'] ) &&
 -                              intval( $formData[ 'rclimit' ] ) !== $user->getIntOption( 'rclimit' )
 -                      ) {
 -                              $formData['rcfilters-limit'] = $formData['rclimit'];
 -                      }
 -
 -                      // Keep old preferences from interfering due to back-compat code, etc.
 -                      $user->resetOptions( 'unused', $form->getContext() );
 -
 -                      foreach ( $formData as $key => $value ) {
 -                              $user->setOption( $key, $value );
 -                      }
 -
 -                      Hooks::run(
 -                              'PreferencesFormPreSave',
 -                              [ $formData, $form, $user, &$result, $oldUserOptions ]
 -                      );
 -              }
 -
 -              MediaWiki\Auth\AuthManager::callLegacyAuthPlugin( 'updateExternalDB', [ $user ] );
 -              $user->saveSettings();
 -
 -              return $result;
 +      public static function tryFormSubmit( $formData, $form ) {
 +              $preferencesFactory = self::getDefaultPreferencesFactory();
 +              return $preferencesFactory->legacySaveFormData( $formData, $form );
        }
  
        /**
         * @return Status
         */
        public static function tryUISubmit( $formData, $form ) {
 -              $res = self::tryFormSubmit( $formData, $form );
 -
 -              if ( $res ) {
 -                      $urlOptions = [];
 -
 -                      if ( $res === 'eauth' ) {
 -                              $urlOptions['eauth'] = 1;
 -                      }
 -
 -                      $urlOptions += $form->getExtraSuccessRedirectParameters();
 -
 -                      $url = $form->getTitle()->getFullURL( $urlOptions );
 -
 -                      $context = $form->getContext();
 -                      // Set session data for the success message
 -                      $context->getRequest()->getSession()->set( 'specialPreferencesSaveSuccess', 1 );
 -
 -                      $context->getOutput()->redirect( $url );
 -              }
 -
 -              return Status::newGood();
 +              $preferencesFactory = self::getDefaultPreferencesFactory();
 +              return $preferencesFactory->legacySubmitForm( $formData, $form );
        }
  
        /**
         * @since 1.26
         */
        public static function getTimeZoneList( Language $language ) {
 -              $identifiers = DateTimeZone::listIdentifiers();
 -              if ( $identifiers === false ) {
 -                      return [];
 -              }
 -              sort( $identifiers );
 -
 -              $tzRegions = [
 -                      'Africa' => wfMessage( 'timezoneregion-africa' )->inLanguage( $language )->text(),
 -                      'America' => wfMessage( 'timezoneregion-america' )->inLanguage( $language )->text(),
 -                      'Antarctica' => wfMessage( 'timezoneregion-antarctica' )->inLanguage( $language )->text(),
 -                      'Arctic' => wfMessage( 'timezoneregion-arctic' )->inLanguage( $language )->text(),
 -                      'Asia' => wfMessage( 'timezoneregion-asia' )->inLanguage( $language )->text(),
 -                      'Atlantic' => wfMessage( 'timezoneregion-atlantic' )->inLanguage( $language )->text(),
 -                      'Australia' => wfMessage( 'timezoneregion-australia' )->inLanguage( $language )->text(),
 -                      'Europe' => wfMessage( 'timezoneregion-europe' )->inLanguage( $language )->text(),
 -                      'Indian' => wfMessage( 'timezoneregion-indian' )->inLanguage( $language )->text(),
 -                      'Pacific' => wfMessage( 'timezoneregion-pacific' )->inLanguage( $language )->text(),
 -              ];
 -              asort( $tzRegions );
 -
 -              $timeZoneList = [];
 -
 -              $now = new DateTime();
 -
 -              foreach ( $identifiers as $identifier ) {
 -                      $parts = explode( '/', $identifier, 2 );
 -
 -                      // DateTimeZone::listIdentifiers() returns a number of
 -                      // backwards-compatibility entries. This filters them out of the
 -                      // list presented to the user.
 -                      if ( count( $parts ) !== 2 || !array_key_exists( $parts[0], $tzRegions ) ) {
 -                              continue;
 -                      }
 -
 -                      // Localize region
 -                      $parts[0] = $tzRegions[$parts[0]];
 -
 -                      $dateTimeZone = new DateTimeZone( $identifier );
 -                      $minDiff = floor( $dateTimeZone->getOffset( $now ) / 60 );
 -
 -                      $display = str_replace( '_', ' ', $parts[0] . '/' . $parts[1] );
 -                      $value = "ZoneInfo|$minDiff|$identifier";
 -
 -                      $timeZoneList[$identifier] = [
 -                              'name' => $display,
 -                              'timecorrection' => $value,
 -                              'region' => $parts[0],
 -                      ];
 -              }
 -
 -              return $timeZoneList;
 +              throw new Exception( __METHOD__ . '() is deprecated and does nothing' );
        }
  }
diff --combined includes/Xml.php
@@@ -160,8 -160,9 +160,9 @@@ class Xml 
        }
  
        /**
-        * @param int $year
-        * @param int $month
+        * @param int|string $year Use '' or 0 to start with no year preselected.
+        * @param int|string $month A month in the 1..12 range. Use '', 0 or -1 to start with no month
+        *  preselected.
         * @return string Formatted HTML
         */
        public static function dateMenu( $year, $month ) {
         *
         * @param string $list Correctly formatted text (newline delimited) to be
         *   used to generate the options.
 -       * @param array $params Extra parameters
 -       * @param string $params['other'] If set, add an option with this as text and a value of 'other'
 +       * @param array $params Extra parameters:
 +       *   - string $params['other'] If set, add an option with this as text and a value of 'other'
         * @return array Array keys are textual labels, values are internal values
         */
        public static function listDropDownOptions( $list, $params = [] ) {
@@@ -186,7 -186,7 +186,7 @@@ class InfoAction extends FormlessActio
         * Adds a table to the content that will be added to the output.
         *
         * @param string $content The content that will be added to the output
-        * @param string $table The table
+        * @param string $table
         * @return string The content with the table added
         */
        protected function addTable( $content, $table ) {
                        ];
                }
  
 +              // Display image SHA-1 value
 +              if ( $title->inNamespace( NS_FILE ) ) {
 +                      $fileObj = wfFindFile( $title );
 +                      if ( $fileObj !== false ) {
 +                              $output = $fileObj->getSha1();
 +                              $pageInfo['header-basic'][] = [
 +                                      $this->msg( 'pageinfo-file-hash' ),
 +                                      $output
 +                              ];
 +                      }
 +              }
 +
                // Page protection
                $pageInfo['header-restrictions'] = [];
  
diff --combined includes/api/ApiBase.php
@@@ -155,7 -155,6 +155,7 @@@ abstract class ApiBase extends ContextS
         * ((string|array|Message)[]) When PARAM_TYPE is an array, this is an array
         * mapping those values to $msg for ApiBase::makeMessage(). Any value not
         * having a mapping will use apihelp-{$path}-paramvalue-{$param}-{$value}.
 +       * Specify an empty array to use the default message key for all values.
         * @since 1.25
         */
        const PARAM_HELP_MSG_PER_VALUE = 14;
         * @param string $paramName Parameter name
         * @param array|mixed $paramSettings Default value or an array of settings
         *  using PARAM_* constants.
-        * @param bool $parseLimit Parse limit?
+        * @param bool $parseLimit Whether to parse and validate 'limit' parameters
         * @return mixed Parameter value
         */
        protected function getParameterFromSettings( $paramName, $paramSettings, $parseLimit ) {
@@@ -34,6 -34,7 +34,6 @@@ class DependencyWrapper 
        private $deps;
  
        /**
 -       * Create an instance.
         * @param mixed $value The user-supplied value
         * @param CacheDependency|CacheDependency[] $deps A dependency or dependency
         *   array. All dependencies must be objects implementing CacheDependency.
@@@ -98,7 -99,7 +98,7 @@@
         * it will be generated with the callback function (if present), and the newly
         * calculated value will be stored to the cache in a wrapper.
         *
-        * @param BagOStuff $cache A cache object
+        * @param BagOStuff $cache
         * @param string $key The cache key
         * @param int $expiry The expiry timestamp or interval in seconds
         * @param bool|callable $callback The callback for generating the value, or false
@@@ -1,5 -1,5 +1,5 @@@
  <?php
 -// @codingStandardsIgnoreFile It's an external lib and it isn't. Let's not bother.
 +// phpcs:ignoreFile -- It's an external lib and it isn't. Let's not bother.
  /**
   * Memcached client for PHP.
   *
@@@ -363,7 -363,7 +363,7 @@@ class MemcachedClient 
        /**
         * Changes the TTL on a key from the server to $time
         *
-        * @param string $key Key
+        * @param string $key
         * @param int $time TTL in seconds
         *
         * @return bool True on success, false on failure
@@@ -96,9 -96,10 +96,9 @@@ class Parser 
        # at least one character of a host name (embeds EXT_LINK_URL_CLASS)
        const EXT_LINK_ADDR = '(?:[0-9.]+|\\[(?i:[0-9a-f:.]+)\\]|[^][<>"\\x00-\\x20\\x7F\p{Zs}\x{FFFD}])';
        # RegExp to make image URLs (embeds IPv6 part of EXT_LINK_ADDR)
 -      // @codingStandardsIgnoreStart Generic.Files.LineLength
 +      // phpcs:ignore Generic.Files.LineLength
        const EXT_IMAGE_REGEX = '/^(http:\/\/|https:\/\/)((?:\\[(?i:[0-9a-f:.]+)\\])?[^][<>"\\x00-\\x20\\x7F\p{Zs}\x{FFFD}]+)
                \\/([A-Za-z0-9_.,~%\\-+&;#*?!=()@\\x80-\\xFF]+)\\.((?i)gif|png|jpg|jpeg)$/Sxu';
 -      // @codingStandardsIgnoreEnd
  
        # Regular expression for a non-newline space
        const SPACE_NOT_NL = '(?:\t|&nbsp;|&\#0*160;|&\#[Xx]0*[Aa]0;|\p{Zs})';
  
                $useSubpages = $this->areSubpagesAllowed();
  
 -              // @codingStandardsIgnoreStart Squiz.WhiteSpace.SemicolonSpacing.Incorrect
                # Loop for each link
                for ( ; $line !== false && $line !== null; $a->next(), $line = $a->current() ) {
 -                      // @codingStandardsIgnoreEnd
 -
                        # Check for excessive memory usage
                        if ( $holders->isBig() ) {
                                # Too big
                                }
  
                                // Extract any forwarded flags
 +                              if ( isset( $result['title'] ) ) {
 +                                      $title = $result['title'];
 +                              }
                                if ( isset( $result['found'] ) ) {
                                        $found = $result['found'];
                                }
                $deps = [];
  
                # Loop to fetch the article, with up to 1 redirect
 -              // @codingStandardsIgnoreStart Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed
 +              // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall
                for ( $i = 0; $i < 2 && is_object( $title ); $i++ ) {
 -                      // @codingStandardsIgnoreEnd
                        # Give extensions a chance to select the revision instead
                        $id = false; # Assume current
                        Hooks::run( 'BeforeParserFetchTemplateAndtitle',
                        $anchor = $safeHeadline;
                        $fallbackAnchor = $fallbackHeadline;
                        if ( isset( $refers[$arrayKey] ) ) {
 -                              // @codingStandardsIgnoreStart
 +                              // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall,Generic.Formatting.DisallowMultipleStatements
                                for ( $i = 2; isset( $refers["${arrayKey}_$i"] ); ++$i );
 -                              // @codingStandardsIgnoreEnd
                                $anchor .= "_$i";
                                $linkAnchor .= "_$i";
                                $refers["${arrayKey}_$i"] = true;
                                $refers[$arrayKey] = true;
                        }
                        if ( $fallbackHeadline !== false && isset( $refers[$fallbackArrayKey] ) ) {
 -                              // @codingStandardsIgnoreStart
 +                              // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall,Generic.Formatting.DisallowMultipleStatements
                                for ( $i = 2; isset( $refers["${fallbackArrayKey}_$i"] ); ++$i );
 -                              // @codingStandardsIgnoreEnd
                                $fallbackAnchor .= "_$i";
                                $refers["${fallbackArrayKey}_$i"] = true;
                        } else {
         * Wrapper for preprocess()
         *
         * @param string $text The text to preprocess
-        * @param ParserOptions $options Options
+        * @param ParserOptions $options
         * @param Title|null $title Title object or null to use $wgTitle
         * @return string
         */
                global $wgFragmentMode;
                if ( isset( $wgFragmentMode[1] ) && $wgFragmentMode[1] === 'legacy' ) {
                        // ForAttribute() and ForLink() are the same for legacy encoding
 -                      $id = Sanitizer::escapeIdForAttribute( $text, Sanitizer::ID_FALLBACK );
 +                      $id = Sanitizer::escapeIdForAttribute( $sectionName, Sanitizer::ID_FALLBACK );
                } else {
 -                      $id = Sanitizer::escapeIdForLink( $text );
 +                      $id = Sanitizer::escapeIdForLink( $sectionName );
                }
  
                return "#$id";
        /**
         * Remove any strip markers found in the given text.
         *
-        * @param string $text Input string
+        * @param string $text
         * @return string
         */
        public function killMarkers( $text ) {
@@@ -65,6 -65,8 +65,6 @@@ abstract class ResourceLoaderModule imp
        # pages like Special:UserLogin and Special:Preferences
        protected $origin = self::ORIGIN_CORE_SITEWIDE;
  
 -      /* Protected Members */
 -
        protected $name = null;
        protected $targets = [ 'desktop' ];
  
@@@ -92,6 -94,8 +92,6 @@@
         */
        protected $logger;
  
 -      /* Methods */
 -
        /**
         * Get this module's name. This is set when the module is registered
         * with ResourceLoader::register()
         * Set this module's name. This is called by ResourceLoader::register()
         * when registering the module. Other code should not call this.
         *
-        * @param string $name Name
+        * @param string $name
         */
        public function setName( $name ) {
                $this->name = $name;
         * Get this module's last modification timestamp for a given context.
         *
         * @deprecated since 1.26 Use getDefinitionSummary() instead
-        * @param ResourceLoaderContext $context Context object
+        * @param ResourceLoaderContext $context
         * @return int|null UNIX timestamp
         */
        public function getModifiedTime( ResourceLoaderContext $context ) {
@@@ -34,7 -34,7 +34,7 @@@ class SearchExactMatchRescorer 
         * may sort based on other algorithms that may cause the exact title match
         * to not be in the results or be lower down the list.
         * @param string $search the query
-        * @param int[] $namespaces the namespaces
+        * @param int[] $namespaces
         * @param string[] $srchres results
         * @param int $limit the max number of results to return
         * @return string[] munged results
        }
  
        /**
-        * @param string[] $titles as strings
+        * @param string[] $titles
         * @return array redirect target prefixedText to index of title in titles
         *   that is a redirect to it.
         */
 -      private function redirectTargetsToRedirect( $titles ) {
 +      private function redirectTargetsToRedirect( array $titles ) {
                $result = [];
                foreach ( $titles as $key => $titleText ) {
                        $title = Title::newFromText( $titleText );
         * @param int $key key to pull to the front
         * @return array $array with the item at $key pulled to the front
         */
 -      private function pullFront( $key, $array ) {
 +      private function pullFront( $key, array $array ) {
                $cut = array_splice( $array, $key, 1 );
                array_unshift( $array, $cut[0] );
                return $array;
@@@ -38,6 -38,7 +38,6 @@@ class SpecialRecentChanges extends Chan
  
        private $watchlistFilterGroupDefinition;
  
 -      // @codingStandardsIgnoreStart Needed "useless" override to change parameters.
        public function __construct( $name = 'Recentchanges', $restriction = '' ) {
                parent::__construct( $name, $restriction );
  
                        }
                ];
        }
 -      // @codingStandardsIgnoreEnd
  
        /**
         * Main execution point
        /**
         * Makes change an option link which carries all the other options
         *
-        * @param string $title Title
+        * @param string $title
         * @param array $override Options to override
         * @param array $options Current options
         * @param bool $active Whether to show the link in bold
diff --combined includes/user/User.php
@@@ -3089,13 -3089,12 +3089,13 @@@ class User implements IDBAccessObject, 
                        $options = $this->mOptions;
                }
  
 -              $prefs = Preferences::getPreferences( $this, $context );
 +              $preferencesFactory = MediaWikiServices::getInstance()->getPreferencesFactory();
 +              $prefs = $preferencesFactory->getFormDescriptor( $this, $context );
                $mapping = [];
  
                // Pull out the "special" options, so they don't get converted as
                // multiselect or checkmatrix.
 -              $specialOptions = array_fill_keys( Preferences::getSaveBlacklist(), true );
 +              $specialOptions = array_fill_keys( $preferencesFactory->getSaveBlacklist(), true );
                foreach ( $specialOptions as $name => $value ) {
                        unset( $prefs[$name] );
                }
         * (T8957 with Gmail and Internet Explorer).
         *
         * @param string $page Special page
-        * @param string $token Token
+        * @param string $token
         * @return string Formatted URL
         */
        protected function getTokenUrl( $page, $token ) {
@@@ -440,8 -440,8 +440,8 @@@ class GenerateSitemap extends Maintenan
        /**
         * Get a sitemap filename
         *
-        * @param int $namespace The namespace
-        * @param int $count The count
+        * @param int $namespace
+        * @param int $count
         * @return string
         */
        function sitemapFilename( $namespace, $count ) {
         * @return string
         */
        function indexEntry( $filename ) {
 -              return
 -                      "\t<sitemap>\n" .
 +              return "\t<sitemap>\n" .
                        "\t\t<loc>{$this->urlpath}$filename</loc>\n" .
                        "\t\t<lastmod>{$this->timestamp}</lastmod>\n" .
                        "\t</sitemap>\n";
         * @return string
         */
        function fileEntry( $url, $date, $priority ) {
 -              return
 -                      "\t<url>\n" .
 +              return "\t<url>\n" .
                        // T36666: $url may contain bad characters such as ampersands.
                        "\t\t<loc>" . htmlspecialchars( $url ) . "</loc>\n" .
                        "\t\t<lastmod>$date</lastmod>\n" .