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).
/**
* 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
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
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;
+ }
}
/**
$qs = $k;
$msg = self::escapeWikiText( $v );
if ( is_array( $msg ) ) {
- $msg = join( " ", $msg );
+ $msg = join( ' ', $msg );
}
}
$p = $this->getModulePrefix();
$intersection = array_intersect( array_keys( array_filter( $params,
- [ $this, "parameterNotEmpty" ] ) ), $required );
+ [ $this, 'parameterNotEmpty' ] ) ), $required );
if ( count( $intersection ) > 1 ) {
$this->dieUsage(
$p = $this->getModulePrefix();
$intersection = array_intersect( array_keys( array_filter( $params,
- [ $this, "parameterNotEmpty" ] ) ), $required );
+ [ $this, 'parameterNotEmpty' ] ) ), $required );
if ( count( $intersection ) > 1 ) {
$this->dieUsage(
$p = $this->getModulePrefix();
$intersection = array_intersect(
- array_keys( array_filter( $params, [ $this, "parameterNotEmpty" ] ) ),
+ array_keys( array_filter( $params, [ $this, 'parameterNotEmpty' ] ) ),
$required
);
ApiBase::dieDebug(
__METHOD__,
"Boolean param $encParamName's default is set to '$default'. " .
- "Boolean parameters must default to false."
+ 'Boolean parameters must default to false.'
);
}
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}"
);
}
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(
],
'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',
],
'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
],
'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"
],
'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',
],
'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',
],
// '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',
],
'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',
],
'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',
// 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',
],
'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',
],
'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',
'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',
// 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'
$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' );
}
);
$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" );
}
}
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 ) {
if ( $m ) {
$msgs[$param][] = $m;
} else {
- $this->dieDebug( __METHOD__,
+ self::dieDebug( __METHOD__,
'Value in ApiBase::PARAM_HELP_MSG_APPEND is not valid' );
}
}
$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";
} else {
$msgExample = " $v";
}
- $msgExample .= ":";
+ $msgExample .= ':';
$msg .= wordwrap( $msgExample, 100, "\n" ) . "\n $k\n";
}
}
* @return string
*/
private function indentExampleText( $item ) {
- return " " . $item;
+ return ' ' . $item;
}
/**
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] )
}
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;
}
}
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)';
}
}
}
$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'
!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.' );
}
}
}
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 '';
* 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;
}
);
}
- function addXslt() {
+ protected function addXslt() {
$nt = Title::newFromText( $this->mXslt );
if ( is_null( $nt ) || !$nt->exists() ) {
$this->setWarning( 'Invalid or non-existent stylesheet specified' );
$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(
* @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 = [];
parent::reportPage( $title, $origTitle, $revisionCount, $successCount, $pageInfo );
}
- function getData() {
+ public function getData() {
return $this->mResultArr;
}
}
case LoginForm::THROTTLED:
$result['result'] = 'Throttled';
- $throttle = $this->getConfig()->get( 'PasswordAttemptThrottle' );
$result['wait'] = intval( $loginForm->mThrottleWait );
break;
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() ) {
$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'
);
}
->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";
}
$ns = implode( '|', SearchEngine::defaultNamespaces() );
if ( !$ns ) {
- $ns = "0";
+ $ns = '0';
}
switch ( $type ) {
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 ) {
'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() );
}
$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 {
$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 );
}
if ( isset( $prop['displaytitle'] ) ) {
- $result_array['displaytitle'] = $p_result->getDisplayTitle() ?
- $p_result->getDisplayTitle() :
+ $result_array['displaytitle'] = $p_result->getDisplayTitle() ?:
$titleObj->getPrefixedText();
}
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'] ) ) {
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 );
// 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;
}
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
*/
}
}
- /**
- * 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
$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;
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' );
}
}
* '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;
$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() );
}
}
}
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;
}
}
if ( $text === null ) {
- $format = $this->contentFormat ? $this->contentFormat : $content->getDefaultFormat();
+ $format = $this->contentFormat ?: $content->getDefaultFormat();
$model = $content->getModel();
if ( !$content->isSupportedFormat( $format ) ) {
}
$data = [
- 'url' => $url ? $url : '',
- 'text' => $text ? $text : ''
+ 'url' => $url ?: '',
+ 'text' => $text ?: ''
];
return $this->getResult()->addValue( 'query', $property, $data );
$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.
}
// @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' );
}
}
$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 )
);
}
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
}
$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 ) ) {
) {
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;
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())
$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
];
}
- 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;
}
}
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 = [
];
ApiResult::setIndexedTagName( $extradata['allowed'], 'ext' );
- $msg = "Filetype not permitted: ";
+ $msg = 'Filetype not permitted: ';
if ( isset( $verification['blacklistedExt'] ) ) {
$msg .= join( ', ', $verification['blacklistedExt'] );
$extradata['blacklisted'] = array_values( $verification['blacklistedExt'] );
$this->dieUsage( 'No such filekey: ' . $e->getMessage(), 'stashnosuchfilekey' );
break;
default:
- $this->dieUsage( $exceptionType . ": " . $e->getMessage(), 'stasherror' );
+ $this->dieUsage( $exceptionType . ': ' . $e->getMessage(), 'stasherror' );
break;
}
}
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(),
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'
);
}
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
# 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;
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)
*/
*/
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
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 );
* @see JobQueue::doAck()
* @param Job $job
* @throws MWException
- * @return Job|bool
*/
protected function doAck( Job $job ) {
if ( !isset( $job->metadata['id'] ) ) {
} catch ( DBError $e ) {
$this->throwDBException( $e );
}
-
- return true;
}
/**
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 */
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 ) {
* @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;
}
* @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 );
];
}
- 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
+ ],
+ ];
}
/**
* 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 ) ) {
$this->readAttribute( $a, 'callableName' ),
$this->readAttribute( $b, 'callableName' )
);
+
+ $c = new ArrayBackedMemoizedCallable( function () {
+ return rand();
+ } );
+ $this->assertEquals( $c->invokeArgs(), $c->invokeArgs(), 'memoized random' );
}
/**