* as grammatical transformation, is done by the caller.
*/
class LocalisationCache {
- const VERSION = 3;
+ const VERSION = 4;
/** Configuration associative array */
private $conf;
* an item specific subkey index. Some items are not arrays and so for those
* items, there are no subkeys.
*/
- protected $data = array();
+ protected $data = [];
/**
* The persistent store object. An instance of LCStore.
* For split items, if set, this indicates that all of the subitems have been
* loaded.
*/
- private $loadedItems = array();
+ private $loadedItems = [];
/**
* A 3-d associative array, code/key/subkey, where presence indicates that
* the subitem is loaded. Only used for the split items, i.e. messages.
*/
- private $loadedSubitems = array();
+ private $loadedSubitems = [];
/**
* An array where presence of a key indicates that that language has been
* initialised. Initialisation includes checking for cache expiry and doing
* any necessary updates.
*/
- private $initialisedLangs = array();
+ private $initialisedLangs = [];
/**
* An array mapping non-existent pseudo-languages to fallback languages. This
* is filled by initShallowFallback() when data is requested from a language
* that lacks a Messages*.php file.
*/
- private $shallowFallbacks = array();
+ private $shallowFallbacks = [];
/**
* An array where the keys are codes that have been recached by this instance.
*/
- private $recachedLangs = array();
+ private $recachedLangs = [];
/**
* All item keys
*/
- static public $allKeys = array(
+ static public $allKeys = [
'fallback', 'namespaceNames', 'bookstoreList',
'magicWords', 'messages', 'rtl', 'capitalizeAllNouns', 'digitTransformTable',
'separatorTransformTable', 'fallback8bitEncoding', 'linkPrefixExtension',
'defaultDateFormat', 'extraUserToggles', 'specialPageAliases',
'imageFiles', 'preloadedMessages', 'namespaceGenderAliases',
'digitGroupingPattern', 'pluralRules', 'pluralRuleTypes', 'compiledPluralRules',
- );
+ ];
/**
* Keys for items which consist of associative arrays, which may be merged
* by a fallback sequence.
*/
- static public $mergeableMapKeys = array( 'messages', 'namespaceNames',
- 'dateFormats', 'imageFiles', 'preloadedMessages'
- );
+ static public $mergeableMapKeys = [ 'messages', 'namespaceNames',
+ 'namespaceAliases', 'dateFormats', 'imageFiles', 'preloadedMessages'
+ ];
/**
* Keys for items which are a numbered array.
*/
- static public $mergeableListKeys = array( 'extraUserToggles' );
+ static public $mergeableListKeys = [ 'extraUserToggles' ];
/**
* Keys for items which contain an array of arrays of equivalent aliases
* for each subitem. The aliases may be merged by a fallback sequence.
*/
- static public $mergeableAliasListKeys = array( 'specialPageAliases' );
+ static public $mergeableAliasListKeys = [ 'specialPageAliases' ];
/**
* Keys for items which contain an associative array, and may be merged if
* the primary value contains the special array key "inherit". That array
* key is removed after the first merge.
*/
- static public $optionalMergeKeys = array( 'bookstoreList' );
+ static public $optionalMergeKeys = [ 'bookstoreList' ];
/**
* Keys for items that are formatted like $magicWords
*/
- static public $magicWordKeys = array( 'magicWords' );
+ static public $magicWordKeys = [ 'magicWords' ];
/**
* Keys for items where the subitems are stored in the backend separately.
*/
- static public $splitKeys = array( 'messages' );
+ static public $splitKeys = [ 'messages' ];
/**
* Keys which are loaded automatically by initLanguage()
*/
- static public $preloadedKeys = array( 'dateFormats', 'namespaceNames' );
+ static public $preloadedKeys = [ 'dateFormats', 'namespaceNames' ];
/**
* Associative array of cached plural rules. The key is the language code,
global $wgCacheDirectory;
$this->conf = $conf;
- $storeConf = array();
+ $storeConf = [];
if ( !empty( $conf['storeClass'] ) ) {
$storeClass = $conf['storeClass'];
} else {
$storeClass = 'LCStoreStaticArray';
break;
case 'detect':
- $storeClass = $wgCacheDirectory ? 'LCStoreCDB' : 'LCStoreDB';
+ if ( !empty( $conf['storeDirectory'] ) ) {
+ $storeClass = 'LCStoreCDB';
+ } else {
+ $cacheDir = $wgCacheDirectory ?: wfTempDir();
+ if ( $cacheDir ) {
+ $storeConf['directory'] = $cacheDir;
+ $storeClass = 'LCStoreCDB';
+ } else {
+ $storeClass = 'LCStoreDB';
+ }
+ }
break;
default:
throw new MWException(
}
$this->store = new $storeClass( $storeConf );
- foreach ( array( 'manualRecache', 'forceRecache' ) as $var ) {
+ foreach ( [ 'manualRecache', 'forceRecache' ] as $var ) {
if ( isset( $conf[$var] ) ) {
$this->$var = $conf[$var];
}
public function readJSONFile( $fileName ) {
if ( !is_readable( $fileName ) ) {
- return array();
+ return [];
}
$json = file_get_contents( $fileName );
if ( $json === false ) {
- return array();
+ return [];
}
$data = FormatJson::decode( $json, true );
}
// The JSON format only supports messages, none of the other variables, so wrap the data
- return array( 'messages' => $data );
+ return [ 'messages' => $data ];
}
/**
} catch ( CLDRPluralRuleError $e ) {
wfDebugLog( 'l10n', $e->getMessage() );
- return array();
+ return [];
}
return $compiledRules;
$rulesets = $doc->getElementsByTagName( "pluralRules" );
foreach ( $rulesets as $ruleset ) {
$codes = $ruleset->getAttribute( 'locales' );
- $rules = array();
- $ruleTypes = array();
+ $rules = [];
+ $ruleTypes = [];
$ruleElements = $ruleset->getElementsByTagName( "pluralRule" );
foreach ( $ruleElements as $elt ) {
$ruleType = $elt->getAttribute( 'count' );
// This reads in the PHP i18n file with non-messages l10n data
$fileName = Language::getMessagesFileName( $code );
if ( !file_exists( $fileName ) ) {
- $data = array();
+ $data = [];
} else {
$deps[] = new FileDependency( $fileName );
$data = $this->readPHPFile( $fileName, 'core' );
$newSynonyms = array_slice( $value[$magicName], 1 );
$synonyms = array_values( array_unique( array_merge(
$newSynonyms, $oldSynonyms ) ) );
- $value[$magicName] = array_merge( array( $fallbackInfo[0] ), $synonyms );
+ $value[$magicName] = array_merge( [ $fallbackInfo[0] ], $synonyms );
}
}
}
*/
public function getMessagesDirs() {
global $wgMessagesDirs, $IP;
- return array(
+ return [
'core' => "$IP/languages/i18n",
'api' => "$IP/includes/api/i18n",
'oojs-ui' => "$IP/resources/lib/oojs-ui/i18n",
- ) + $wgMessagesDirs;
+ ] + $wgMessagesDirs;
}
/**
# Initial values
$initialData = array_fill_keys( self::$allKeys, null );
$coreData = $initialData;
- $deps = array();
+ $deps = [];
# Load the primary localisation from the source file
$data = $this->readSourceFilesAndRegisterDeps( $code, $deps );
$coreData['fallback'] = $code === 'en' ? false : 'en';
}
if ( $coreData['fallback'] === false ) {
- $coreData['fallbackSequence'] = array();
+ $coreData['fallbackSequence'] = [];
} else {
$coreData['fallbackSequence'] = array_map( 'trim', explode( ',', $coreData['fallback'] ) );
$len = count( $coreData['fallbackSequence'] );
}
}
- $codeSequence = array_merge( array( $code ), $coreData['fallbackSequence'] );
+ $codeSequence = array_merge( [ $code ], $coreData['fallbackSequence'] );
$messageDirs = $this->getMessagesDirs();
# Load non-JSON localisation data for extensions
# Allow extensions an opportunity to adjust the data for this
# fallback
- Hooks::run( 'LocalisationCacheRecacheFallback', array( $this, $csCode, &$csData ) );
+ Hooks::run( 'LocalisationCacheRecacheFallback', [ $this, $csCode, &$csData ] );
# Merge the data for this fallback into the final array
if ( $csCode === $code ) {
# If there were no plural rules, return an empty array
if ( $allData['pluralRules'] === null ) {
- $allData['pluralRules'] = array();
+ $allData['pluralRules'] = [];
}
if ( $allData['compiledPluralRules'] === null ) {
- $allData['compiledPluralRules'] = array();
+ $allData['compiledPluralRules'] = [];
}
# If there were no plural rule types, return an empty array
if ( $allData['pluralRuleTypes'] === null ) {
- $allData['pluralRuleTypes'] = array();
+ $allData['pluralRuleTypes'] = [];
}
# Set the list keys
- $allData['list'] = array();
+ $allData['list'] = [];
foreach ( self::$splitKeys as $key ) {
$allData['list'][$key] = array_keys( $allData[$key] );
}
# Run hooks
$purgeBlobs = true;
- Hooks::run( 'LocalisationCacheRecache', array( $this, $code, &$allData, &$purgeBlobs ) );
+ Hooks::run( 'LocalisationCacheRecache', [ $this, $code, &$allData, &$purgeBlobs ] );
if ( is_null( $allData['namespaceNames'] ) ) {
throw new MWException( __METHOD__ . ': Localisation data failed sanity check! ' .
* @return array
*/
protected function buildPreload( $data ) {
- $preload = array( 'messages' => array() );
+ $preload = [ 'messages' => [] ];
foreach ( self::$preloadedKeys as $key ) {
$preload[$key] = $data[$key];
}
* This will work on any MediaWiki installation.
*/
class LCStoreDB implements LCStore {
+ /** @var string */
private $currentLang;
+ /** @var bool */
private $writesDone = false;
-
- /** @var DatabaseBase */
+ /** @var IDatabase */
private $dbw;
/** @var array */
- private $batch = array();
-
+ private $batch = [];
+ /** @var bool */
private $readOnly = false;
public function get( $code, $key ) {
- if ( $this->writesDone ) {
- $db = wfGetDB( DB_MASTER );
+ if ( $this->writesDone && $this->dbw ) {
+ $db = $this->dbw; // see the changes in finishWrite()
} else {
$db = wfGetDB( DB_SLAVE );
}
- $row = $db->selectRow( 'l10n_cache', array( 'lc_value' ),
- array( 'lc_lang' => $code, 'lc_key' => $key ), __METHOD__ );
- if ( $row ) {
- return unserialize( $db->decodeBlob( $row->lc_value ) );
- } else {
- return null;
- }
+
+ $value = $db->selectField(
+ 'l10n_cache',
+ 'lc_value',
+ [ 'lc_lang' => $code, 'lc_key' => $key ],
+ __METHOD__
+ );
+
+ return ( $value !== false ) ? unserialize( $db->decodeBlob( $value ) ) : null;
}
public function startWrite( $code ) {
}
$this->dbw = wfGetDB( DB_MASTER );
+ $this->readOnly = $this->dbw->isReadOnly();
$this->currentLang = $code;
- $this->batch = array();
+ $this->batch = [];
}
public function finishWrite() {
throw new MWException( __CLASS__ . ': must call startWrite() before finishWrite()' );
}
- $this->dbw->begin( __METHOD__ );
+ $this->dbw->startAtomic( __METHOD__ );
try {
- $this->dbw->delete( 'l10n_cache',
- array( 'lc_lang' => $this->currentLang ), __METHOD__ );
+ $this->dbw->delete(
+ 'l10n_cache',
+ [ 'lc_lang' => $this->currentLang ],
+ __METHOD__
+ );
foreach ( array_chunk( $this->batch, 500 ) as $rows ) {
$this->dbw->insert( 'l10n_cache', $rows, __METHOD__ );
}
throw $e;
}
}
- $this->dbw->commit( __METHOD__ );
+ $this->dbw->endAtomic( __METHOD__ );
$this->currentLang = null;
- $this->batch = array();
+ $this->batch = [];
}
public function set( $key, $value ) {
throw new MWException( __CLASS__ . ': must call startWrite() before set()' );
}
- $this->batch[] = array(
+ $this->batch[] = [
'lc_lang' => $this->currentLang,
'lc_key' => $key,
- 'lc_value' => $this->dbw->encodeBlob( serialize( $value ) ) );
+ 'lc_value' => $this->dbw->encodeBlob( serialize( $value ) )
+ ];
}
}
/** @var bool|string Cache directory. False if not set */
private $directory;
- function __construct( $conf = array() ) {
+ function __construct( $conf = [] ) {
global $wgCacheDirectory;
if ( isset( $conf['directory'] ) ) {
* A cache of the contents of data files.
* Core files are serialized to avoid using ~1GB of RAM during a recache.
*/
- private $fileCache = array();
+ private $fileCache = [];
/**
* Most recently used languages. Uses the linked-list aspect of PHP hashtables
* to keep the most recently used language codes at the end of the array, and
* the language codes that are ready to be deleted at the beginning.
*/
- private $mruLangs = array();
+ private $mruLangs = [];
/**
* Maximum number of languages that may be loaded into $this->data