X-Git-Url: https://git.heureux-cyclage.org/?p=lhc%2Fweb%2Fwiklou.git;a=blobdiff_plain;f=includes%2Fcache%2Flocalisation%2FLocalisationCache.php;h=a9e69697d64952670c260a3f4571444f76af81bc;hp=c6d6b8fa5b753821d35160f527b23909253adcd7;hb=101493a70783b15656daa0686d404ac1a7a6976b;hpb=af80076034fb734d652eb043c523c1d8df974e51 diff --git a/includes/cache/localisation/LocalisationCache.php b/includes/cache/localisation/LocalisationCache.php index c6d6b8fa5b..a9e69697d6 100644 --- a/includes/cache/localisation/LocalisationCache.php +++ b/includes/cache/localisation/LocalisationCache.php @@ -22,14 +22,14 @@ use CLDRPluralRuleParser\Evaluator; use CLDRPluralRuleParser\Error as CLDRPluralRuleError; -use MediaWiki\Logger\LoggerFactory; -use MediaWiki\MediaWikiServices; +use MediaWiki\Config\ServiceOptions; +use Psr\Log\LoggerInterface; /** * Class for caching the contents of localisation files, Messages*.php * and *.i18n.php. * - * An instance of this class is available using Language::getLocalisationCache(). + * An instance of this class is available using MediaWikiServices. * * The values retrieved from here are merged, containing items from extension * files, core messages files and the language fallback sequence (e.g. zh-cn -> @@ -40,8 +40,8 @@ use MediaWiki\MediaWikiServices; class LocalisationCache { const VERSION = 4; - /** Configuration associative array */ - private $conf; + /** @var ServiceOptions */ + private $options; /** * True if recaching should only be done on an explicit call to recache(). @@ -50,11 +50,6 @@ class LocalisationCache { */ private $manualRecache = false; - /** - * True to treat all files as expired until they are regenerated by this object. - */ - private $forceRecache = false; - /** * The cache data. 3-d array, where the first key is the language code, * the second key is the item key e.g. 'messages', and the third key is @@ -71,16 +66,20 @@ class LocalisationCache { private $store; /** - * @var \Psr\Log\LoggerInterface + * @var LoggerInterface */ private $logger; + /** @var callable[] See comment for parameter in constructor */ + private $clearStoreCallbacks; + /** * A 2-d associative array, code/key, where presence indicates that the item * is loaded. Value arbitrary. * * For split items, if set, this indicates that all of the subitems have been * loaded. + * */ private $loadedItems = []; @@ -189,59 +188,79 @@ class LocalisationCache { private $mergeableKeys = null; /** - * For constructor parameters, see the documentation in DefaultSettings.php - * for $wgLocalisationCacheConf. + * Return a suitable LCStore as specified by the given configuration. * - * @param array $conf - * @throws MWException + * @since 1.34 + * @param array $conf In the format of $wgLocalisationCacheConf + * @param string|false|null $fallbackCacheDir In case 'storeDirectory' isn't specified + * @return LCStore */ - function __construct( $conf ) { - global $wgCacheDirectory; - - $this->conf = $conf; - $this->logger = LoggerFactory::getInstance( 'localisation' ); - - $directory = !empty( $conf['storeDirectory'] ) ? $conf['storeDirectory'] : $wgCacheDirectory; + public static function getStoreFromConf( array $conf, $fallbackCacheDir ) : LCStore { $storeArg = []; - $storeArg['directory'] = $directory; + $storeArg['directory'] = + $conf['storeDirectory'] ?: $fallbackCacheDir; if ( !empty( $conf['storeClass'] ) ) { $storeClass = $conf['storeClass']; + } elseif ( $conf['store'] === 'files' || $conf['store'] === 'file' || + ( $conf['store'] === 'detect' && $storeArg['directory'] ) + ) { + $storeClass = LCStoreCDB::class; + } elseif ( $conf['store'] === 'db' || $conf['store'] === 'detect' ) { + $storeClass = LCStoreDB::class; + $storeArg['server'] = $conf['storeServer'] ?? []; + } elseif ( $conf['store'] === 'array' ) { + $storeClass = LCStoreStaticArray::class; } else { - switch ( $conf['store'] ) { - case 'files': - case 'file': - $storeClass = LCStoreCDB::class; - break; - case 'db': - $storeClass = LCStoreDB::class; - $storeArg['server'] = $conf['storeServer'] ?? []; - break; - case 'array': - $storeClass = LCStoreStaticArray::class; - break; - case 'detect': - if ( $directory ) { - $storeClass = LCStoreCDB::class; - } else { - $storeClass = LCStoreDB::class; - $storeArg['server'] = $conf['storeServer'] ?? []; - } - break; - default: - throw new MWException( - 'Please set $wgLocalisationCacheConf[\'store\'] to something sensible.' - ); - } + throw new MWException( + 'Please set $wgLocalisationCacheConf[\'store\'] to something sensible.' + ); } - $this->logger->debug( static::class . ": using store $storeClass" ); - $this->store = new $storeClass( $storeArg ); - foreach ( [ 'manualRecache', 'forceRecache' ] as $var ) { - if ( isset( $conf[$var] ) ) { - $this->$var = $conf[$var]; - } - } + return new $storeClass( $storeArg ); + } + + /** + * @var array + * @since 1.34 + */ + public const CONSTRUCTOR_OPTIONS = [ + // True to treat all files as expired until they are regenerated by this object. + 'forceRecache', + 'manualRecache', + 'ExtensionMessagesFiles', + 'MessagesDirs', + ]; + + /** + * For constructor parameters, see the documentation in DefaultSettings.php + * for $wgLocalisationCacheConf. + * + * Do not construct this directly. Use MediaWikiServices. + * + * @param ServiceOptions $options + * @param LCStore $store What backend to use for storage + * @param LoggerInterface $logger + * @param callable[] $clearStoreCallbacks To be called whenever the cache is cleared. Can be + * used to clear other caches that depend on this one, such as ResourceLoader's + * MessageBlobStore. + * @throws MWException + */ + function __construct( + ServiceOptions $options, + LCStore $store, + LoggerInterface $logger, + array $clearStoreCallbacks = [] + ) { + $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS ); + + $this->options = $options; + $this->store = $store; + $this->logger = $logger; + $this->clearStoreCallbacks = $clearStoreCallbacks; + + // Keep this separate from $this->options so it can be mutable + $this->manualRecache = $options->get( 'manualRecache' ); } /** @@ -406,7 +425,7 @@ class LocalisationCache { * @return bool */ public function isExpired( $code ) { - if ( $this->forceRecache && !isset( $this->recachedLangs[$code] ) ) { + if ( $this->options->get( 'forceRecache' ) && !isset( $this->recachedLangs[$code] ) ) { $this->logger->debug( __METHOD__ . "($code): forced reload" ); return true; @@ -796,14 +815,12 @@ class LocalisationCache { public function getMessagesDirs() { global $IP; - $config = MediaWikiServices::getInstance()->getMainConfig(); - $messagesDirs = $config->get( 'MessagesDirs' ); return [ 'core' => "$IP/languages/i18n", 'exif' => "$IP/languages/i18n/exif", 'api' => "$IP/includes/api/i18n", 'oojs-ui' => "$IP/resources/lib/ooui/i18n", - ] + $messagesDirs; + ] + $this->options->get( 'MessagesDirs' ); } /** @@ -813,8 +830,6 @@ class LocalisationCache { * @throws MWException */ public function recache( $code ) { - global $wgExtensionMessagesFiles; - if ( !$code ) { throw new MWException( "Invalid language code requested" ); } @@ -861,7 +876,7 @@ class LocalisationCache { # Load non-JSON localisation data for extensions $extensionData = array_fill_keys( $codeSequence, $initialData ); - foreach ( $wgExtensionMessagesFiles as $extension => $fileName ) { + foreach ( $this->options->get( 'ExtensionMessagesFiles' ) as $extension => $fileName ) { if ( isset( $messageDirs[$extension] ) ) { # This extension has JSON message data; skip the PHP shim continue; @@ -1023,8 +1038,9 @@ class LocalisationCache { # HACK: If using a null (i.e. disabled) storage backend, we # can't write to the MessageBlobStore either if ( !$this->store instanceof LCStoreNull ) { - $blobStore = MediaWikiServices::getInstance()->getResourceLoader()->getMessageBlobStore(); - $blobStore->clear(); + foreach ( $this->clearStoreCallbacks as $callback ) { + $callback(); + } } } @@ -1085,5 +1101,4 @@ class LocalisationCache { $this->store = new LCStoreNull; $this->manualRecache = false; } - }