$this->mAuto = $auto;
$this->isHardblock( !$anonOnly );
$this->prevents( 'createaccount', $createAccount );
- if ( $expiry == 'infinity' || $expiry == wfGetDB( DB_SLAVE )->getInfinity() ) {
- $this->mExpiry = 'infinity';
- } else {
- $this->mExpiry = wfTimestamp( TS_MW, $expiry );
- }
+ $this->mExpiry = wfGetDB( DB_SLAVE )->decodeExpiry( $expiry );
$this->isAutoblocking( $enableAutoblock );
$this->mHideName = $hideName;
$this->prevents( 'sendemail', $blockEmail );
$this->mParentBlockId = $row->ipb_parent_block_id;
// I wish I didn't have to do this
- $db = wfGetDB( DB_SLAVE );
- if ( $row->ipb_expiry == $db->getInfinity() ) {
- $this->mExpiry = 'infinity';
- } else {
- $this->mExpiry = wfTimestamp( TS_MW, $row->ipb_expiry );
- }
+ $this->mExpiry = wfGetDB( DB_SLAVE )->decodeExpiry( $row->ipb_expiry );
$this->isHardblock( !$row->ipb_anon_only );
$this->isAutoblocking( $row->ipb_enable_autoblock );
$dbw = wfGetDB( DB_MASTER );
}
- # Don't collide with expired blocks
- Block::purgeExpired();
+ # Periodic purge via commit hooks
+ if ( mt_rand( 0, 9 ) == 0 ) {
+ Block::purgeExpired();
+ }
$row = $this->getDatabaseArray();
$row['ipb_id'] = $dbw->nextSequenceValue( "ipblocks_ipb_id_seq" );
- $dbw->insert(
- 'ipblocks',
- $row,
- __METHOD__,
- array( 'IGNORE' )
- );
+ $dbw->insert( 'ipblocks', $row, __METHOD__, array( 'IGNORE' ) );
$affected = $dbw->affectedRows();
+
+ # Don't collide with expired blocks.
+ # Do this after trying to insert to avoid pointless gap locks.
+ if ( !$affected ) {
+ $dbw->delete( 'ipblocks',
+ array(
+ 'ipb_address' => $row['ipb_address'],
+ 'ipb_user' => $row['ipb_user'],
+ 'ipb_expiry < ' . $dbw->addQuotes( $dbw->timestamp() )
+ ),
+ __METHOD__
+ );
+
+ $dbw->insert( 'ipblocks', $row, __METHOD__, array( 'IGNORE' ) );
+ $affected = $dbw->affectedRows();
+ }
+
$this->mId = $dbw->insertId();
if ( $affected ) {
* however, it does so inefficiently.
* @note Consider using a TitleValue object instead. TitleValue is more lightweight
* and does not rely on global state or the database.
- *
- * @internal documentation reviewed 15 Mar 2010
*/
class Title {
/** @var MapCacheLRU */
* by a prefix. If you want to force a specific namespace even if
* $text might begin with a namespace prefix, use makeTitle() or
* makeTitleSafe().
- * @throws MWException
+ * @throws InvalidArgumentException
* @return Title|null Title or null on an error.
*/
public static function newFromText( $text, $defaultNamespace = NS_MAIN ) {
if ( is_object( $text ) ) {
- throw new MWException( 'Title::newFromText given an object' );
+ throw new InvalidArgumentException( '$text must be a string.' );
+ } elseif ( !is_string( $text ) ) {
+ wfWarn( __METHOD__ . ': $text must be a string. This will throw an InvalidArgumentException in future.', 2 );
}
$cache = self::getTitleCache();
if ( $row['permission'] == 'autoconfirmed' ) {
$row['permission'] = 'editsemiprotected'; // B/C
}
+ $row['expiry'] = $dbr->decodeExpiry( $row['expiry'] );
}
$this->mTitleProtection = $row;
}
* false.
*/
public function getCascadeProtectionSources( $getPages = true ) {
- global $wgContLang;
$pagerestrictions = array();
if ( $this->mCascadeSources !== null && $getPages ) {
$now = wfTimestampNow();
foreach ( $res as $row ) {
- $expiry = $wgContLang->formatExpiry( $row->pr_expiry, TS_MW );
+ $expiry = $dbr->decodeExpiry( $row->pr_expiry );
if ( $expiry > $now ) {
if ( $getPages ) {
$page_id = $row->pr_page;
* restrictions from page table (pre 1.10)
*/
public function loadRestrictionsFromRows( $rows, $oldFashionedRestrictions = null ) {
- global $wgContLang;
$dbr = wfGetDB( DB_SLAVE );
$restrictionTypes = $this->getRestrictionTypes();
foreach ( $restrictionTypes as $type ) {
$this->mRestrictions[$type] = array();
- $this->mRestrictionsExpiry[$type] = $wgContLang->formatExpiry( '', TS_MW );
+ $this->mRestrictionsExpiry[$type] = 'infinity';
}
$this->mCascadeRestriction = false;
// This code should be refactored, now that it's being used more generally,
// But I don't really see any harm in leaving it in Block for now -werdna
- $expiry = $wgContLang->formatExpiry( $row->pr_expiry, TS_MW );
+ $expiry = $dbr->decodeExpiry( $row->pr_expiry );
// Only apply the restrictions if they haven't expired!
if ( !$expiry || $expiry > $now ) {
* restrictions from page table (pre 1.10)
*/
public function loadRestrictions( $oldFashionedRestrictions = null ) {
- global $wgContLang;
if ( !$this->mRestrictionsLoaded ) {
+ $dbr = wfGetDB( DB_SLAVE );
if ( $this->exists() ) {
- $dbr = wfGetDB( DB_SLAVE );
-
$res = $dbr->select(
'page_restrictions',
array( 'pr_type', 'pr_expiry', 'pr_level', 'pr_cascade' ),
if ( $title_protection ) {
$now = wfTimestampNow();
- $expiry = $wgContLang->formatExpiry( $title_protection['expiry'], TS_MW );
+ $expiry = $dbr->decodeExpiry( $title_protection['expiry'] );
if ( !$expiry || $expiry > $now ) {
// Apply the restrictions
$this->mTitleProtection = false;
}
} else {
- $this->mRestrictionsExpiry['create'] = $wgContLang->formatExpiry( '', TS_MW );
+ $this->mRestrictionsExpiry['create'] = 'infinity';
}
$this->mRestrictionsLoaded = true;
}
public function getEditNotices( $oldid = 0 ) {
$notices = array();
- # Optional notices on a per-namespace and per-page basis
+ // Optional notice for the entire namespace
$editnotice_ns = 'editnotice-' . $this->getNamespace();
- $editnotice_ns_message = wfMessage( $editnotice_ns );
- if ( $editnotice_ns_message->exists() ) {
- $notices[$editnotice_ns] = '<div class="mw-editnotice mw-editnotice-namespace ' .
- Sanitizer::escapeClass( "mw-$editnotice_ns" ) . '">' .
- $editnotice_ns_message->parseAsBlock() . '</div>';
+ $msg = wfMessage( $editnotice_ns );
+ if ( $msg->exists() ) {
+ $html = $msg->parseAsBlock();
+ // Edit notices may have complex logic, but output nothing (T91715)
+ if ( trim( $html ) !== '' ) {
+ $notices[$editnotice_ns] = Html::rawElement(
+ 'div',
+ array( 'class' => array(
+ 'mw-editnotice',
+ 'mw-editnotice-namespace',
+ Sanitizer::escapeClass( "mw-$editnotice_ns" )
+ ) ),
+ $html
+ );
+ }
}
+
if ( MWNamespace::hasSubpages( $this->getNamespace() ) ) {
+ // Optional notice for page itself and any parent page
$parts = explode( '/', $this->getDBkey() );
$editnotice_base = $editnotice_ns;
while ( count( $parts ) > 0 ) {
$editnotice_base .= '-' . array_shift( $parts );
- $editnotice_base_msg = wfMessage( $editnotice_base );
- if ( $editnotice_base_msg->exists() ) {
- $notices[$editnotice_base] = '<div class="mw-editnotice mw-editnotice-base ' .
- Sanitizer::escapeClass( "mw-$editnotice_base" ) . '">' .
- $editnotice_base_msg->parseAsBlock() . '</div>';
+ $msg = wfMessage( $editnotice_base );
+ if ( $msg->exists() ) {
+ $html = $msg->parseAsBlock();
+ if ( trim( $html ) !== '' ) {
+ $notices[$editnotice_base] = Html::rawElement(
+ 'div',
+ array( 'class' => array(
+ 'mw-editnotice',
+ 'mw-editnotice-base',
+ Sanitizer::escapeClass( "mw-$editnotice_base" )
+ ) ),
+ $html
+ );
+ }
}
}
} else {
- # Even if there are no subpages in namespace, we still don't want / in MW ns.
+ // Even if there are no subpages in namespace, we still don't want "/" in MediaWiki message keys
$editnoticeText = $editnotice_ns . '-' . str_replace( '/', '-', $this->getDBkey() );
- $editnoticeMsg = wfMessage( $editnoticeText );
- if ( $editnoticeMsg->exists() ) {
- $notices[$editnoticeText] = '<div class="mw-editnotice mw-editnotice-page ' .
- Sanitizer::escapeClass( "mw-$editnoticeText" ) . '">' .
- $editnoticeMsg->parseAsBlock() . '</div>';
+ $msg = wfMessage( $editnoticeText );
+ if ( $msg->exists() ) {
+ $html = $msg->parseAsBlock();
+ if ( trim( $html ) !== '' ) {
+ $notices[$editnoticeText] = Html::rawElement(
+ 'div',
+ array( 'class' => array(
+ 'mw-editnotice',
+ 'mw-editnotice-page',
+ Sanitizer::escapeClass( "mw-$editnoticeText" )
+ ) ),
+ $html
+ );
+ }
}
}
$vals2['flags'] = isset( $params[$flagsKey] ) ? $params[$flagsKey] : '';
// Indefinite blocks have no expiry time
- if ( SpecialBlock::parseExpiryInput( $params[$durationKey] ) !== wfGetDB( DB_SLAVE )->getInfinity() ) {
+ if ( SpecialBlock::parseExpiryInput( $params[$durationKey] ) !== 'infinity' ) {
$vals2['expiry'] = wfTimestamp( TS_ISO_8601,
strtotime( $params[$durationKey], wfTimestamp( TS_UNIX, $ts ) ) );
}
unset( $params[$idsKey] );
}
if ( isset( $params[$ofieldKey] ) ) {
- $params[] = $params[$ofieldKey];
+ $params[] = 'ofield=' . $params[$ofieldKey];
unset( $params[$ofieldKey] );
}
if ( isset( $params[$nfieldKey] ) ) {
- $params[] = $params[$nfieldKey];
+ $params[] = 'nfield=' . $params[$nfieldKey];
unset( $params[$nfieldKey] );
}
}
* @throws DBQueryError
*/
public function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false ) {
- # Ignore errors during error handling to avoid infinite recursion
- $ignore = $this->ignoreErrors( true );
++$this->mErrorCount;
- if ( $ignore || $tempIgnore ) {
+ if ( $this->ignoreErrors() || $tempIgnore ) {
wfDebug( "SQL ERROR (ignored): $error\n" );
- $this->ignoreErrors( $ignore );
} else {
$sql1line = mb_substr( str_replace( "\n", "\\n", $sql ), 0, 5 * 1024 );
wfLogDBError(
* @return bool
*/
public function deadlockLoop() {
- $this->begin( __METHOD__ );
$args = func_get_args();
$function = array_shift( $args );
- $oldIgnore = $this->ignoreErrors( true );
$tries = self::DEADLOCK_TRIES;
-
if ( is_array( $function ) ) {
$fname = $function[0];
} else {
$fname = $function;
}
- do {
- $retVal = call_user_func_array( $function, $args );
- $error = $this->lastError();
- $errno = $this->lastErrno();
- $sql = $this->lastQuery();
+ $this->begin( __METHOD__ );
- if ( $errno ) {
+ $e = null;
+ do {
+ try {
+ $retVal = call_user_func_array( $function, $args );
+ break;
+ } catch ( DBQueryError $e ) {
+ $error = $this->lastError();
+ $errno = $this->lastErrno();
+ $sql = $this->lastQuery();
if ( $this->wasDeadlock() ) {
- # Retry
+ // Retry after a randomized delay
usleep( mt_rand( self::DEADLOCK_DELAY_MIN, self::DEADLOCK_DELAY_MAX ) );
} else {
- $this->reportQueryError( $error, $errno, $sql, $fname );
+ // Throw the error back up
+ throw $e;
}
}
- } while ( $this->wasDeadlock() && --$tries > 0 );
-
- $this->ignoreErrors( $oldIgnore );
+ } while ( --$tries > 0 );
if ( $tries <= 0 ) {
+ // Too many deadlocks; give up
$this->rollback( __METHOD__ );
- $this->reportQueryError( $error, $errno, $sql, $fname );
-
- return false;
+ throw $e;
} else {
$this->commit( __METHOD__ );
if ( !$this->mTrxLevel ) {
$this->begin( $fname );
$this->mTrxAutomatic = true;
- $this->mTrxAutomaticAtomic = true;
+ // If DBO_TRX is set, a series of startAtomic/endAtomic pairs will result
+ // in all changes being in one transaction to keep requests transactional.
+ if ( !$this->getFlag( DBO_TRX ) ) {
+ $this->mTrxAutomaticAtomic = true;
+ }
}
$this->mTrxAtomicLevels->push( $fname );
$this->runOnTransactionPreCommitCallbacks();
$this->doCommit( $fname );
if ( $this->mTrxDoneWrites ) {
+ $this->mDoneWrites = microtime( true );
$this->getTransactionProfiler()->transactionWritingOut(
$this->mServer, $this->mDBname, $this->mTrxShortId );
}
$this->runOnTransactionPreCommitCallbacks();
$this->doCommit( $fname );
if ( $this->mTrxDoneWrites ) {
+ $this->mDoneWrites = microtime( true );
$this->getTransactionProfiler()->transactionWritingOut(
$this->mServer, $this->mDBname, $this->mTrxShortId );
}
* @return string
*/
public function decodeExpiry( $expiry, $format = TS_MW ) {
- return ( $expiry == '' || $expiry == $this->getInfinity() )
+ return ( $expiry == '' || $expiry == 'infinity' || $expiry == $this->getInfinity() )
? 'infinity'
: wfTimestamp( $format, $expiry );
}
*
* Some fields are public only for backwards-compatibility. Use accessors.
* In the past, this class was part of Article.php and everything was public.
- *
- * @internal documentation reviewed 15 Mar 2010
*/
class WikiPage implements Page, IDBAccessObject {
// Constants for $mDataLoadedFrom and related
$data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle );
} elseif ( $from === self::READ_NORMAL ) {
$data = $this->pageDataFromTitle( wfGetDB( DB_SLAVE ), $this->mTitle );
- // Use a "last rev inserted" timestamp key to diminish the issue of slave lag.
- // Note that DB also stores the master position in the session and checks it.
- $touched = $this->getCachedLastEditTime();
- if ( $touched ) { // key set
- if ( !$data || $touched > wfTimestamp( TS_MW, $data->page_touched ) ) {
- $from = self::READ_LATEST;
- $data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle );
- }
+ if ( !$data
+ && wfGetLB()->getServerCount() > 1
+ && wfGetLB()->hasOrMadeRecentMasterChanges()
+ ) {
+ $from = self::READ_LATEST;
+ $data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle );
}
} else {
// No idea from where the caller got this data, assume slave database.
return; // page doesn't exist or is missing page_latest info
}
- // Bug 37225: if session S1 loads the page row FOR UPDATE, the result always includes the
- // latest changes committed. This is true even within REPEATABLE-READ transactions, where
- // S1 normally only sees changes committed before the first S1 SELECT. Thus we need S1 to
- // also gets the revision row FOR UPDATE; otherwise, it may not find it since a page row
- // UPDATE and revision row INSERT by S2 may have happened after the first S1 SELECT.
- // http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html#isolevel_repeatable-read.
- $flags = ( $this->mDataLoadedFrom == self::READ_LOCKING ) ? Revision::READ_LOCKING : 0;
+ if ( $this->mDataLoadedFrom == self::READ_LOCKING ) {
+ // Bug 37225: if session S1 loads the page row FOR UPDATE, the result always
+ // includes the latest changes committed. This is true even within REPEATABLE-READ
+ // transactions, where S1 normally only sees changes committed before the first S1
+ // SELECT. Thus we need S1 to also gets the revision row FOR UPDATE; otherwise, it
+ // may not find it since a page row UPDATE and revision row INSERT by S2 may have
+ // happened after the first S1 SELECT.
+ // http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html#isolevel_repeatable-read.
+ $flags = Revision::READ_LOCKING;
+ } elseif ( $this->mDataLoadedFrom == self::READ_LATEST ) {
+ // Bug T93976: if page_latest was loaded from the master, fetch the
+ // revision from there as well, as it may not exist yet on a slave DB.
+ // Also, this keeps the queries in the same REPEATABLE-READ snapshot.
+ $flags = Revision::READ_LATEST;
+ } else {
+ $flags = 0;
+ }
$revision = Revision::newFromPageId( $this->getId(), $latest, $flags );
if ( $revision ) { // sanity
$this->setLastEdit( $revision );
}
}
- /**
- * Get the cached timestamp for the last time the page changed.
- * This is only used to help handle slave lag by comparing to page_touched.
- * @return string MW timestamp
- */
- protected function getCachedLastEditTime() {
- global $wgMemc;
- $key = wfMemcKey( 'page-lastedit', md5( $this->mTitle->getPrefixedDBkey() ) );
- return $wgMemc->get( $key );
- }
-
- /**
- * Set the cached timestamp for the last time the page changed.
- * This is only used to help handle slave lag by comparing to page_touched.
- * @param string $timestamp
- * @return void
- */
- public function setCachedLastEditTime( $timestamp ) {
- global $wgMemc;
- $key = wfMemcKey( 'page-lastedit', md5( $this->mTitle->getPrefixedDBkey() ) );
- $wgMemc->set( $key, wfTimestamp( TS_MW, $timestamp ), 60 * 15 );
- }
-
/**
* Determine whether a page would be suitable for being counted as an
* article in the site_stats table based on the title & its content
* @return bool
*/
public function doPurge() {
- global $wgUseSquid;
-
if ( !Hooks::run( 'ArticlePurge', array( &$this ) ) ) {
return false;
}
- // Invalidate the cache
- $this->mTitle->invalidateCache();
-
- if ( $wgUseSquid ) {
- // Commit the transaction before the purge is sent
- $dbw = wfGetDB( DB_MASTER );
- $dbw->commit( __METHOD__ );
-
- // Send purge
- $update = SquidUpdate::newSimplePurge( $this->mTitle );
- $update->doUpdate();
- }
+ $title = $this->mTitle;
+ wfGetDB( DB_MASTER )->onTransactionIdle( function() use ( $title ) {
+ global $wgUseSquid;
+ // Invalidate the cache in auto-commit mode
+ $title->invalidateCache();
+ if ( $wgUseSquid ) {
+ // Send purge now that page_touched update was committed above
+ $update = SquidUpdate::newSimplePurge( $title );
+ $update->doUpdate();
+ }
+ } );
if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) {
// @todo move this logic to MessageCache
-
if ( $this->exists() ) {
// NOTE: use transclusion text for messages.
// This is consistent with MessageCache::getMsgFromNamespace()
MessageCache::singleton()->replace( $this->mTitle->getDBkey(), $text );
}
+
return true;
}
) {
global $wgContentHandlerUseDB;
+ // Assertion to try to catch T92046
+ if ( (int)$revision->getId() === 0 ) {
+ throw new InvalidArgumentException(
+ __METHOD__ . ': Revision has ID ' . var_export( $revision->getId(), 1 )
+ );
+ }
+
$content = $revision->getContent();
$len = $content ? $content->getSize() : 0;
$rt = $content ? $content->getUltimateRedirectTarget() : null;
if ( $result ) {
$this->updateRedirectOn( $dbw, $rt, $lastRevIsRedirect );
$this->setLastEdit( $revision );
- $this->setCachedLastEditTime( $now );
$this->mLatest = $revision->getId();
$this->mIsRedirect = (bool)$rt;
// Update the LinkCache.
$baseRevId = null;
if ( $edittime && $sectionId !== 'new' ) {
- $dbw = wfGetDB( DB_MASTER );
- $rev = Revision::loadFromTimestamp( $dbw, $this->mTitle, $edittime );
+ $dbr = wfGetDB( DB_SLAVE );
+ $rev = Revision::loadFromTimestamp( $dbr, $this->mTitle, $edittime );
+ // Try the master if this thread may have just added it.
+ // This could be abstracted into a Revision method, but we don't want
+ // to encourage loading of revisions by timestamp.
+ if ( !$rev
+ && wfGetLB()->getServerCount() > 1
+ && wfGetLB()->hasOrMadeRecentMasterChanges()
+ ) {
+ $dbw = wfGetDB( DB_MASTER );
+ $rev = Revision::loadFromTimestamp( $dbw, $this->mTitle, $edittime );
+ }
if ( $rev ) {
$baseRevId = $rev->getId();
}
if ( is_null( $baseRevId ) || $sectionId === 'new' ) {
$oldContent = $this->getContent();
} else {
- // TODO: try DB_SLAVE first
- $dbw = wfGetDB( DB_MASTER );
- $rev = Revision::loadFromId( $dbw, $baseRevId );
-
+ $rev = Revision::newFromId( $baseRevId );
if ( !$rev ) {
wfDebug( __METHOD__ . " asked for bogus section (page: " .
$this->getId() . "; section: $sectionId)\n" );
* error will be returned. These two conditions are also possible with
* auto-detection due to MediaWiki's performance-optimised locking strategy.
*
- * @param bool|int $baseRevId The revision ID this edit was based off, if any
+ * @param bool|int $baseRevId The revision ID this edit was based off, if any.
+ * This is not the parent revision ID, rather the revision ID for older
+ * content used as the source for a rollback, for example.
* @param User $user The user doing the edit
*
* @throws MWException
* error will be returned. These two conditions are also possible with
* auto-detection due to MediaWiki's performance-optimised locking strategy.
*
- * @param bool|int $baseRevId The revision ID this edit was based off, if any
+ * @param bool|int $baseRevId The revision ID this edit was based off, if any.
+ * This is not the parent revision ID, rather the revision ID for older
+ * content used as the source for a rollback, for example.
* @param User $user The user doing the edit
* @param string $serialFormat Format for storing the content in the
* database.
$dbw->begin( __METHOD__ );
try {
- $prepStatus = $content->prepareSave( $this, $flags, $baseRevId, $user );
+ $prepStatus = $content->prepareSave( $this, $flags, $oldid, $user );
$status->merge( $prepStatus );
if ( !$status->isOK() ) {
$dbw->begin( __METHOD__ );
try {
- $prepStatus = $content->prepareSave( $this, $flags, $baseRevId, $user );
+ $prepStatus = $content->prepareSave( $this, $flags, $oldid, $user );
$status->merge( $prepStatus );
if ( !$status->isOK() ) {
// Promote user to any groups they meet the criteria for
$dbw->onTransactionIdle( function () use ( $user ) {
$user->addAutopromoteOnceGroups( 'onEdit' );
+ $user->addAutopromoteOnceGroups( 'onView' ); // b/c
} );
return $status;
}
// The edit may have already been prepared via api.php?action=stashedit
- $cachedEdit = $useCache && $wgAjaxEditStash
+ $cachedEdit = $useCache && $wgAjaxEditStash && !$user->isAllowed( 'bot' )
? ApiStashEdit::checkCache( $this->getTitle(), $content, $user )
: false;
$dbw = wfGetDB( DB_MASTER );
foreach ( $restrictionTypes as $action ) {
- if ( !isset( $expiry[$action] ) ) {
- $expiry[$action] = $dbw->getInfinity();
+ if ( !isset( $expiry[$action] ) || $expiry[$action] === $dbw->getInfinity() ) {
+ $expiry[$action] = 'infinity';
}
if ( !isset( $limit[$action] ) ) {
$limit[$action] = '';
*/
protected function formatExpiry( $expiry ) {
global $wgContLang;
- $dbr = wfGetDB( DB_SLAVE );
- $encodedExpiry = $dbr->encodeExpiry( $expiry );
- if ( $encodedExpiry != 'infinity' ) {
+ if ( $expiry != 'infinity' ) {
return wfMessage(
'protect-expiring',
$wgContLang->timeanddate( $expiry, false, false ),
}
// Generate the edit summary if necessary
- $target = Revision::newFromId( $s->rev_id );
+ $target = Revision::newFromId( $s->rev_id, Revision::READ_LATEST );
if ( empty( $summary ) ) {
if ( $from == '' ) { // no public user name
$summary = wfMessage( 'revertpage-nouser' );
* Opportunistically enqueue link update jobs given fresh parser output if useful
*
* @param ParserOutput $parserOutput Current version page output
- * @return bool Whether a job was pushed
* @since 1.25
*/
public function triggerOpportunisticLinksUpdate( ParserOutput $parserOutput ) {
if ( wfReadOnly() ) {
- return false;
+ return;
+ }
+
+ if ( !Hooks::run( 'OpportunisticLinksUpdate', array( $this, $this->mTitle, $parserOutput ) ) ) {
+ return;
}
if ( $this->mTitle->areRestrictionsCascading() ) {
$params = array();
} else {
// If the inclusions are deterministic, the edit-triggered link jobs are enough
- return false;
+ return;
}
// Check if the last link refresh was before page_touched
JobQueueGroup::singleton()->push( EnqueueJob::newFromLocalJobs(
new JobSpecification( 'refreshLinks', $params, array(), $this->mTitle )
) );
- return true;
+ return;
}
- return false;
+ return;
}
/**
}
// Break down Hangul syllables to grab the first jamo
- $code = utf8ToCodepoint( $matches[1] );
+ $code = UtfNormal\Utils::utf8ToCodepoint( $matches[1] );
if ( $code < 0xac00 || 0xd7a4 <= $code ) {
return $matches[1];
} elseif ( $code < 0xb098 ) {
*/
function normalize( $s ) {
global $wgAllUnicodeFixes;
- $s = UtfNormal::cleanUp( $s );
+ $s = UtfNormal\Validator::cleanUp( $s );
if ( $wgAllUnicodeFixes ) {
$s = $this->transformUsingPairFile( 'normalize-ar.ser', $s );
$s = $this->transformUsingPairFile( 'normalize-ml.ser', $s );
/**
* Decode an expiry (block, protection, etc) which has come from the DB
*
- * @todo FIXME: why are we returnings DBMS-dependent strings???
- *
* @param string $expiry Database expiry String
* @param bool|int $format True to process using language functions, or TS_ constant
* to return the expiry in a given timestamp
+ * @param string $inifinity If $format is not true, use this string for infinite expiry
* @return string
* @since 1.18
*/
- public function formatExpiry( $expiry, $format = true ) {
- static $infinity;
- if ( $infinity === null ) {
- $infinity = wfGetDB( DB_SLAVE )->getInfinity();
+ public function formatExpiry( $expiry, $format = true, $infinity = 'infinity' ) {
+ static $dbInfinity;
+ if ( $dbInfinity === null ) {
+ $dbInfinity = wfGetDB( DB_SLAVE )->getInfinity();
}
- if ( $expiry == '' || $expiry == $infinity ) {
+ if ( $expiry == '' || $expiry === 'infinity' || $expiry == $dbInfinity ) {
return $format === true
? $this->getMessageFromDB( 'infiniteblock' )
: $infinity;