protected $mCache;
/**
- * Should mean that database cannot be used, but check
+ * Should mean that database cannot be used, but check
* @var bool $mDisable
*/
protected $mDisable;
* Variable for tracking which variables are already loaded
* @var array $mLoadedLanguages
*/
- protected $mLoadedLanguages = array();
+ protected $mLoadedLanguages = [];
/**
* @var bool $mInParser
# Loading code starts
$success = false; # Keep track of success
$staleCache = false; # a cache array with expired data, or false if none has been loaded
- $where = array(); # Debug info, delayed to avoid spamming debug log too much
+ $where = []; # Debug info, delayed to avoid spamming debug log too much
# Hash of the contents is stored in memcache, to detect if data-center cache
# or local cache goes out of date (e.g. due to replace() on some other server)
$where[] = 'global cache is expired';
$staleCache = $cache;
} elseif ( $hashVolatile ) {
- # DB results are slave lag prone until the holdoff TTL passes.
+ # DB results are replica DB lag prone until the holdoff TTL passes.
# By then, updates should be reflected in loadFromDBWithLock().
# One thread renerates the cache while others use old values.
$where[] = 'global cache is expired/volatile';
$where[] = 'loading FAILED - cache is disabled';
$this->mDisable = true;
$this->mCache = false;
+ wfDebugLog( 'MessageCacheError', __METHOD__ . ": Failed to load $code\n" );
# This used to throw an exception, but that led to nasty side effects like
# the whole wiki being instantly down if the memcached server died
} else {
$dbr = wfGetDB( ( $mode == self::FOR_UPDATE ) ? DB_MASTER : DB_SLAVE );
- $cache = array();
+ $cache = [];
# Common conditions
- $conds = array(
+ $conds = [
'page_is_redirect' => 0,
'page_namespace' => NS_MEDIAWIKI,
- );
+ ];
- $mostused = array();
+ $mostused = [];
if ( $wgAdaptiveMessageCache && $code !== $wgLanguageCode ) {
if ( !isset( $this->mCache[$wgLanguageCode] ) ) {
$this->load( $wgLanguageCode );
$smallConds[] = 'page_len <= ' . intval( $wgMaxMsgCacheEntrySize );
$res = $dbr->select(
- array( 'page', 'revision', 'text' ),
- array( 'page_title', 'old_text', 'old_flags' ),
+ [ 'page', 'revision', 'text' ],
+ [ 'page_title', 'old_text', 'old_flags' ],
$smallConds,
__METHOD__ . "($code)-small"
);
}
// Mark this cache as definitely "latest" (non-volatile) so
- // load() calls do try to refresh the cache with slave data
+ // load() calls do try to refresh the cache with replica DB data
$this->mCache[$code]['LATEST'] = time();
// Update caches if the lock was acquired
$this->wanCache->touchCheckKey( wfMemcKey( 'messages', $code ) );
// Also delete cached sidebar... just in case it is affected
- $codes = array( $code );
+ $codes = [ $code ];
if ( $code === 'en' ) {
// Delete all sidebars, like for example on action=purge on the
// sidebar messages
$blobStore = $resourceloader->getMessageBlobStore();
$blobStore->updateMessage( $wgContLang->lcfirst( $msg ) );
- Hooks::run( 'MessageCacheReplace', array( $title, $text ) );
+ Hooks::run( 'MessageCacheReplace', [ $title, $text ] );
}
/**
$value = $this->wanCache->get(
wfMemcKey( 'messages', $code, 'hash', 'v1' ),
$curTTL,
- array( wfMemcKey( 'messages', $code ) )
+ [ wfMemcKey( 'messages', $code ) ]
);
if ( !$value ) {
}
}
- return array( $hash, $expired );
+ return [ $hash, $expired ];
}
/**
protected function setValidationHash( $code, array $cache ) {
$this->wanCache->set(
wfMemcKey( 'messages', $code, 'hash', 'v1' ),
- array(
+ [
'hash' => $cache['HASH'],
'latest' => isset( $cache['LATEST'] ) ? $cache['LATEST'] : 0
- ),
+ ],
WANObjectCache::TTL_INDEFINITE
);
}
// Normalise title-case input (with some inlining)
$lckey = MessageCache::normalizeKey( $key );
- Hooks::run( 'MessageCache::get', array( &$lckey ) );
+ Hooks::run( 'MessageCache::get', [ &$lckey ] );
// Loop through each language in the fallback list until we find something useful
$lang = wfGetLangObj( $langcode );
if ( $message !== false ) {
// Fix whitespace
$message = str_replace(
- array(
+ [
# Fix for trailing whitespace, removed by textarea
' ',
# Fix for NBSP, converted to space by firefox
' ',
' ',
- ),
- array(
+ '­'
+ ],
+ [
' ',
"\xc2\xa0",
- "\xc2\xa0"
- ),
+ "\xc2\xa0",
+ "\xc2\xad"
+ ],
$message
);
}
* @return string|bool The message, or false if not found
*/
protected function getMessageFromFallbackChain( $lang, $lckey, $useDB ) {
- global $wgLanguageCode, $wgContLang;
-
- $uckey = $wgContLang->ucfirst( $lckey );
- $langcode = $lang->getCode();
- $message = false;
+ global $wgContLang;
- // First try the requested language.
- if ( $useDB ) {
- if ( $langcode === $wgLanguageCode ) {
- // Messages created in the content language will not have the /lang extension
- $message = $this->getMsgFromNamespace( $uckey, $langcode );
- } else {
- $message = $this->getMsgFromNamespace( "$uckey/$langcode", $langcode );
- }
- }
+ $alreadyTried = [];
+ // First try the requested language.
+ $message = $this->getMessageForLang( $lang, $lckey, $useDB, $alreadyTried );
if ( $message !== false ) {
return $message;
}
- // Check the CDB cache
- $message = $lang->getMessage( $lckey );
- if ( $message !== null ) {
- return $message;
- }
+ // Now try checking the site language.
+ $message = $this->getMessageForLang( $wgContLang, $lckey, $useDB, $alreadyTried );
+ return $message;
+ }
- list( $fallbackChain, $siteFallbackChain ) =
- Language::getFallbacksIncludingSiteLanguage( $langcode );
+ /**
+ * Given a language, try and fetch messages from that language and its fallbacks.
+ *
+ * @see MessageCache::get
+ * @param Language|StubObject $lang Preferred language
+ * @param string $lckey Lowercase key for the message (as for localisation cache)
+ * @param bool $useDB Whether to include messages from the wiki database
+ * @param bool[] $alreadyTried Contains true for each language that has been tried already
+ * @return string|bool The message, or false if not found
+ */
+ private function getMessageForLang( $lang, $lckey, $useDB, &$alreadyTried ) {
+ global $wgContLang;
+ $langcode = $lang->getCode();
- // Next try checking the database for all of the fallback languages of the requested language.
+ // Try checking the database for the requested language
if ( $useDB ) {
- foreach ( $fallbackChain as $code ) {
- if ( $code === $wgLanguageCode ) {
- // Messages created in the content language will not have the /lang extension
- $message = $this->getMsgFromNamespace( $uckey, $code );
- } else {
- $message = $this->getMsgFromNamespace( "$uckey/$code", $code );
- }
+ $uckey = $wgContLang->ucfirst( $lckey );
+
+ if ( !isset( $alreadyTried[ $langcode ] ) ) {
+ $message = $this->getMsgFromNamespace(
+ $this->getMessagePageName( $langcode, $uckey ),
+ $langcode
+ );
if ( $message !== false ) {
- // Found the message.
return $message;
}
+ $alreadyTried[ $langcode ] = true;
}
}
- // Now try checking the site language.
- if ( $useDB ) {
- $message = $this->getMsgFromNamespace( $uckey, $wgLanguageCode );
- if ( $message !== false ) {
- return $message;
- }
- }
-
- $message = $wgContLang->getMessage( $lckey );
+ // Check the CDB cache
+ $message = $lang->getMessage( $lckey );
if ( $message !== null ) {
return $message;
}
- // Finally try the DB for the site language's fallbacks.
+ // Try checking the database for all of the fallback languages
if ( $useDB ) {
- foreach ( $siteFallbackChain as $code ) {
- $message = $this->getMsgFromNamespace( "$uckey/$code", $code );
- if ( $message === false && $code === $wgLanguageCode ) {
- // Messages created in the content language will not have the /lang extension
- $message = $this->getMsgFromNamespace( $uckey, $code );
+ $fallbackChain = Language::getFallbacksFor( $langcode );
+
+ foreach ( $fallbackChain as $code ) {
+ if ( isset( $alreadyTried[ $code ] ) ) {
+ continue;
}
+ $message = $this->getMsgFromNamespace( $this->getMessagePageName( $code, $uckey ), $code );
+
if ( $message !== false ) {
- // Found the message.
return $message;
}
+ $alreadyTried[ $code ] = true;
}
}
return false;
}
+ /**
+ * Get the message page name for a given language
+ *
+ * @param string $langcode
+ * @param string $uckey Uppercase key for the message
+ * @return string The page name
+ */
+ private function getMessagePageName( $langcode, $uckey ) {
+ global $wgLanguageCode;
+ if ( $langcode === $wgLanguageCode ) {
+ // Messages created in the content language will not have the /lang extension
+ return $uckey;
+ } else {
+ return "$uckey/$langcode";
+ }
+ }
+
/**
* Get a message from the MediaWiki namespace, with caching. The key must
* first be converted to two-part lang/msg form if necessary.
} else {
// XXX: This is not cached in process cache, should it?
$message = false;
- Hooks::run( 'MessagesPreLoad', array( $title, &$message ) );
+ Hooks::run( 'MessagesPreLoad', [ $title, &$message ] );
if ( $message !== false ) {
return $message;
}
* @param Title $title
* @param bool $linestart Whether or not this is at the start of a line
* @param bool $interface Whether this is an interface message
- * @param string $language Language code
+ * @param Language|string $language Language code
* @return ParserOutput|string
*/
public function parse( $text, $title = null, $linestart = true,
$parser = $this->getParser();
$popts = $this->getParserOptions();
$popts->setInterfaceMessage( $interface );
+
+ if ( is_string( $language ) ) {
+ $language = Language::factory( $language );
+ }
$popts->setTargetLanguage( $language );
if ( !$title || !$title instanceof Title ) {
$this->mDisable = false;
}
+ /**
+ * Whether DB/cache usage is disabled for determining messages
+ *
+ * If so, this typically indicates either:
+ * - a) load() failed to find a cached copy nor query the DB
+ * - b) we are in a special context or error mode that cannot use the DB
+ * If the DB is ignored, any derived HTML output or cached objects may be wrong.
+ * To avoid long-term cache pollution, TTLs can be adjusted accordingly.
+ *
+ * @return bool
+ * @since 1.27
+ */
+ public function isDisabled() {
+ return $this->mDisable;
+ }
+
/**
* Clear all stored messages. Mainly used after a mass rebuild.
*/
$this->wanCache->touchCheckKey( wfMemcKey( 'messages', $code ) );
}
- $this->mLoadedLanguages = array();
+ $this->mLoadedLanguages = [];
}
/**
$pieces = explode( '/', $key );
if ( count( $pieces ) < 2 ) {
- return array( $key, $wgLanguageCode );
+ return [ $key, $wgLanguageCode ];
}
$lang = array_pop( $pieces );
if ( !Language::fetchLanguageName( $lang, null, 'mw' ) ) {
- return array( $key, $wgLanguageCode );
+ return [ $key, $wgLanguageCode ];
}
$message = implode( '/', $pieces );
- return array( $message, $lang );
+ return [ $message, $lang ];
}
/**
unset( $cache['VERSION'] );
unset( $cache['EXPIRY'] );
// Remove any !NONEXISTENT keys
- $cache = array_diff( $cache, array( '!NONEXISTENT' ) );
+ $cache = array_diff( $cache, [ '!NONEXISTENT' ] );
// Keys may appear with a capital first letter. lcfirst them.
- return array_map( array( $wgContLang, 'lcfirst' ), array_keys( $cache ) );
+ return array_map( [ $wgContLang, 'lcfirst' ], array_keys( $cache ) );
}
}