Merge "Move EmailNotification::updateWatchlistTimestamp to WatchedItemStore"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Tue, 8 Mar 2016 19:19:12 +0000 (19:19 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Tue, 8 Mar 2016 19:19:12 +0000 (19:19 +0000)
67 files changed:
RELEASE-NOTES-1.27
docs/hooks.txt
includes/DefaultSettings.php
includes/GlobalFunctions.php
includes/OutputPage.php
includes/Title.php
includes/WebResponse.php
includes/api/ApiBase.php
includes/api/ApiContinuationManager.php
includes/api/ApiEditPage.php
includes/api/ApiExpandTemplates.php
includes/api/ApiFeedContributions.php
includes/api/ApiFormatBase.php
includes/api/ApiFormatXml.php
includes/api/ApiHelp.php
includes/api/ApiImageRotate.php
includes/api/ApiImport.php
includes/api/ApiLogin.php
includes/api/ApiMain.php
includes/api/ApiOpenSearch.php
includes/api/ApiOptions.php
includes/api/ApiPageSet.php
includes/api/ApiParamInfo.php
includes/api/ApiParse.php
includes/api/ApiQuery.php
includes/api/ApiQueryAllLinks.php
includes/api/ApiQueryBacklinks.php
includes/api/ApiQueryBacklinksprop.php
includes/api/ApiQueryFileRepoInfo.php
includes/api/ApiQueryImageInfo.php
includes/api/ApiQueryRevisionsBase.php
includes/api/ApiQuerySiteinfo.php
includes/api/ApiQueryStashImageInfo.php
includes/api/ApiResult.php
includes/api/ApiStashEdit.php
includes/api/ApiTokens.php
includes/api/ApiUpload.php
includes/api/ApiWatch.php
includes/content/JsonContent.php
includes/db/DatabaseMysqlBase.php
includes/db/DatabaseOracle.php
includes/db/DatabaseUtility.php
includes/db/IDatabase.php
includes/filerepo/ForeignAPIRepo.php
includes/installer/MysqlUpdater.php
includes/jobqueue/JobQueueDB.php
includes/jobqueue/JobQueueFederated.php
includes/parser/Parser.php
includes/search/SearchMssql.php
includes/session/BotPasswordSessionProvider.php
includes/session/Session.php
includes/session/SessionManager.php
includes/specialpage/SpecialPageFactory.php
includes/specials/SpecialImport.php
includes/utils/MWRestrictions.php
languages/classes/LanguageCu.php
languages/classes/LanguageHy.php
languages/classes/LanguageUk.php
maintenance/benchmarks/Benchmarker.php
maintenance/getConfiguration.php
tests/phpunit/includes/api/RandomImageGenerator.php
tests/phpunit/includes/db/DatabaseMysqlBaseTest.php
tests/phpunit/includes/libs/MemoizedCallableTest.php
tests/phpunit/includes/media/WebPTest.php
tests/phpunit/includes/specialpage/SpecialPageFactoryTest.php
tests/phpunit/structure/ApiDocumentationTest.php
tests/qunit/data/generateJqueryMsgData.php

index a7706e7..b64bf40 100644 (file)
@@ -217,7 +217,10 @@ HHVM 3.1.
   ApiQueryBase::keyPartToTitle() all removed (deprecated since 1.24).
 * ApiQueryBase::checkRowCount() was removed (deprecated since 1.24).
 * ApiQueryBase::getDirectionDescription() was removed (deprecated since 1.25).
+* ApiQuery::getGenerators() was removed (deprecated since 1.21).
 * ApiQuery::getModules() was removed (deprecated since 1.21).
+* ApiQuery::getModuleType() was removed (deprecated since 1.21).
+* ApiQuery::setGeneratorContinue() was removed (deprecated since 1.24).
 * ApiMain::getModules() was removed (deprecated since 1.21).
 * ApiBase::getVersion() was removed (deprecated since 1.21).
 
index c5f2424..a431f1b 100644 (file)
@@ -178,7 +178,8 @@ once for 'TimStarling', and once for 'brion'.
 
 Hooks can return three possible values:
 
-  * true: the hook has operated successfully
+  * No return value (or null): the hook has operated successfully. Previously,
+    true was required. This is the default since MediaWiki 1.23.
   * "some string": an error occurred; processing should stop and the error
                    should be shown to the user
   * false: the hook has successfully done the work necessary and the calling
index 2a9986e..c04602c 100644 (file)
@@ -2096,7 +2096,7 @@ $wgTransactionalTimeLimit = 120;
 
 /**
  * Directory for caching data in the local filesystem. Should not be accessible
- * from the web. Set this to false to not use any local caches.
+ * from the web.
  *
  * Note: if multiple wikis share the same localisation cache directory, they
  * must all have the same set of extensions. You can set a directory just for
index e48a399..3fa91fa 100644 (file)
@@ -1738,7 +1738,7 @@ function wfEscapeWikiText( $text ) {
                                $repl2[] = preg_quote( substr( $prot, 0, -1 ), '/' );
                        }
                }
-               $repl2 = $repl2 ? '/\b(' . join( '|', $repl2 ) . '):/i' : '/^(?!)/';
+               $repl2 = $repl2 ? '/\b(' . implode( '|', $repl2 ) . '):/i' : '/^(?!)/';
        }
        $text = substr( strtr( "\n$text", $repl ), 1 );
        $text = preg_replace( $repl2, '$1&#58;', $text );
index 5d1d5d0..11c23f0 100644 (file)
@@ -2069,7 +2069,7 @@ class OutputPage extends ContextSource {
                foreach ( SessionManager::singleton()->getVaryHeaders() as $header => $options ) {
                        $this->addVaryHeader( $header, $options );
                }
-               return 'Vary: ' . join( ', ', array_keys( $this->mVaryHeader ) );
+               return 'Vary: ' . implode( ', ', array_keys( $this->mVaryHeader ) );
        }
 
        /**
@@ -2213,8 +2213,12 @@ class OutputPage extends ContextSource {
 
                if ( $this->mEnableClientCache ) {
                        if (
-                               $config->get( 'UseSquid' ) && !SessionManager::getGlobalSession()->isPersistent() &&
-                               !$this->isPrintable() && $this->mCdnMaxage != 0 && !$this->haveCacheVaryCookies()
+                               $config->get( 'UseSquid' ) &&
+                               !$response->hasCookies() &&
+                               !SessionManager::getGlobalSession()->isPersistent() &&
+                               !$this->isPrintable() &&
+                               $this->mCdnMaxage != 0 &&
+                               !$this->haveCacheVaryCookies()
                        ) {
                                if ( $config->get( 'UseESI' ) ) {
                                        # We'll purge the proxy cache explicitly, but require end user agents
index 1a8a5f1..0ac3e46 100644 (file)
@@ -174,7 +174,7 @@ class Title implements LinkTarget {
                // make sure we are using the right one. To detect changes over the course
                // of a request, we remember a fingerprint of the config used to create the
                // codec singleton, and re-create it if the fingerprint doesn't match.
-               $fingerprint = spl_object_hash( $wgContLang ) . '|' . join( '+', $wgLocalInterwikis );
+               $fingerprint = spl_object_hash( $wgContLang ) . '|' . implode( '+', $wgLocalInterwikis );
 
                if ( $fingerprint !== $titleCodecFingerprint ) {
                        $titleCodec = null;
index c7d0a5b..458c207 100644 (file)
@@ -179,6 +179,16 @@ class WebResponse {
        public function clearCookie( $name, $options = [] ) {
                $this->setCookie( $name, '', time() - 31536000 /* 1 year */, $options );
        }
+
+       /**
+        * Checks whether this request is performing cookie operations
+        *
+        * @return bool
+        * @since 1.27
+        */
+       public function hasCookies() {
+               return (bool)self::$setCookies;
+       }
 }
 
 /**
index 6acacf1..85dee2b 100644 (file)
@@ -302,7 +302,7 @@ abstract class ApiBase extends ContextSource {
                                        $qs = $k;
                                        $msg = self::escapeWikiText( $v );
                                        if ( is_array( $msg ) ) {
-                                               $msg = join( " ", $msg );
+                                               $msg = implode( ' ', $msg );
                                        }
                                }
 
@@ -547,13 +547,13 @@ abstract class ApiBase extends ContextSource {
                        $parent = $module;
                        $manager = $parent->getModuleManager();
                        if ( $manager === null ) {
-                               $errorPath = join( '+', array_slice( $parts, 0, $i ) );
+                               $errorPath = implode( '+', array_slice( $parts, 0, $i ) );
                                $this->dieUsage( "The module \"$errorPath\" has no submodules", 'badmodule' );
                        }
                        $module = $manager->getModule( $parts[$i] );
 
                        if ( $module === null ) {
-                               $errorPath = $i ? join( '+', array_slice( $parts, 0, $i ) ) : $parent->getModuleName();
+                               $errorPath = $i ? implode( '+', array_slice( $parts, 0, $i ) ) : $parent->getModuleName();
                                $this->dieUsage(
                                        "The module \"$errorPath\" does not have a submodule \"{$parts[$i]}\"",
                                        'badmodule'
@@ -711,7 +711,7 @@ abstract class ApiBase extends ContextSource {
                $p = $this->getModulePrefix();
 
                $intersection = array_intersect( array_keys( array_filter( $params,
-                       [ $this, "parameterNotEmpty" ] ) ), $required );
+                       [ $this, 'parameterNotEmpty' ] ) ), $required );
 
                if ( count( $intersection ) > 1 ) {
                        $this->dieUsage(
@@ -737,7 +737,7 @@ abstract class ApiBase extends ContextSource {
                $p = $this->getModulePrefix();
 
                $intersection = array_intersect( array_keys( array_filter( $params,
-                       [ $this, "parameterNotEmpty" ] ) ), $required );
+                       [ $this, 'parameterNotEmpty' ] ) ), $required );
 
                if ( count( $intersection ) > 1 ) {
                        $this->dieUsage(
@@ -760,7 +760,7 @@ abstract class ApiBase extends ContextSource {
                $p = $this->getModulePrefix();
 
                $intersection = array_intersect(
-                       array_keys( array_filter( $params, [ $this, "parameterNotEmpty" ] ) ),
+                       array_keys( array_filter( $params, [ $this, 'parameterNotEmpty' ] ) ),
                        $required
                );
 
@@ -917,7 +917,7 @@ abstract class ApiBase extends ContextSource {
                                ApiBase::dieDebug(
                                        __METHOD__,
                                        "Boolean param $encParamName's default is set to '$default'. " .
-                                               "Boolean parameters must default to false."
+                                               'Boolean parameters must default to false.'
                                );
                        }
 
@@ -942,8 +942,8 @@ abstract class ApiBase extends ContextSource {
                                if ( $value !== null ) {
                                        $this->dieUsage(
                                                "File upload param $encParamName is not a file upload; " .
-                                                       "be sure to use multipart/form-data for your POST and include " .
-                                                       "a filename in the Content-Disposition header.",
+                                                       'be sure to use multipart/form-data for your POST and include ' .
+                                                       'a filename in the Content-Disposition header.',
                                                "badupload_{$encParamName}"
                                        );
                                }
@@ -1157,7 +1157,7 @@ abstract class ApiBase extends ContextSource {
                        if ( count( $unknown ) ) {
                                if ( $allowMultiple ) {
                                        $s = count( $unknown ) > 1 ? 's' : '';
-                                       $vals = implode( ", ", $unknown );
+                                       $vals = implode( ', ', $unknown );
                                        $this->setWarning( "Unrecognized value$s for parameter '$valueName': $vals" );
                                } else {
                                        $this->dieUsage(
@@ -1615,15 +1615,15 @@ abstract class ApiBase extends ContextSource {
                ],
                'badaccess-group0' => [
                        'code' => 'permissiondenied',
-                       'info' => "Permission denied"
+                       'info' => 'Permission denied'
                ], // Generic permission denied message
                'badaccess-groups' => [
                        'code' => 'permissiondenied',
-                       'info' => "Permission denied"
+                       'info' => 'Permission denied'
                ],
                'titleprotected' => [
                        'code' => 'protectedtitle',
-                       'info' => "This title has been protected from creation"
+                       'info' => 'This title has been protected from creation'
                ],
                'nocreate-loggedin' => [
                        'code' => 'cantcreate',
@@ -1643,15 +1643,15 @@ abstract class ApiBase extends ContextSource {
                ],
                'confirmedittext' => [
                        'code' => 'confirmemail',
-                       'info' => "You must confirm your email address before you can edit"
+                       'info' => 'You must confirm your email address before you can edit'
                ],
                'blockedtext' => [
                        'code' => 'blocked',
-                       'info' => "You have been blocked from editing"
+                       'info' => 'You have been blocked from editing'
                ],
                'autoblockedtext' => [
                        'code' => 'autoblocked',
-                       'info' => "Your IP address has been blocked automatically, because it was used by a blocked user"
+                       'info' => 'Your IP address has been blocked automatically, because it was used by a blocked user'
                ],
 
                // Miscellaneous interface messages
@@ -1661,19 +1661,19 @@ abstract class ApiBase extends ContextSource {
                ],
                'alreadyrolled' => [
                        'code' => 'alreadyrolled',
-                       'info' => "The page you tried to rollback was already rolled back"
+                       'info' => 'The page you tried to rollback was already rolled back'
                ],
                'cantrollback' => [
                        'code' => 'onlyauthor',
-                       'info' => "The page you tried to rollback only has one author"
+                       'info' => 'The page you tried to rollback only has one author'
                ],
                'readonlytext' => [
                        'code' => 'readonly',
-                       'info' => "The wiki is currently in read-only mode"
+                       'info' => 'The wiki is currently in read-only mode'
                ],
                'sessionfailure' => [
                        'code' => 'badtoken',
-                       'info' => "Invalid token" ],
+                       'info' => 'Invalid token' ],
                'cannotdelete' => [
                        'code' => 'cantdelete',
                        'info' => "Couldn't delete \"\$1\". Maybe it was deleted already by someone else"
@@ -1686,11 +1686,11 @@ abstract class ApiBase extends ContextSource {
                ],
                'immobile_namespace' => [
                        'code' => 'immobilenamespace',
-                       'info' => "You tried to move pages from or to a namespace that is protected from moving"
+                       'info' => 'You tried to move pages from or to a namespace that is protected from moving'
                ],
                'articleexists' => [
                        'code' => 'articleexists',
-                       'info' => "The destination article already exists and is not a redirect to the source article"
+                       'info' => 'The destination article already exists and is not a redirect to the source article'
                ],
                'protectedpage' => [
                        'code' => 'protectedpage',
@@ -1698,11 +1698,11 @@ abstract class ApiBase extends ContextSource {
                ],
                'hookaborted' => [
                        'code' => 'hookaborted',
-                       'info' => "The modification you tried to make was aborted by an extension hook"
+                       'info' => 'The modification you tried to make was aborted by an extension hook'
                ],
                'cantmove-titleprotected' => [
                        'code' => 'protectedtitle',
-                       'info' => "The destination article has been protected from creation"
+                       'info' => 'The destination article has been protected from creation'
                ],
                'imagenocrossnamespace' => [
                        'code' => 'nonfilenamespace',
@@ -1714,20 +1714,20 @@ abstract class ApiBase extends ContextSource {
                ],
                // 'badarticleerror' => shouldn't happen
                // 'badtitletext' => shouldn't happen
-               'ip_range_invalid' => [ 'code' => 'invalidrange', 'info' => "Invalid IP range" ],
+               'ip_range_invalid' => [ 'code' => 'invalidrange', 'info' => 'Invalid IP range' ],
                'range_block_disabled' => [
                        'code' => 'rangedisabled',
-                       'info' => "Blocking IP ranges has been disabled"
+                       'info' => 'Blocking IP ranges has been disabled'
                ],
                'nosuchusershort' => [
                        'code' => 'nosuchuser',
                        'info' => "The user you specified doesn't exist"
                ],
-               'badipaddress' => [ 'code' => 'invalidip', 'info' => "Invalid IP address specified" ],
-               'ipb_expiry_invalid' => [ 'code' => 'invalidexpiry', 'info' => "Invalid expiry time" ],
+               'badipaddress' => [ 'code' => 'invalidip', 'info' => 'Invalid IP address specified' ],
+               'ipb_expiry_invalid' => [ 'code' => 'invalidexpiry', 'info' => 'Invalid expiry time' ],
                'ipb_already_blocked' => [
                        'code' => 'alreadyblocked',
-                       'info' => "The user you tried to block was already blocked"
+                       'info' => 'The user you tried to block was already blocked'
                ],
                'ipb_blocked_as_range' => [
                        'code' => 'blockedasrange',
@@ -1735,11 +1735,11 @@ abstract class ApiBase extends ContextSource {
                ],
                'ipb_cant_unblock' => [
                        'code' => 'cantunblock',
-                       'info' => "The block you specified was not found. It may have been unblocked already"
+                       'info' => 'The block you specified was not found. It may have been unblocked already'
                ],
                'mailnologin' => [
                        'code' => 'cantsend',
-                       'info' => "You are not logged in, you do not have a confirmed email address, or you are not allowed to send email to other users, so you cannot send email"
+                       'info' => 'You are not logged in, you do not have a confirmed email address, or you are not allowed to send email to other users, so you cannot send email'
                ],
                'ipbblocked' => [
                        'code' => 'ipbblocked',
@@ -1751,23 +1751,23 @@ abstract class ApiBase extends ContextSource {
                ],
                'usermaildisabled' => [
                        'code' => 'usermaildisabled',
-                       'info' => "User email has been disabled"
+                       'info' => 'User email has been disabled'
                ],
                'blockedemailuser' => [
                        'code' => 'blockedfrommail',
-                       'info' => "You have been blocked from sending email"
+                       'info' => 'You have been blocked from sending email'
                ],
                'notarget' => [
                        'code' => 'notarget',
-                       'info' => "You have not specified a valid target for this action"
+                       'info' => 'You have not specified a valid target for this action'
                ],
                'noemail' => [
                        'code' => 'noemail',
-                       'info' => "The user has not specified a valid email address, or has chosen not to receive email from other users"
+                       'info' => 'The user has not specified a valid email address, or has chosen not to receive email from other users'
                ],
                'rcpatroldisabled' => [
                        'code' => 'patroldisabled',
-                       'info' => "Patrolling is disabled on this wiki"
+                       'info' => 'Patrolling is disabled on this wiki'
                ],
                'markedaspatrollederror-noautopatrol' => [
                        'code' => 'noautopatrol',
@@ -1804,7 +1804,7 @@ abstract class ApiBase extends ContextSource {
                // API-specific messages
                'readrequired' => [
                        'code' => 'readapidenied',
-                       'info' => "You need read permission to use this module"
+                       'info' => 'You need read permission to use this module'
                ],
                'writedisabled' => [
                        'code' => 'noapiwrite',
@@ -1843,7 +1843,7 @@ abstract class ApiBase extends ContextSource {
                ],
                'unblock-notarget' => [
                        'code' => 'notarget',
-                       'info' => "Either the id or the user parameter must be set"
+                       'info' => 'Either the id or the user parameter must be set'
                ],
                'unblock-idanduser' => [
                        'code' => 'idanduser',
@@ -1863,7 +1863,7 @@ abstract class ApiBase extends ContextSource {
                ],
                'createonly-exists' => [
                        'code' => 'articleexists',
-                       'info' => "The article you tried to create has been created already"
+                       'info' => 'The article you tried to create has been created already'
                ],
                'nocreate-missing' => [
                        'code' => 'missingtitle',
@@ -1992,17 +1992,17 @@ abstract class ApiBase extends ContextSource {
                'noedit' => [ 'code' => 'noedit', 'info' => "You don't have permission to edit pages" ],
                'wasdeleted' => [
                        'code' => 'pagedeleted',
-                       'info' => "The page has been deleted since you fetched its timestamp"
+                       'info' => 'The page has been deleted since you fetched its timestamp'
                ],
                'blankpage' => [
                        'code' => 'emptypage',
-                       'info' => "Creating new, empty pages is not allowed"
+                       'info' => 'Creating new, empty pages is not allowed'
                ],
-               'editconflict' => [ 'code' => 'editconflict', 'info' => "Edit conflict detected" ],
-               'hashcheckfailed' => [ 'code' => 'badmd5', 'info' => "The supplied MD5 hash was incorrect" ],
+               'editconflict' => [ 'code' => 'editconflict', 'info' => 'Edit conflict detected' ],
+               'hashcheckfailed' => [ 'code' => 'badmd5', 'info' => 'The supplied MD5 hash was incorrect' ],
                'missingtext' => [
                        'code' => 'notext',
-                       'info' => "One of the text, appendtext, prependtext and undo parameters must be set"
+                       'info' => 'One of the text, appendtext, prependtext and undo parameters must be set'
                ],
                'emptynewsection' => [
                        'code' => 'emptynewsection',
@@ -2024,13 +2024,13 @@ abstract class ApiBase extends ContextSource {
                // Messages from WikiPage::doEit(]
                'edit-hook-aborted' => [
                        'code' => 'edit-hook-aborted',
-                       'info' => "Your edit was aborted by an ArticleSave hook"
+                       'info' => 'Your edit was aborted by an ArticleSave hook'
                ],
                'edit-gone-missing' => [
                        'code' => 'edit-gone-missing',
                        'info' => "The page you tried to edit doesn't seem to exist anymore"
                ],
-               'edit-conflict' => [ 'code' => 'editconflict', 'info' => "Edit conflict detected" ],
+               'edit-conflict' => [ 'code' => 'editconflict', 'info' => 'Edit conflict detected' ],
                'edit-already-exists' => [
                        'code' => 'edit-already-exists',
                        'info' => 'It seems the page you tried to create already exist'
@@ -2223,7 +2223,7 @@ abstract class ApiBase extends ContextSource {
                Hooks::run( 'APIGetDescription', [ &$this, &$desc ] );
                $desc = self::escapeWikiText( $desc );
                if ( is_array( $desc ) ) {
-                       $desc = join( "\n", $desc );
+                       $desc = implode( "\n", $desc );
                } else {
                        $desc = (string)$desc;
                }
@@ -2309,7 +2309,7 @@ abstract class ApiBase extends ContextSource {
                                        }
                                        return $line;
                                }, $d );
-                               $d = join( ' ', $d );
+                               $d = implode( ' ', $d );
                        }
 
                        if ( isset( $settings[ApiBase::PARAM_HELP_MSG] ) ) {
@@ -2323,18 +2323,18 @@ abstract class ApiBase extends ContextSource {
                        $msg = ApiBase::makeMessage( $msg, $this->getContext(),
                                [ $prefix, $param, $name, $path ] );
                        if ( !$msg ) {
-                               $this->dieDebug( __METHOD__,
+                               self::dieDebug( __METHOD__,
                                        'Value in ApiBase::PARAM_HELP_MSG is not valid' );
                        }
                        $msgs[$param] = [ $msg ];
 
                        if ( isset( $settings[ApiBase::PARAM_HELP_MSG_PER_VALUE] ) ) {
                                if ( !is_array( $settings[ApiBase::PARAM_HELP_MSG_PER_VALUE] ) ) {
-                                       $this->dieDebug( __METHOD__,
+                                       self::dieDebug( __METHOD__,
                                                'ApiBase::PARAM_HELP_MSG_PER_VALUE is not valid' );
                                }
                                if ( !is_array( $settings[ApiBase::PARAM_TYPE] ) ) {
-                                       $this->dieDebug( __METHOD__,
+                                       self::dieDebug( __METHOD__,
                                                'ApiBase::PARAM_HELP_MSG_PER_VALUE may only be used when ' .
                                                'ApiBase::PARAM_TYPE is an array' );
                                }
@@ -2356,7 +2356,7 @@ abstract class ApiBase extends ContextSource {
                                                );
                                                $msgs[$param][] = $m->setContext( $this->getContext() );
                                        } else {
-                                               $this->dieDebug( __METHOD__,
+                                               self::dieDebug( __METHOD__,
                                                        "Value in ApiBase::PARAM_HELP_MSG_PER_VALUE for $value is not valid" );
                                        }
                                }
@@ -2364,7 +2364,7 @@ abstract class ApiBase extends ContextSource {
 
                        if ( isset( $settings[ApiBase::PARAM_HELP_MSG_APPEND] ) ) {
                                if ( !is_array( $settings[ApiBase::PARAM_HELP_MSG_APPEND] ) ) {
-                                       $this->dieDebug( __METHOD__,
+                                       self::dieDebug( __METHOD__,
                                                'Value for ApiBase::PARAM_HELP_MSG_APPEND is not an array' );
                                }
                                foreach ( $settings[ApiBase::PARAM_HELP_MSG_APPEND] as $m ) {
@@ -2373,7 +2373,7 @@ abstract class ApiBase extends ContextSource {
                                        if ( $m ) {
                                                $msgs[$param][] = $m;
                                        } else {
-                                               $this->dieDebug( __METHOD__,
+                                               self::dieDebug( __METHOD__,
                                                        'Value in ApiBase::PARAM_HELP_MSG_APPEND is not valid' );
                                        }
                                }
@@ -2740,7 +2740,7 @@ abstract class ApiBase extends ContextSource {
                                                $examples
                                        ];
                                }
-                               $msg .= "Example" . ( count( $examples ) > 1 ? 's' : '' ) . ":\n";
+                               $msg .= 'Example' . ( count( $examples ) > 1 ? 's' : '' ) . ":\n";
                                foreach ( $examples as $k => $v ) {
                                        if ( is_numeric( $k ) ) {
                                                $msg .= "  $v\n";
@@ -2750,7 +2750,7 @@ abstract class ApiBase extends ContextSource {
                                                } else {
                                                        $msgExample = "  $v";
                                                }
-                                               $msgExample .= ":";
+                                               $msgExample .= ':';
                                                $msg .= wordwrap( $msgExample, 100, "\n" ) . "\n    $k\n";
                                        }
                                }
@@ -2766,7 +2766,7 @@ abstract class ApiBase extends ContextSource {
         * @return string
         */
        private function indentExampleText( $item ) {
-               return "  " . $item;
+               return '  ' . $item;
        }
 
        /**
@@ -2849,7 +2849,7 @@ abstract class ApiBase extends ContextSource {
                                if ( isset( $paramSettings[self::PARAM_REQUIRED] )
                                        && $paramSettings[self::PARAM_REQUIRED]
                                ) {
-                                       $desc .= $paramPrefix . "This parameter is required";
+                                       $desc .= $paramPrefix . 'This parameter is required';
                                }
 
                                $type = isset( $paramSettings[self::PARAM_TYPE] )
@@ -2925,7 +2925,7 @@ abstract class ApiBase extends ContextSource {
                                                                }
                                                                break;
                                                        case 'upload':
-                                                               $desc .= $paramPrefix . "Must be posted as a file upload using multipart/form-data";
+                                                               $desc .= $paramPrefix . 'Must be posted as a file upload using multipart/form-data';
                                                                break;
                                                }
                                        }
@@ -2939,8 +2939,8 @@ abstract class ApiBase extends ContextSource {
                                                if ( !$isArray
                                                        || $isArray && count( $type ) > self::LIMIT_SML1
                                                ) {
-                                                       $desc .= $paramPrefix . "Maximum number of values " .
-                                                               self::LIMIT_SML1 . " (" . self::LIMIT_SML2 . " for bots)";
+                                                       $desc .= $paramPrefix . 'Maximum number of values ' .
+                                                               self::LIMIT_SML1 . ' (' . self::LIMIT_SML2 . ' for bots)';
                                                }
                                        }
                                }
index 25407bf..8f1bd19 100644 (file)
@@ -137,7 +137,7 @@ class ApiContinuationManager {
                }
                $paramName = $module->encodeParamName( $paramName );
                if ( is_array( $paramValue ) ) {
-                       $paramValue = join( '|', $paramValue );
+                       $paramValue = implode( '|', $paramValue );
                }
                $this->continuationData[$name][$paramName] = $paramValue;
        }
@@ -152,7 +152,7 @@ class ApiContinuationManager {
                $name = $module->getModuleName();
                $paramName = $module->encodeParamName( $paramName );
                if ( is_array( $paramValue ) ) {
-                       $paramValue = join( '|', $paramValue );
+                       $paramValue = implode( '|', $paramValue );
                }
                $this->generatorContinuationData[$name][$paramName] = $paramValue;
        }
@@ -193,7 +193,7 @@ class ApiContinuationManager {
                                $data += $kvp;
                        }
                        $data += $this->generatorParams;
-                       $generatorKeys = join( '|', array_keys( $this->generatorParams ) );
+                       $generatorKeys = implode( '|', array_keys( $this->generatorParams ) );
                } elseif ( $this->generatorContinuationData ) {
                        // All the generator-using modules are complete, but the
                        // generator isn't. Continue the generator and restart the
@@ -204,7 +204,7 @@ class ApiContinuationManager {
                        }
                        $data += $generatorParams;
                        $finishedModules = array_diff( $finishedModules, $this->generatedModules );
-                       $generatorKeys = join( '|', array_keys( $generatorParams ) );
+                       $generatorKeys = implode( '|', array_keys( $generatorParams ) );
                        $batchcomplete = true;
                } else {
                        // Generator and prop modules are all done. Mark it so.
@@ -215,7 +215,7 @@ class ApiContinuationManager {
                // Set 'continue' if any continuation data is set or if the generator
                // still needs to run
                if ( $data || $generatorKeys !== '-' ) {
-                       $data['continue'] = $generatorKeys . '||' . join( '|', $finishedModules );
+                       $data['continue'] = $generatorKeys . '||' . implode( '|', $finishedModules );
                }
 
                return [ $data, $batchcomplete ];
index f32bab0..08aba94 100644 (file)
@@ -335,7 +335,7 @@ class ApiEditPage extends ApiBase {
                        $section = $params['section'];
                        if ( !preg_match( '/^((T-)?\d+|new)$/', $section ) ) {
                                $this->dieUsage( "The section parameter must be a valid section id or 'new'",
-                                       "invalidsection" );
+                                       'invalidsection' );
                        }
                        $content = $pageObj->getContent();
                        if ( $section !== '0' && $section != 'new'
index 6611a09..286fe88 100644 (file)
@@ -158,7 +158,7 @@ class ApiExpandTemplates extends ApiBase {
                                        !isset( $prop['jsconfigvars'] ) && !isset( $prop['encodedjsconfigvars'] ) ) {
                                        $this->setWarning( "Property 'modules' was set but not 'jsconfigvars' " .
                                                "or 'encodedjsconfigvars'. Configuration variables are necessary " .
-                                               "for proper module usage." );
+                                               'for proper module usage.' );
                                }
                        }
                }
index dacf828..e28b068 100644 (file)
@@ -173,7 +173,7 @@ class ApiFeedContributions extends ApiBase {
 
                        return '<p>' . htmlspecialchars( $revision->getUserText() ) . $msg .
                                htmlspecialchars( FeedItem::stripComment( $revision->getComment() ) ) .
-                               "</p>\n<hr />\n<div>" . $html . "</div>";
+                               "</p>\n<hr />\n<div>" . $html . '</div>';
                }
 
                return '';
index 7c203d9..c826bba 100644 (file)
@@ -151,7 +151,7 @@ abstract class ApiFormatBase extends ApiBase {
         * Initialize the printer function and prepare the output headers.
         * @param bool $unused Always false since 1.25
         */
-       function initPrinter( $unused = false ) {
+       public function initPrinter( $unused = false ) {
                if ( $this->mDisabled ) {
                        return;
                }
index be9b6d0..a45dbeb 100644 (file)
@@ -266,7 +266,7 @@ class ApiFormatXml extends ApiFormatBase {
                );
        }
 
-       function addXslt() {
+       protected function addXslt() {
                $nt = Title::newFromText( $this->mXslt );
                if ( is_null( $nt ) || !$nt->exists() ) {
                        $this->setWarning( 'Invalid or non-existent stylesheet specified' );
index 349a34d..f2d6329 100644 (file)
@@ -268,7 +268,7 @@ class ApiHelp extends ApiBase {
                                        'level' => $level,
                                        'anchor' => $anchor,
                                        'line' => $header,
-                                       'number' => join( '.', $tocnumber ),
+                                       'number' => implode( '.', $tocnumber ),
                                        'index' => false,
                                ];
                                if ( empty( $options['noheader'] ) ) {
@@ -618,7 +618,7 @@ class ApiHelp extends ApiBase {
                                                                        ->parse();
                                                        }
                                                        if ( $extra ) {
-                                                               $info[] = join( ' ', $extra );
+                                                               $info[] = implode( ' ', $extra );
                                                        }
                                                }
                                        }
@@ -655,7 +655,7 @@ class ApiHelp extends ApiBase {
                                        }
 
                                        if ( $description ) {
-                                               $description = join( '', $description );
+                                               $description = implode( '', $description );
                                                $description = preg_replace( '!\s*</([oud]l)>\s*<\1>\s*!', "\n", $description );
                                                $help['parameters'] .= Html::rawElement( 'dd',
                                                        [ 'class' => 'description' ], $description );
@@ -744,7 +744,7 @@ class ApiHelp extends ApiBase {
 
                        Hooks::run( 'APIHelpModifyOutput', [ $module, &$help, $suboptions, &$haveModules ] );
 
-                       $out .= join( "\n", $help );
+                       $out .= implode( "\n", $help );
                }
 
                return $out;
index b309149..2b99353 100644 (file)
@@ -111,9 +111,9 @@ class ApiImageRotate extends ApiBase {
                        $tmpFile = TempFSFile::factory( 'rotate_', $ext );
                        $dstPath = $tmpFile->getPath();
                        $err = $handler->rotate( $file, [
-                               "srcPath" => $srcPath,
-                               "dstPath" => $dstPath,
-                               "rotation" => $rotation
+                               'srcPath' => $srcPath,
+                               'dstPath' => $dstPath,
+                               'rotation' => $rotation
                        ] );
                        if ( !$err ) {
                                $comment = wfMessage(
index 8574dce..10106ff 100644 (file)
@@ -175,7 +175,7 @@ class ApiImportReporter extends ImportReporter {
         * @param array $pageInfo
         * @return void
         */
-       function reportPage( $title, $origTitle, $revisionCount, $successCount, $pageInfo ) {
+       public function reportPage( $title, $origTitle, $revisionCount, $successCount, $pageInfo ) {
                // Add a result entry
                $r = [];
 
@@ -194,7 +194,7 @@ class ApiImportReporter extends ImportReporter {
                parent::reportPage( $title, $origTitle, $revisionCount, $successCount, $pageInfo );
        }
 
-       function getData() {
+       public function getData() {
                return $this->mResultArr;
        }
 }
index a6e6c49..02aae06 100644 (file)
@@ -208,7 +208,6 @@ class ApiLogin extends ApiBase {
 
                        case LoginForm::THROTTLED:
                                $result['result'] = 'Throttled';
-                               $throttle = $this->getConfig()->get( 'PasswordAttemptThrottle' );
                                $result['wait'] = intval( $loginForm->mThrottleWait );
                                break;
 
index 9e56819..f09c6f2 100644 (file)
@@ -978,7 +978,7 @@ class ApiMain extends ApiBase {
                if ( $module->needsToken() === true ) {
                        throw new MWException(
                                "Module '{$module->getModuleName()}' must be updated for the new token handling. " .
-                               "See documentation for ApiBase::needsToken for details."
+                               'See documentation for ApiBase::needsToken for details.'
                        );
                }
                if ( $module->needsToken() ) {
@@ -1174,7 +1174,7 @@ class ApiMain extends ApiBase {
                                $this->dieUsageMsg( 'writerequired' );
                        } elseif ( $this->getRequest()->getHeader( 'Promise-Non-Write-API-Action' ) ) {
                                $this->dieUsage(
-                                       "Promise-Non-Write-API-Action HTTP header cannot be sent to write API modules",
+                                       'Promise-Non-Write-API-Action HTTP header cannot be sent to write API modules',
                                        'promised-nonwrite-api'
                                );
                        }
@@ -1225,7 +1225,7 @@ class ApiMain extends ApiBase {
                // If a majority of slaves are too lagged then disallow writes
                $slaveCount = wfGetLB()->getServerCount() - 1;
                if ( $numLagged >= ceil( $slaveCount / 2 ) ) {
-                       $laggedServers = join( ', ', $laggedServers );
+                       $laggedServers = implode( ', ', $laggedServers );
                        wfDebugLog(
                                'api-readonly',
                                "Api request failed as read only because the following DBs are lagged: $laggedServers"
@@ -1443,7 +1443,7 @@ class ApiMain extends ApiBase {
                $ret = $this->getRequest()->getVal( $name );
                if ( $ret === null ) {
                        if ( $this->getRequest()->getArray( $name ) !== null ) {
-                               // See bug 10262 for why we don't just join( '|', ... ) the
+                               // See bug 10262 for why we don't just implode( '|', ... ) the
                                // array.
                                $this->setWarning(
                                        "Parameter '$name' uses unsupported PHP array syntax"
@@ -1637,7 +1637,7 @@ class ApiMain extends ApiBase {
                                        'level' => $level,
                                        'anchor' => 'main/datatypes',
                                        'line' => $header,
-                                       'number' => join( '.', $tocnumber ),
+                                       'number' => implode( '.', $tocnumber ),
                                        'index' => false,
                                ];
                        }
@@ -1656,7 +1656,7 @@ class ApiMain extends ApiBase {
                                        'level' => $level,
                                        'anchor' => 'main/credits',
                                        'line' => $header,
-                                       'number' => join( '.', $tocnumber ),
+                                       'number' => implode( '.', $tocnumber ),
                                        'index' => false,
                                ];
                        }
@@ -1771,7 +1771,7 @@ class ApiMain extends ApiBase {
                                ->inLanguage( 'en' )
                                ->text();
                        $groups = User::getGroupsWithPermission( $right );
-                       $msg .= "* " . $right . " *\n  $rightsMsg" .
+                       $msg .= '* ' . $right . " *\n  $rightsMsg" .
                                "\nGranted to:\n  " . str_replace( '*', 'all', implode( ', ', $groups ) ) . "\n\n";
                }
 
index 304b2d6..effa520 100644 (file)
@@ -358,7 +358,7 @@ class ApiOpenSearch extends ApiBase {
 
                $ns = implode( '|', SearchEngine::defaultNamespaces() );
                if ( !$ns ) {
-                       $ns = "0";
+                       $ns = '0';
                }
 
                switch ( $type ) {
index 1dde9c2..e51d46d 100644 (file)
@@ -99,19 +99,19 @@ class ApiOptions extends ApiBase {
                                case 'userjs':
                                        // Allow non-default preferences prefixed with 'userjs-', to be set by user scripts
                                        if ( strlen( $key ) > 255 ) {
-                                               $validation = "key too long (no more than 255 bytes allowed)";
-                                       } elseif ( preg_match( "/[^a-zA-Z0-9_-]/", $key ) !== 0 ) {
-                                               $validation = "invalid key (only a-z, A-Z, 0-9, _, - allowed)";
+                                               $validation = 'key too long (no more than 255 bytes allowed)';
+                                       } elseif ( preg_match( '/[^a-zA-Z0-9_-]/', $key ) !== 0 ) {
+                                               $validation = 'invalid key (only a-z, A-Z, 0-9, _, - allowed)';
                                        } else {
                                                $validation = true;
                                        }
                                        break;
                                case 'special':
-                                       $validation = "cannot be set by this module";
+                                       $validation = 'cannot be set by this module';
                                        break;
                                case 'unused':
                                default:
-                                       $validation = "not a valid preference";
+                                       $validation = 'not a valid preference';
                                        break;
                        }
                        if ( $validation === true ) {
index 1441a45..6bab762 100644 (file)
@@ -595,22 +595,22 @@ class ApiPageSet extends ApiBase {
                'special', 'missingIds', 'missingRevIds', 'missingTitles', 'interwikiTitles' ]
        ) {
                $result = [];
-               if ( in_array( "invalidTitles", $invalidChecks ) ) {
+               if ( in_array( 'invalidTitles', $invalidChecks ) ) {
                        self::addValues( $result, $this->getInvalidTitlesAndReasons(), 'invalid' );
                }
-               if ( in_array( "special", $invalidChecks ) ) {
+               if ( in_array( 'special', $invalidChecks ) ) {
                        self::addValues( $result, $this->getSpecialTitles(), 'special', 'title' );
                }
-               if ( in_array( "missingIds", $invalidChecks ) ) {
+               if ( in_array( 'missingIds', $invalidChecks ) ) {
                        self::addValues( $result, $this->getMissingPageIDs(), 'missing', 'pageid' );
                }
-               if ( in_array( "missingRevIds", $invalidChecks ) ) {
+               if ( in_array( 'missingRevIds', $invalidChecks ) ) {
                        self::addValues( $result, $this->getMissingRevisionIDs(), 'missing', 'revid' );
                }
-               if ( in_array( "missingTitles", $invalidChecks ) ) {
+               if ( in_array( 'missingTitles', $invalidChecks ) ) {
                        self::addValues( $result, $this->getMissingTitles(), 'missing' );
                }
-               if ( in_array( "interwikiTitles", $invalidChecks ) ) {
+               if ( in_array( 'interwikiTitles', $invalidChecks ) ) {
                        self::addValues( $result, $this->getInterwikiTitlesAsResult() );
                }
 
index 6e44f82..c3c9e21 100644 (file)
@@ -137,7 +137,7 @@ class ApiParamInfo extends ApiBase {
                                foreach ( $msgs as $m ) {
                                        $ret[] = $m->setContext( $this->context )->text();
                                }
-                               $res[$key] = join( "\n\n", $ret );
+                               $res[$key] = implode( "\n\n", $ret );
                                if ( $joinLists ) {
                                        $res[$key] = preg_replace( '!^(([*#:;])[^\n]*)\n\n(?=\2)!m', "$1\n", $res[$key] );
                                }
@@ -148,7 +148,7 @@ class ApiParamInfo extends ApiBase {
                                foreach ( $msgs as $m ) {
                                        $ret[] = $m->setContext( $this->context )->parseAsBlock();
                                }
-                               $ret = join( "\n", $ret );
+                               $ret = implode( "\n", $ret );
                                if ( $joinLists ) {
                                        $ret = preg_replace( '!\s*</([oud]l)>\s*<\1>\s*!', "\n", $ret );
                                }
index 872876d..fe418e3 100644 (file)
@@ -72,7 +72,7 @@ class ApiParse extends ApiBase {
                        $this->section = $params['section'];
                        if ( !preg_match( '/^((T-)?\d+|new)$/', $this->section ) ) {
                                $this->dieUsage(
-                                       "The section parameter must be a valid section id or 'new'", "invalidsection"
+                                       'The section parameter must be a valid section id or "new"', 'invalidsection'
                                );
                        }
                } else {
@@ -275,7 +275,7 @@ class ApiParse extends ApiBase {
                $result_array = [];
 
                $result_array['title'] = $titleObj->getPrefixedText();
-               $result_array['pageid'] = $pageid ? $pageid : $pageObj->getId();
+               $result_array['pageid'] = $pageid ?: $pageObj->getId();
 
                if ( !is_null( $oldid ) ) {
                        $result_array['revid'] = intval( $oldid );
@@ -341,8 +341,7 @@ class ApiParse extends ApiBase {
                }
 
                if ( isset( $prop['displaytitle'] ) ) {
-                       $result_array['displaytitle'] = $p_result->getDisplayTitle() ?
-                               $p_result->getDisplayTitle() :
+                       $result_array['displaytitle'] = $p_result->getDisplayTitle() ?:
                                $titleObj->getPrefixedText();
                }
 
@@ -390,9 +389,9 @@ class ApiParse extends ApiBase {
 
                if ( isset( $prop['modules'] ) &&
                        !isset( $prop['jsconfigvars'] ) && !isset( $prop['encodedjsconfigvars'] ) ) {
-                       $this->setWarning( "Property 'modules' was set but not 'jsconfigvars' " .
-                               "or 'encodedjsconfigvars'. Configuration variables are necessary " .
-                               "for proper module usage." );
+                       $this->setWarning( 'Property "modules" was set but not "jsconfigvars" ' .
+                               'or "encodedjsconfigvars". Configuration variables are necessary ' .
+                               'for proper module usage.' );
                }
 
                if ( isset( $prop['indicators'] ) ) {
@@ -428,7 +427,7 @@ class ApiParse extends ApiBase {
 
                if ( isset( $prop['parsetree'] ) || $params['generatexml'] ) {
                        if ( $this->content->getModel() != CONTENT_MODEL_WIKITEXT ) {
-                               $this->dieUsage( "parsetree is only supported for wikitext content", "notwikitext" );
+                               $this->dieUsage( 'parsetree is only supported for wikitext content', 'notwikitext' );
                        }
 
                        $wgParser->startExternalParse( $titleObj, $popts, Parser::OT_PREPROCESS );
@@ -545,10 +544,10 @@ class ApiParse extends ApiBase {
                // Not cached (save or load)
                $section = $content->getSection( $this->section );
                if ( $section === false ) {
-                       $this->dieUsage( "There is no section {$this->section} in " . $what, 'nosuchsection' );
+                       $this->dieUsage( "There is no section {$this->section} in $what", 'nosuchsection' );
                }
                if ( $section === null ) {
-                       $this->dieUsage( "Sections are not supported by " . $what, 'nosuchsection' );
+                       $this->dieUsage( "Sections are not supported by $what", 'nosuchsection' );
                        $section = false;
                }
 
index 58b670a..4336907 100644 (file)
@@ -185,33 +185,6 @@ class ApiQuery extends ApiBase {
                return $this->mPageSet;
        }
 
-       /**
-        * Get the generators array mapping module names to class names
-        * @deprecated since 1.21, list of generators is maintained by ApiPageSet
-        * @return array Array(modulename => classname)
-        */
-       public function getGenerators() {
-               wfDeprecated( __METHOD__, '1.21' );
-               $gens = [];
-               foreach ( $this->mModuleMgr->getNamesWithClasses() as $name => $class ) {
-                       if ( is_subclass_of( $class, 'ApiQueryGeneratorBase' ) ) {
-                               $gens[$name] = $class;
-                       }
-               }
-
-               return $gens;
-       }
-
-       /**
-        * Get whether the specified module is a prop, list or a meta query module
-        * @deprecated since 1.21, use getModuleManager()->getModuleGroup()
-        * @param string $moduleName Name of the module to find type for
-        * @return string|null
-        */
-       function getModuleType( $moduleName ) {
-               return $this->getModuleManager()->getModuleGroup( $moduleName );
-       }
-
        /**
         * @return ApiFormatRaw|null
         */
@@ -451,22 +424,6 @@ class ApiQuery extends ApiBase {
                }
        }
 
-       /**
-        * This method is called by the generator base when generator in the smart-continue
-        * mode tries to set 'query-continue' value. ApiQuery stores those values separately
-        * until the post-processing when it is known if the generation should continue or repeat.
-        * @deprecated since 1.24
-        * @param ApiQueryGeneratorBase $module Generator module
-        * @param string $paramName
-        * @param mixed $paramValue
-        * @return bool True if processed, false if this is a legacy continue
-        */
-       public function setGeneratorContinue( $module, $paramName, $paramValue ) {
-               wfDeprecated( __METHOD__, '1.24' );
-               $this->getContinuationManager()->addGeneratorContinueParam( $module, $paramName, $paramValue );
-               return !$this->getParameter( 'rawcontinue' );
-       }
-
        /**
         * @param ApiPageSet $pageSet Pages to be exported
         * @param ApiResult $result Result to output to
index 94707da..ac90605 100644 (file)
@@ -117,7 +117,7 @@ class ApiQueryAllLinks extends ApiQueryGeneratorBase {
                        if ( $matches ) {
                                $p = $this->getModulePrefix();
                                $this->dieUsage(
-                                       "Cannot use {$p}prop=" . join( '|', array_keys( $matches ) ) . " with {$p}unique",
+                                       "Cannot use {$p}prop=" . implode( '|', array_keys( $matches ) ) . " with {$p}unique",
                                        'params'
                                );
                        }
index 97b122a..fb502e4 100644 (file)
@@ -296,7 +296,7 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase {
                                // Note we must keep the parameters for the first query constant
                                // This may be overridden at a later step
                                $title = $row->{$this->bl_title};
-                               $this->continueStr = join( '|', array_slice( $this->cont, 0, 2 ) ) .
+                               $this->continueStr = implode( '|', array_slice( $this->cont, 0, 2 ) ) .
                                        "|$ns|$title|{$row->from_ns}|{$row->page_id}";
                                break;
                        }
@@ -451,7 +451,7 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase {
                                                [ 'query', $this->getModuleName() ],
                                                $idx, array_diff_key( $arr, [ 'redirlinks' => '' ] ) );
                                        if ( !$fit ) {
-                                               $this->continueStr = join( '|', array_slice( $this->cont, 0, 6 ) ) .
+                                               $this->continueStr = implode( '|', array_slice( $this->cont, 0, 6 ) ) .
                                                        "|$pageID";
                                                break;
                                        }
@@ -474,7 +474,7 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase {
                                                        [ 'query', $this->getModuleName(), $idx, 'redirlinks' ],
                                                        null, $redir );
                                                if ( !$fit ) {
-                                                       $this->continueStr = join( '|', array_slice( $this->cont, 0, 6 ) ) .
+                                                       $this->continueStr = implode( '|', array_slice( $this->cont, 0, 6 ) ) .
                                                                "|$pageID|$key";
                                                        break;
                                                }
index 17b51da..3810e90 100644 (file)
@@ -164,22 +164,14 @@ class ApiQueryBacklinksprop extends ApiQueryGeneratorBase {
                        $this->dieContinueUsageIf( count( $cont ) != count( $sortby ) );
                        $where = '';
                        $i = count( $sortby ) - 1;
-                       $cont_ns = 0;
-                       $cont_title = '';
                        foreach ( array_reverse( $sortby, true ) as $field => $type ) {
                                $v = $cont[$i];
                                switch ( $type ) {
                                        case 'ns':
-                                               $cont_ns = (int)$v;
-                                               /* fall through */
                                        case 'int':
                                                $v = (int)$v;
                                                $this->dieContinueUsageIf( $v != $cont[$i] );
                                                break;
-
-                                       case 'title':
-                                               $cont_title = $v;
-                                               /* fall through */
                                        default:
                                                $v = $db->addQuotes( $v );
                                                break;
@@ -321,7 +313,7 @@ class ApiQueryBacklinksprop extends ApiQueryGeneratorBase {
                foreach ( $sortby as $field => $v ) {
                        $cont[] = $row->$field;
                }
-               $this->setContinueEnumParameter( 'continue', join( '|', $cont ) );
+               $this->setContinueEnumParameter( 'continue', implode( '|', $cont ) );
        }
 
        public function getCacheMode( $params ) {
index 7848bc8..c491236 100644 (file)
@@ -78,7 +78,7 @@ class ApiQueryFileRepoInfo extends ApiQueryBase {
 
                return [
                        'prop' => [
-                               ApiBase::PARAM_DFLT => join( '|', $props ),
+                               ApiBase::PARAM_DFLT => implode( '|', $props ),
                                ApiBase::PARAM_ISMULTI => true,
                                ApiBase::PARAM_TYPE => $props,
                        ],
index 6890046..ab94574 100644 (file)
@@ -308,7 +308,7 @@ class ApiQueryImageInfo extends ApiQueryBase {
 
                foreach ( $paramList as $name => $value ) {
                        if ( !$h->validateParam( $name, $value ) ) {
-                               $this->dieUsage( "Invalid value for {$p}urlparam ($name=$value)", "urlparam" );
+                               $this->dieUsage( "Invalid value for {$p}urlparam ($name=$value)", 'urlparam' );
                        }
                }
 
@@ -357,7 +357,7 @@ class ApiQueryImageInfo extends ApiQueryBase {
         *    'revdelUser': User to use when checking whether to show revision-deleted fields.
         * @return array Result array
         */
-       static function getInfo( $file, $prop, $result, $thumbParams = null, $opts = false ) {
+       public static function getInfo( $file, $prop, $result, $thumbParams = null, $opts = false ) {
                global $wgContLang;
 
                $anyHidden = false;
index c12393d..266d699 100644 (file)
@@ -294,9 +294,9 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
                                        $vals['parsetree'] = $xml;
                                } else {
                                        $vals['badcontentformatforparsetree'] = true;
-                                       $this->setWarning( "Conversion to XML is supported for wikitext only, " .
+                                       $this->setWarning( 'Conversion to XML is supported for wikitext only, ' .
                                                $title->getPrefixedDBkey() .
-                                               " uses content model " . $content->getModel() );
+                                               ' uses content model ' . $content->getModel() );
                                }
                        }
                }
@@ -315,9 +315,9 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
                                                ParserOptions::newFromContext( $this->getContext() )
                                        );
                                } else {
-                                       $this->setWarning( "Template expansion is supported for wikitext only, " .
+                                       $this->setWarning( 'Template expansion is supported for wikitext only, ' .
                                                $title->getPrefixedDBkey() .
-                                               " uses content model " . $content->getModel() );
+                                               ' uses content model ' . $content->getModel() );
                                        $vals['badcontentformat'] = true;
                                        $text = false;
                                }
@@ -332,7 +332,7 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
                        }
 
                        if ( $text === null ) {
-                               $format = $this->contentFormat ? $this->contentFormat : $content->getDefaultFormat();
+                               $format = $this->contentFormat ?: $content->getDefaultFormat();
                                $model = $content->getModel();
 
                                if ( !$content->isSupportedFormat( $format ) ) {
index 4befad6..f05556e 100644 (file)
@@ -652,8 +652,8 @@ class ApiQuerySiteinfo extends ApiQueryBase {
                }
 
                $data = [
-                       'url' => $url ? $url : '',
-                       'text' => $text ? $text : ''
+                       'url' => $url ?: '',
+                       'text' => $text ?: ''
                ];
 
                return $this->getResult()->addValue( 'query', $property, $data );
index 51f4862..6d1540b 100644 (file)
@@ -42,7 +42,7 @@ class ApiQueryStashImageInfo extends ApiQueryImageInfo {
                $result = $this->getResult();
 
                if ( !$params['filekey'] && !$params['sessionkey'] ) {
-                       $this->dieUsage( "One of filekey or sessionkey must be supplied", 'nofilekey' );
+                       $this->dieUsage( 'One of filekey or sessionkey must be supplied', 'nofilekey' );
                }
 
                // Alias sessionkey to filekey, but give an existing filekey precedence.
@@ -62,9 +62,9 @@ class ApiQueryStashImageInfo extends ApiQueryImageInfo {
                        }
                // @todo Update exception handling here to understand current getFile exceptions
                } catch ( UploadStashFileNotFoundException $e ) {
-                       $this->dieUsage( "File not found: " . $e->getMessage(), "invalidsessiondata" );
+                       $this->dieUsage( 'File not found: ' . $e->getMessage(), 'invalidsessiondata' );
                } catch ( UploadStashBadPathException $e ) {
-                       $this->dieUsage( "Bad path: " . $e->getMessage(), "invalidsessiondata" );
+                       $this->dieUsage( 'Bad path: ' . $e->getMessage(), 'invalidsessiondata' );
                }
        }
 
index f70bbe7..3436320 100644 (file)
@@ -312,7 +312,7 @@ class ApiResult implements ApiSerializable {
                        if ( !$conflicts ) {
                                $arr[$name] += $value;
                        } else {
-                               $keys = join( ', ', array_keys( $conflicts ) );
+                               $keys = implode( ', ', array_keys( $conflicts ) );
                                throw new RuntimeException(
                                        "Conflicting keys ($keys) when attempting to merge element $name"
                                );
@@ -340,7 +340,7 @@ class ApiResult implements ApiSerializable {
                                $value = $value->serializeForApiResult();
                                if ( is_object( $value ) ) {
                                        throw new UnexpectedValueException(
-                                               get_class( $oldValue ) . "::serializeForApiResult() returned an object of class " .
+                                               get_class( $oldValue ) . '::serializeForApiResult() returned an object of class ' .
                                                        get_class( $value )
                                        );
                                }
@@ -351,7 +351,7 @@ class ApiResult implements ApiSerializable {
                                        return self::validateValue( $value );
                                } catch ( Exception $ex ) {
                                        throw new UnexpectedValueException(
-                                               get_class( $oldValue ) . "::serializeForApiResult() returned an invalid value: " .
+                                               get_class( $oldValue ) . '::serializeForApiResult() returned an invalid value: ' .
                                                        $ex->getMessage(),
                                                0,
                                                $ex
@@ -372,7 +372,7 @@ class ApiResult implements ApiSerializable {
                        }
                        $value = $tmp;
                } elseif ( is_float( $value ) && !is_finite( $value ) ) {
-                       throw new InvalidArgumentException( "Cannot add non-finite floats to ApiResult" );
+                       throw new InvalidArgumentException( 'Cannot add non-finite floats to ApiResult' );
                } elseif ( is_string( $value ) ) {
                        $value = $wgContLang->normalize( $value );
                } elseif ( $value !== null && !is_scalar( $value ) ) {
@@ -538,7 +538,7 @@ class ApiResult implements ApiSerializable {
                ) {
                        throw new RuntimeException(
                                "Attempting to set content element as $name when " . $arr[self::META_CONTENT] .
-                                       " is already set as the content element"
+                                       ' is already set as the content element'
                        );
                }
                $arr[self::META_CONTENT] = $name;
@@ -1132,12 +1132,12 @@ class ApiResult implements ApiSerializable {
                                                $tmp = [];
                                                return $tmp;
                                        default:
-                                               $fail = join( '.', array_slice( $path, 0, $i + 1 ) );
+                                               $fail = implode( '.', array_slice( $path, 0, $i + 1 ) );
                                                throw new InvalidArgumentException( "Path $fail does not exist" );
                                }
                        }
                        if ( !is_array( $ret[$k] ) ) {
-                               $fail = join( '.', array_slice( $path, 0, $i + 1 ) );
+                               $fail = implode( '.', array_slice( $path, 0, $i + 1 ) );
                                throw new InvalidArgumentException( "Path $fail is not an array" );
                        }
                        $ret = &$ret[$k];
index d8562b0..3c02c9c 100644 (file)
@@ -50,7 +50,7 @@ class ApiStashEdit extends ApiBase {
                if ( !ContentHandler::getForModelID( $params['contentmodel'] )
                        ->isSupportedFormat( $params['contentformat'] )
                ) {
-                       $this->dieUsage( "Unsupported content model/format", 'badmodelformat' );
+                       $this->dieUsage( 'Unsupported content model/format', 'badmodelformat' );
                }
 
                // Trim and fix newlines so the key SHA1's match (see RequestContext::getText())
@@ -77,7 +77,7 @@ class ApiStashEdit extends ApiBase {
                                $baseRev->getId()
                        );
                        if ( !$editContent ) {
-                               $this->dieUsage( "Could not merge updated section.", 'replacefailed' );
+                               $this->dieUsage( 'Could not merge updated section.', 'replacefailed' );
                        }
                        if ( $currentRev->getId() == $baseRev->getId() ) {
                                // Base revision was still the latest; nothing to merge
@@ -433,19 +433,19 @@ class ApiStashEdit extends ApiBase {
                ];
        }
 
-       function needsToken() {
+       public function needsToken() {
                return 'csrf';
        }
 
-       function mustBePosted() {
+       public function mustBePosted() {
                return true;
        }
 
-       function isWriteMode() {
+       public function isWriteMode() {
                return true;
        }
 
-       function isInternal() {
+       public function isInternal() {
                return true;
        }
 }
index 63bae9d..4940394 100644 (file)
@@ -32,9 +32,9 @@ class ApiTokens extends ApiBase {
 
        public function execute() {
                $this->setWarning(
-                       "action=tokens has been deprecated. Please use action=query&meta=tokens instead."
+                       'action=tokens has been deprecated. Please use action=query&meta=tokens instead.'
                );
-               $this->logFeatureUsage( "action=tokens" );
+               $this->logFeatureUsage( 'action=tokens' );
 
                $params = $this->extractRequestParams();
                $res = [
index 79e88c6..326f8ba 100644 (file)
@@ -542,9 +542,9 @@ class ApiUpload extends ApiBase {
                                ];
                                ApiResult::setIndexedTagName( $extradata['allowed'], 'ext' );
 
-                               $msg = "Filetype not permitted: ";
+                               $msg = 'Filetype not permitted: ';
                                if ( isset( $verification['blacklistedExt'] ) ) {
-                                       $msg .= join( ', ', $verification['blacklistedExt'] );
+                                       $msg .= implode( ', ', $verification['blacklistedExt'] );
                                        $extradata['blacklisted'] = array_values( $verification['blacklistedExt'] );
                                        ApiResult::setIndexedTagName( $extradata['blacklisted'], 'ext' );
                                } else {
@@ -664,7 +664,7 @@ class ApiUpload extends ApiBase {
                                $this->dieUsage( 'No such filekey: ' . $e->getMessage(), 'stashnosuchfilekey' );
                                break;
                        default:
-                               $this->dieUsage( $exceptionType . ": " . $e->getMessage(), 'stasherror' );
+                               $this->dieUsage( $exceptionType . ': ' . $e->getMessage(), 'stasherror' );
                                break;
                }
        }
@@ -714,7 +714,7 @@ class ApiUpload extends ApiBase {
                if ( $this->mParams['async'] ) {
                        $progress = UploadBase::getSessionStatus( $this->getUser(), $this->mParams['filekey'] );
                        if ( $progress && $progress['result'] === 'Poll' ) {
-                               $this->dieUsage( "Upload from stash already in progress.", 'publishfailed' );
+                               $this->dieUsage( 'Upload from stash already in progress.', 'publishfailed' );
                        }
                        UploadBase::setSessionStatus(
                                $this->getUser(),
index 4e5e000..f09fdcb 100644 (file)
@@ -80,7 +80,7 @@ class ApiWatch extends ApiBase {
                        if ( $extraParams ) {
                                $p = $this->getModulePrefix();
                                $this->dieUsage(
-                                       "The parameter {$p}title can not be used with " . implode( ", ", $extraParams ),
+                                       "The parameter {$p}title can not be used with " . implode( ', ', $extraParams ),
                                        'invalidparammix'
                                );
                        }
index b9215fc..40d9277 100644 (file)
@@ -161,7 +161,7 @@ class JsonContent extends TextContent {
                        );
                }
                return Html::rawElement( 'table', [ 'class' => 'mw-json' ],
-                       Html::rawElement( 'tbody', [], join( '', $rows ) )
+                       Html::rawElement( 'tbody', [], implode( '', $rows ) )
                );
        }
 
@@ -200,7 +200,7 @@ class JsonContent extends TextContent {
                        );
                }
                return Html::rawElement( 'table', [ 'class' => 'mw-json' ],
-                       Html::rawElement( 'tbody', [], join( "\n", $rows ) )
+                       Html::rawElement( 'tbody', [], implode( "\n", $rows ) )
                );
        }
 
index 7058061..1e27205 100644 (file)
@@ -757,19 +757,13 @@ abstract class DatabaseMysqlBase extends Database {
                return $approxLag;
        }
 
-       /**
-        * Wait for the slave to catch up to a given master position.
-        * @todo Return values for this and base class are rubbish
-        *
-        * @param DBMasterPos|MySQLMasterPos $pos
-        * @param int $timeout The maximum number of seconds to wait for synchronisation
-        * @return int Zero if the slave was past that position already,
-        *   greater than zero if we waited for some period of time, less than
-        *   zero if we timed out.
-        */
        function masterPosWait( DBMasterPos $pos, $timeout ) {
+               if ( !( $pos instanceof MySQLMasterPos ) ) {
+                       throw new InvalidArgumentException( "Position not an instance of MySQLMasterPos" );
+               }
+
                if ( $this->lastKnownSlavePos && $this->lastKnownSlavePos->hasReached( $pos ) ) {
-                       return '0'; // http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html
+                       return 0;
                }
 
                # Commit any open transactions
@@ -778,18 +772,28 @@ abstract class DatabaseMysqlBase extends Database {
                # Call doQuery() directly, to avoid opening a transaction if DBO_TRX is set
                $encFile = $this->addQuotes( $pos->file );
                $encPos = intval( $pos->pos );
-               $sql = "SELECT MASTER_POS_WAIT($encFile, $encPos, $timeout)";
-               $res = $this->doQuery( $sql );
-
-               $status = false;
-               if ( $res ) {
-                       $row = $this->fetchRow( $res );
-                       if ( $row ) {
-                               $status = $row[0]; // can be NULL, -1, or 0+ per the MySQL manual
-                               if ( ctype_digit( $status ) ) { // success
-                                       $this->lastKnownSlavePos = $pos;
-                               }
+               $res = $this->doQuery( "SELECT MASTER_POS_WAIT($encFile, $encPos, $timeout)" );
+
+               $row = $res ? $this->fetchRow( $res ) : false;
+               if ( !$row ) {
+                       throw new DBExpectedError( $this, "Failed to query MASTER_POS_WAIT()" );
+               }
+
+               // Result can be NULL (error), -1 (timeout), or 0+ per the MySQL manual
+               $status = ( $row[0] !== null ) ? intval( $row[0] ) : null;
+               if ( $status === null ) {
+                       // T126436: jobs programmed to wait on master positions might be referencing binlogs
+                       // with an old master hostname. Such calls make MASTER_POS_WAIT() return null. Try
+                       // to detect this and treat the slave as having reached the position; a proper master
+                       // switchover already requires that the new master be caught up before the switch.
+                       $slavePos = $this->getSlavePos();
+                       if ( $slavePos && !$slavePos->channelsMatch( $pos ) ) {
+                               $this->lastKnownSlavePos = $slavePos;
+                               $status = 0;
                        }
+               } elseif ( $status >= 0 ) {
+                       // Remember that this position was reached to save queries next time
+                       $this->lastKnownSlavePos = $pos;
                }
 
                return $status;
@@ -1446,11 +1450,34 @@ class MySQLMasterPos implements DBMasterPos {
                return ( $thisPos && $thatPos && $thisPos >= $thatPos );
        }
 
+       function channelsMatch( DBMasterPos $pos ) {
+               if ( !( $pos instanceof self ) ) {
+                       throw new InvalidArgumentException( "Position not an instance of " . __CLASS__ );
+               }
+
+               $thisBinlog = $this->getBinlogName();
+               $thatBinlog = $pos->getBinlogName();
+
+               return ( $thisBinlog !== false && $thisBinlog === $thatBinlog );
+       }
+
        function __toString() {
                // e.g db1034-bin.000976/843431247
                return "{$this->file}/{$this->pos}";
        }
 
+       /**
+        * @return string|bool
+        */
+       protected function getBinlogName() {
+               $m = [];
+               if ( preg_match( '!^(.+)\.(\d+)/(\d+)$!', (string)$this, $m ) ) {
+                       return $m[1];
+               }
+
+               return false;
+       }
+
        /**
         * @return array|bool (int, int)
         */
index 9b301a9..9e53653 100644 (file)
@@ -618,7 +618,7 @@ class DatabaseOracle extends Database {
 
                $table = $this->tableName( $table );
                // "INSERT INTO tables (a, b, c)"
-               $sql = "INSERT INTO " . $table . " (" . join( ',', array_keys( $row ) ) . ')';
+               $sql = "INSERT INTO " . $table . " (" . implode( ',', array_keys( $row ) ) . ')';
                $sql .= " VALUES (";
 
                // for each value, append ":key"
index 6fa8bf0..b6c37ee 100644 (file)
@@ -332,6 +332,13 @@ interface DBMasterPos {
         */
        public function hasReached( DBMasterPos $pos );
 
+       /**
+        * @param DBMasterPos $pos
+        * @return bool Whether this position appears to be for the same channel as another
+        * @since 1.27
+        */
+       public function channelsMatch( DBMasterPos $pos );
+
        /**
         * @return string
         * @since 1.27
index 7855861..8b1c3df 100644 (file)
@@ -1183,14 +1183,13 @@ interface IDatabase {
        public function wasReadOnlyError();
 
        /**
-        * Wait for the slave to catch up to a given master position.
+        * Wait for the slave to catch up to a given master position
         *
         * @param DBMasterPos $pos
-        * @param int $timeout The maximum number of seconds to wait for
-        *   synchronisation
-        * @return int Zero if the slave was past that position already,
+        * @param int $timeout The maximum number of seconds to wait for synchronisation
+        * @return int|null Zero if the slave was past that position already,
         *   greater than zero if we waited for some period of time, less than
-        *   zero if we timed out.
+        *   zero if it timed out, and null on error
         */
        public function masterPosWait( DBMasterPos $pos, $timeout );
 
index d29cd7d..cc9099c 100644 (file)
@@ -537,7 +537,7 @@ class ForeignAPIRepo extends FileRepo {
         * @since 1.23
         */
        protected static function getIIProps() {
-               return join( '|', self::$imageInfoProps );
+               return implode( '|', self::$imageInfoProps );
        }
 
        /**
index 57eaffe..154f7c3 100644 (file)
@@ -516,7 +516,7 @@ class MysqlUpdater extends DatabaseUpdater {
                                $prev_title = $row->cur_title;
                                $prev_namespace = $row->cur_namespace;
                        }
-                       $sql = "DELETE FROM $cur WHERE cur_id IN ( " . join( ',', $deleteId ) . ')';
+                       $sql = "DELETE FROM $cur WHERE cur_id IN ( " . implode( ',', $deleteId ) . ')';
                        $this->db->query( $sql, __METHOD__ );
                        $this->output( wfTimestamp( TS_DB ) );
                        $this->output( "......<b>Deleted</b> " . $this->db->affectedRows() . " records.\n" );
index aaf9fb0..479ec32 100644 (file)
@@ -452,7 +452,6 @@ class JobQueueDB extends JobQueue {
         * @see JobQueue::doAck()
         * @param Job $job
         * @throws MWException
-        * @return Job|bool
         */
        protected function doAck( Job $job ) {
                if ( !isset( $job->metadata['id'] ) ) {
@@ -476,8 +475,6 @@ class JobQueueDB extends JobQueue {
                } catch ( DBError $e ) {
                        $this->throwDBException( $e );
                }
-
-               return true;
        }
 
        /**
index c127239..bd832db 100644 (file)
@@ -49,7 +49,7 @@
 class JobQueueFederated extends JobQueue {
        /** @var HashRing */
        protected $partitionRing;
-       /** @var array (partition name => JobQueue) reverse sorted by weight */
+       /** @var JobQueue[] (partition name => JobQueue) reverse sorted by weight */
        protected $partitionQueues = [];
 
        /** @var int Maximum number of partitions to try */
@@ -311,7 +311,7 @@ class JobQueueFederated extends JobQueue {
                        throw new MWException( "The given job has no defined partition name." );
                }
 
-               return $this->partitionQueues[$job->metadata['QueuePartition']]->ack( $job );
+               $this->partitionQueues[$job->metadata['QueuePartition']]->ack( $job );
        }
 
        protected function doIsRootJobOldDuplicate( Job $job ) {
index d65e8be..d7ba266 100644 (file)
@@ -4636,7 +4636,7 @@ class Parser {
                        $anchor = $safeHeadline;
                        $legacyAnchor = $legacyHeadline;
                        if ( isset( $refers[$arrayKey] ) ) {
-                               // @codingStandardsIgnoreStart 
+                               // @codingStandardsIgnoreStart
                                for ( $i = 2; isset( $refers["${arrayKey}_$i"] ); ++$i );
                                // @codingStandardsIgnoreEnd
                                $anchor .= "_$i";
@@ -4645,7 +4645,7 @@ class Parser {
                                $refers[$arrayKey] = true;
                        }
                        if ( $legacyHeadline !== false && isset( $refers[$legacyArrayKey] ) ) {
-                               // @codingStandardsIgnoreStart 
+                               // @codingStandardsIgnoreStart
                                for ( $i = 2; isset( $refers["${legacyArrayKey}_$i"] ); ++$i );
                                // @codingStandardsIgnoreEnd
                                $legacyAnchor .= "_$i";
@@ -4793,7 +4793,7 @@ class Parser {
                        $sections[0] = $sections[0] . $toc . "\n";
                }
 
-               $full .= join( '', $sections );
+               $full .= implode( '', $sections );
 
                if ( $this->mForceTocPosition ) {
                        return str_replace( '<!--MWTOC-->', $toc, $full );
index 598702d..5e8fb04 100644 (file)
@@ -160,7 +160,7 @@ class SearchMssql extends SearchDatabase {
                        }
                }
 
-               $searchon = $this->db->addQuotes( join( ',', $q ) );
+               $searchon = $this->db->addQuotes( implode( ',', $q ) );
                $field = $this->getIndexField( $fulltext );
                return "$field, $searchon";
        }
index 70c771d..bbdfdc3 100644 (file)
@@ -120,7 +120,7 @@ class BotPasswordSessionProvider extends ImmutableSessionProviderWithCookie {
                if ( $missingKeys ) {
                        $this->logger->info( 'Session "{session}": Missing metadata: {missing}', [
                                'session' => $info,
-                               'missing' => join( ', ', $missingKeys ),
+                               'missing' => implode( ', ', $missingKeys ),
                        ] );
                        return false;
                }
index 21db609..0fd8fa8 100644 (file)
@@ -352,7 +352,7 @@ final class Session implements \Countable, \Iterator, \ArrayAccess {
                        $new = true;
                }
                if ( is_array( $salt ) ) {
-                       $salt = join( '|', $salt );
+                       $salt = implode( '|', $salt );
                }
                return new Token( $secret, (string)$salt, $new );
        }
index d31e2f1..efa3445 100644 (file)
@@ -287,7 +287,7 @@ final class SessionManager implements SessionManagerInterface {
                // Make sure there's exactly one
                if ( count( $infos ) > 1 ) {
                        throw new \UnexpectedValueException(
-                               'Multiple empty sessions tied for top priority: ' . join( ', ', $infos )
+                               'Multiple empty sessions tied for top priority: ' . implode( ', ', $infos )
                        );
                } elseif ( count( $infos ) < 1 ) {
                        throw new \UnexpectedValueException( 'No provider could provide an empty session!' );
@@ -677,7 +677,7 @@ final class SessionManager implements SessionManagerInterface {
 
                if ( count( $retInfos ) > 1 ) {
                        $ex = new \OverflowException(
-                               'Multiple sessions for this request tied for top priority: ' . join( ', ', $retInfos )
+                               'Multiple sessions for this request tied for top priority: ' . implode( ', ', $retInfos )
                        );
                        $ex->sessionInfos = $retInfos;
                        throw $ex;
index bc2bb31..8ce480e 100644 (file)
@@ -582,31 +582,51 @@ class SpecialPageFactory {
         * @return string HTML fragment
         */
        public static function capturePath( Title $title, IContextSource $context ) {
-               global $wgOut, $wgTitle, $wgRequest, $wgUser, $wgLang;
-
-               // Save current globals
-               $oldTitle = $wgTitle;
-               $oldOut = $wgOut;
-               $oldRequest = $wgRequest;
-               $oldUser = $wgUser;
-               $oldLang = $wgLang;
-
-               // Set the globals to the current context
+               global $wgTitle, $wgOut, $wgRequest, $wgUser, $wgLang;
+               $main = RequestContext::getMain();
+
+               // Save current globals and main context
+               $glob = [
+                       'title' => $wgTitle,
+                       'output' => $wgOut,
+                       'request' => $wgRequest,
+                       'user' => $wgUser,
+                       'language' => $wgLang,
+               ];
+               $ctx = [
+                       'title' => $main->getTitle(),
+                       'output' => $main->getOutput(),
+                       'request' => $main->getRequest(),
+                       'user' => $main->getUser(),
+                       'language' => $main->getLanguage(),
+               ];
+
+               // Override
                $wgTitle = $title;
                $wgOut = $context->getOutput();
                $wgRequest = $context->getRequest();
                $wgUser = $context->getUser();
                $wgLang = $context->getLanguage();
+               $main->setTitle( $title );
+               $main->setOutput( $context->getOutput() );
+               $main->setRequest( $context->getRequest() );
+               $main->setUser( $context->getUser() );
+               $main->setLanguage( $context->getLanguage() );
 
                // The useful part
                $ret = self::executePath( $title, $context, true );
 
-               // And restore the old globals
-               $wgTitle = $oldTitle;
-               $wgOut = $oldOut;
-               $wgRequest = $oldRequest;
-               $wgUser = $oldUser;
-               $wgLang = $oldLang;
+               // Restore old globals and context
+               $wgTitle = $glob['title'];
+               $wgOut = $glob['output'];
+               $wgRequest = $glob['request'];
+               $wgUser = $glob['user'];
+               $wgLang = $glob['language'];
+               $main->setTitle( $ctx['title'] );
+               $main->setOutput( $ctx['output'] );
+               $main->setRequest( $ctx['request'] );
+               $main->setUser( $ctx['user'] );
+               $main->setLanguage( $ctx['language'] );
 
                return $ret;
        }
index 72f8cca..fe1dd98 100644 (file)
@@ -581,7 +581,7 @@ class ImportReporter extends ContextSource {
         * @param array $pageInfo
         * @return void
         */
-       function reportPage( $title, $foreignTitle, $revisionCount,
+       public function reportPage( $title, $foreignTitle, $revisionCount,
                        $successCount, $pageInfo ) {
                $args = func_get_args();
                call_user_func_array( $this->mOriginalPageOutCallback, $args );
index 521e345..617e8f5 100644 (file)
@@ -69,13 +69,13 @@ class MWRestrictions {
                $invalidKeys = array_diff( $keys, $validKeys );
                if ( $invalidKeys ) {
                        throw new InvalidArgumentException(
-                               'Array contains invalid keys: ' . join( ', ', $invalidKeys )
+                               'Array contains invalid keys: ' . implode( ', ', $invalidKeys )
                        );
                }
                $missingKeys = array_diff( $neededKeys, $keys );
                if ( $missingKeys ) {
                        throw new InvalidArgumentException(
-                               'Array is missing required keys: ' . join( ', ', $missingKeys )
+                               'Array is missing required keys: ' . implode( ', ', $missingKeys )
                        );
                }
 
index b36f080..89625c0 100644 (file)
@@ -52,11 +52,11 @@ class LanguageCu extends Language {
                if ( !preg_match( "/[a-zA-Z_]/us", $word ) ) {
                        switch ( $case ) {
                                case 'genitive': # родительный падеж
-                                       if ( ( join( '', array_slice( $ar[0], -4 ) ) == 'вики' )
-                                               || ( join( '', array_slice( $ar[0], -4 ) ) == 'Вики' )
+                                       if ( ( implode( '', array_slice( $ar[0], -4 ) ) == 'вики' )
+                                               || ( implode( '', array_slice( $ar[0], -4 ) ) == 'Вики' )
                                        ) {
-                                       } elseif ( join( '', array_slice( $ar[0], -2 ) ) == 'ї' ) {
-                                               $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'їѩ';
+                                       } elseif ( implode( '', array_slice( $ar[0], -2 ) ) == 'ї' ) {
+                                               $word = implode( '', array_slice( $ar[0], 0, -2 ) ) . 'їѩ';
                                        }
                                        break;
                                case 'accusative': # винительный падеж
index f6d5270..05b0ebe 100644 (file)
@@ -52,12 +52,12 @@ class LanguageHy extends Language {
                if ( !preg_match( "/[a-zA-Z_]/us", $word ) ) {
                        switch ( $case ) {
                                case 'genitive': # սեռական հոլով
-                                       if ( join( '', array_slice( $ar[0], -1 ) ) == 'ա' ) {
-                                               $word = join( '', array_slice( $ar[0], 0, -1 ) ) . 'այի';
-                                       } elseif ( join( '', array_slice( $ar[0], -1 ) ) == 'ո' ) {
-                                               $word = join( '', array_slice( $ar[0], 0, -1 ) ) . 'ոյի';
-                                       } elseif ( join( '', array_slice( $ar[0], -4 ) ) == 'գիրք' ) {
-                                               $word = join( '', array_slice( $ar[0], 0, -4 ) ) . 'գրքի';
+                                       if ( implode( '', array_slice( $ar[0], -1 ) ) == 'ա' ) {
+                                               $word = implode( '', array_slice( $ar[0], 0, -1 ) ) . 'այի';
+                                       } elseif ( implode( '', array_slice( $ar[0], -1 ) ) == 'ո' ) {
+                                               $word = implode( '', array_slice( $ar[0], 0, -1 ) ) . 'ոյի';
+                                       } elseif ( implode( '', array_slice( $ar[0], -4 ) ) == 'գիրք' ) {
+                                               $word = implode( '', array_slice( $ar[0], 0, -4 ) ) . 'գրքի';
                                        } else {
                                                $word .= 'ի';
                                        }
index 6cc23e3..72bde40 100644 (file)
@@ -51,19 +51,19 @@ class LanguageUk extends Language {
                if ( !preg_match( "/[a-zA-Z_]/us", $word ) ) {
                        switch ( $case ) {
                                case 'genitive': # родовий відмінок
-                                       if ( join( '', array_slice( $ar[0], -2 ) ) === 'ія' ) {
-                                               $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'ії';
-                                       } elseif ( join( '', array_slice( $ar[0], -2 ) ) === 'ти' ) {
-                                               $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'т';
-                                       } elseif ( join( '', array_slice( $ar[0], -2 ) ) === 'ди' ) {
-                                               $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'дів';
-                                       } elseif ( join( '', array_slice( $ar[0], -3 ) ) === 'ник' ) {
-                                               $word = join( '', array_slice( $ar[0], 0, -3 ) ) . 'ника';
+                                       if ( implode( '', array_slice( $ar[0], -2 ) ) === 'ія' ) {
+                                               $word = implode( '', array_slice( $ar[0], 0, -2 ) ) . 'ії';
+                                       } elseif ( implode( '', array_slice( $ar[0], -2 ) ) === 'ти' ) {
+                                               $word = implode( '', array_slice( $ar[0], 0, -2 ) ) . 'т';
+                                       } elseif ( implode( '', array_slice( $ar[0], -2 ) ) === 'ди' ) {
+                                               $word = implode( '', array_slice( $ar[0], 0, -2 ) ) . 'дів';
+                                       } elseif ( implode( '', array_slice( $ar[0], -3 ) ) === 'ник' ) {
+                                               $word = implode( '', array_slice( $ar[0], 0, -3 ) ) . 'ника';
                                        }
                                        break;
                                case 'accusative': # знахідний відмінок
-                                       if ( join( '', array_slice( $ar[0], -2 ) ) === 'ія' ) {
-                                               $word = join( '', array_slice( $ar[0], 0, -2 ) ) . 'ію';
+                                       if ( implode( '', array_slice( $ar[0], -2 ) ) === 'ія' ) {
+                                               $word = implode( '', array_slice( $ar[0], 0, -2 ) ) . 'ію';
                                        }
                                        break;
                        }
index 8651a68..5fab082 100644 (file)
@@ -87,7 +87,7 @@ abstract class Benchmarker extends Maintenance {
                        $ret .= sprintf( "%s times: function %s(%s) :\n",
                                $res['count'],
                                $res['function'],
-                               join( ', ', $res['arguments'] )
+                               implode( ', ', $res['arguments'] )
                        );
                        $ret .= sprintf( "   %6.2fms (%6.2fms each)\n",
                                $res['delta'] * 1000,
index 6bc9a6a..3c679e6 100644 (file)
@@ -53,7 +53,7 @@ class GetConfiguration extends Maintenance {
                $this->addOption( 'regex', 'regex to filter variables with', false, true );
                $this->addOption( 'iregex', 'same as --regex but case insensitive', false, true );
                $this->addOption( 'settings', 'Space-separated list of wg* variables', false, true );
-               $this->addOption( 'format', join( ', ', self::$outFormats ), false, true );
+               $this->addOption( 'format', implode( ', ', self::$outFormats ), false, true );
        }
 
        protected function validateParamsAndArgs() {
index 62e175b..78cb7fb 100644 (file)
@@ -230,7 +230,7 @@ class RandomImageGenerator {
                        $points[] = $point['x'] . ',' . $point['y'];
                }
 
-               return join( " ", $points );
+               return implode( " ", $points );
        }
 
        /**
@@ -425,7 +425,7 @@ class RandomImageGenerator {
                        $components[] = mt_rand( 0, 255 );
                }
 
-               return 'rgb(' . join( ', ', $components ) . ')';
+               return 'rgb(' . implode( ', ', $components ) . ')';
        }
 
        /**
index 8e8002c..168b2c6 100644 (file)
@@ -247,14 +247,64 @@ class DatabaseMysqlBaseTest extends MediaWikiTestCase {
                ];
        }
 
-       function testMasterPos() {
-               $pos1 = new MySQLMasterPos( 'db1034-bin.000976', '843431247' );
-               $pos2 = new MySQLMasterPos( 'db1034-bin.000976', '843431248' );
-
-               $this->assertTrue( $pos1->hasReached( $pos1 ) );
-               $this->assertTrue( $pos2->hasReached( $pos2 ) );
-               $this->assertTrue( $pos2->hasReached( $pos1 ) );
-               $this->assertFalse( $pos1->hasReached( $pos2 ) );
+       /**
+        * @dataProvider provideComparePositions
+        */
+       function testHasReached( MySQLMasterPos $lowerPos, MySQLMasterPos $higherPos ) {
+               $this->assertTrue( $higherPos->hasReached( $lowerPos ) );
+               $this->assertTrue( $higherPos->hasReached( $higherPos ) );
+               $this->assertTrue( $lowerPos->hasReached( $lowerPos ) );
+               $this->assertFalse( $lowerPos->hasReached( $higherPos ) );
+       }
+
+       function provideComparePositions() {
+               return [
+                       [
+                               new MySQLMasterPos( 'db1034-bin.000976', '843431247' ),
+                               new MySQLMasterPos( 'db1034-bin.000976', '843431248' )
+                       ],
+                       [
+                               new MySQLMasterPos( 'db1034-bin.000976', '999' ),
+                               new MySQLMasterPos( 'db1034-bin.000976', '1000' )
+                       ],
+                       [
+                               new MySQLMasterPos( 'db1034-bin.000976', '999' ),
+                               new MySQLMasterPos( 'db1035-bin.000976', '1000' )
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideChannelPositions
+        */
+       function testChannelsMatch( MySQLMasterPos $pos1, MySQLMasterPos $pos2, $matches ) {
+               $this->assertEquals( $matches, $pos1->channelsMatch( $pos2 ) );
+               $this->assertEquals( $matches, $pos2->channelsMatch( $pos1 ) );
+       }
+
+       function provideChannelPositions() {
+               return [
+                       [
+                               new MySQLMasterPos( 'db1034-bin.000876', '44' ),
+                               new MySQLMasterPos( 'db1034-bin.000976', '74' ),
+                               true
+                       ],
+                       [
+                               new MySQLMasterPos( 'db1052-bin.000976', '999' ),
+                               new MySQLMasterPos( 'db1052-bin.000976', '1000' ),
+                               true
+                       ],
+                       [
+                               new MySQLMasterPos( 'db1066-bin.000976', '9999' ),
+                               new MySQLMasterPos( 'db1035-bin.000976', '10000' ),
+                               false
+                       ],
+                       [
+                               new MySQLMasterPos( 'db1066-bin.000976', '9999' ),
+                               new MySQLMasterPos( 'trump2016.000976', '10000' ),
+                               false
+                       ],
+               ];
        }
 
        /**
index 519c8c3..6eb96b1 100644 (file)
@@ -4,7 +4,7 @@
  * in an instance property rather than APC.
  */
 class ArrayBackedMemoizedCallable extends MemoizedCallable {
-       public $cache = [];
+       private $cache = [];
 
        protected function fetchResult( $key, &$success ) {
                if ( array_key_exists( $key, $this->cache ) ) {
@@ -112,6 +112,11 @@ class MemoizedCallableTest extends PHPUnit_Framework_TestCase {
                        $this->readAttribute( $a, 'callableName' ),
                        $this->readAttribute( $b, 'callableName' )
                );
+
+               $c = new ArrayBackedMemoizedCallable( function () {
+                       return rand();
+               } );
+               $this->assertEquals( $c->invokeArgs(), $c->invokeArgs(), 'memoized random' );
        }
 
        /**
index b50fe80..dfa92f1 100644 (file)
@@ -137,5 +137,5 @@ class WebPHandlerTest extends MediaWikiTestCase {
 }
 
 /* Python code to extract a header and convert to PHP format:
- * print '"%s"' % ''.join( '\\x%02X' % ord(c) for c in urllib.urlopen(url).read(36) )
+ * print '"%s"' % ''.implode( '\\x%02X' % ord(c) for c in urllib.urlopen(url).read(36) )
  */
index 998d2bb..534cf9b 100644 (file)
@@ -171,7 +171,7 @@ class SpecialPageFactoryTest extends MediaWikiTestCase {
                $gotWarnings = count( $warnings );
                if ( $gotWarnings !== $expectWarnings ) {
                        $this->fail( "Expected $expectWarnings warning(s), but got $gotWarnings:\n" .
-                               join( "\n", $warnings )
+                               implode( "\n", $warnings )
                        );
                }
        }
index b9cb6c1..542420a 100644 (file)
@@ -153,7 +153,7 @@ class ApiDocumentationTest extends MediaWikiTestCase {
                                foreach ( $globals as $k => $v ) {
                                        $g[] = "$k=" . var_export( $v, 1 );
                                }
-                               $k = "Module $path with " . join( ', ', $g );
+                               $k = "Module $path with " . implode( ', ', $g );
                                $ret[$k] = [ $path, $globals ];
                        }
                }
index 456787c..5a96dc3 100644 (file)
@@ -110,7 +110,7 @@ class GenerateJqueryMsgData extends Maintenance {
                                        $langKey = $languageCode . '_' . $key;
                                        $messages[$langKey] = $template;
                                        $tests[] = [
-                                               'name' => $languageCode . ' ' . $key . ' ' . join( ',', $args ),
+                                               'name' => $languageCode . ' ' . $key . ' ' . implode( ',', $args ),
                                                'key' => $langKey,
                                                'args' => $args,
                                                'result' => $result,