MediaWiki REL1_30
MessageBlobStore.php
Go to the documentation of this file.
1<?php
26use Psr\Log\LoggerAwareInterface;
27use Psr\Log\LoggerInterface;
28use Psr\Log\NullLogger;
30
37class MessageBlobStore implements LoggerAwareInterface {
38
39 /* @var ResourceLoader|null */
41
45 protected $logger;
46
50 protected $wanCache;
51
56 public function __construct( ResourceLoader $rl = null, LoggerInterface $logger = null ) {
57 $this->resourceloader = $rl;
58 $this->logger = $logger ?: new NullLogger();
59 $this->wanCache = ObjectCache::getMainWANInstance();
60 }
61
66 public function setLogger( LoggerInterface $logger ) {
67 $this->logger = $logger;
68 }
69
78 public function getBlob( ResourceLoaderModule $module, $lang ) {
79 $blobs = $this->getBlobs( [ $module->getName() => $module ], $lang );
80 return $blobs[$module->getName()];
81 }
82
91 public function getBlobs( array $modules, $lang ) {
92 // Each cache key for a message blob by module name and language code also has a generic
93 // check key without language code. This is used to invalidate any and all language subkeys
94 // that exist for a module from the updateMessage() method.
96 $checkKeys = [
97 // Global check key, see clear()
98 $cache->makeKey( __CLASS__ )
99 ];
100 $cacheKeys = [];
101 foreach ( $modules as $name => $module ) {
102 $cacheKey = $this->makeCacheKey( $module, $lang );
103 $cacheKeys[$name] = $cacheKey;
104 // Per-module check key, see updateMessage()
105 $checkKeys[$cacheKey][] = $cache->makeKey( __CLASS__, $name );
106 }
107 $curTTLs = [];
108 $result = $cache->getMulti( array_values( $cacheKeys ), $curTTLs, $checkKeys );
109
110 $blobs = [];
111 foreach ( $modules as $name => $module ) {
112 $key = $cacheKeys[$name];
113 if ( !isset( $result[$key] ) || $curTTLs[$key] === null || $curTTLs[$key] < 0 ) {
114 $blobs[$name] = $this->recacheMessageBlob( $key, $module, $lang );
115 } else {
116 // Use unexpired cache
117 $blobs[$name] = $result[$key];
118 }
119 }
120 return $blobs;
121 }
122
127 public function get( ResourceLoader $resourceLoader, $modules, $lang ) {
128 return $this->getBlobs( $modules, $lang );
129 }
130
135 public function insertMessageBlob( $name, ResourceLoaderModule $module, $lang ) {
136 return false;
137 }
138
145 private function makeCacheKey( ResourceLoaderModule $module, $lang ) {
146 $messages = array_values( array_unique( $module->getMessages() ) );
147 sort( $messages );
148 return $this->wanCache->makeKey( __CLASS__, $module->getName(), $lang,
149 md5( json_encode( $messages ) )
150 );
151 }
152
160 protected function recacheMessageBlob( $cacheKey, ResourceLoaderModule $module, $lang ) {
161 $blob = $this->generateMessageBlob( $module, $lang );
163 $cache->set( $cacheKey, $blob,
164 // Add part of a day to TTL to avoid all modules expiring at once
165 $cache::TTL_WEEK + mt_rand( 0, $cache::TTL_DAY ),
166 Database::getCacheSetOptions( wfGetDB( DB_REPLICA ) )
167 );
168 return $blob;
169 }
170
177 public function updateMessage( $key ) {
178 $moduleNames = $this->getResourceLoader()->getModulesByMessage( $key );
179 foreach ( $moduleNames as $moduleName ) {
180 // Uses a holdoff to account for database replica DB lag (for MessageCache)
181 $this->wanCache->touchCheckKey( $this->wanCache->makeKey( __CLASS__, $moduleName ) );
182 }
183 }
184
189 public function clear() {
191 // Disable holdoff because this invalidates all modules and also not needed since
192 // LocalisationCache is stored outside the database and doesn't have lag.
193 $cache->touchCheckKey( $cache->makeKey( __CLASS__ ), $cache::HOLDOFF_NONE );
194 }
195
200 protected function getResourceLoader() {
201 // Back-compat: This class supports instantiation without a ResourceLoader object.
202 // Lazy-initialise this property because most callers don't need it.
203 if ( $this->resourceloader === null ) {
204 $this->logger->warning( __CLASS__ . ' created without a ResourceLoader instance' );
205 $this->resourceloader = new ResourceLoader();
206 }
208 }
209
216 protected function fetchMessage( $key, $lang ) {
217 $message = wfMessage( $key )->inLanguage( $lang );
218 $value = $message->plain();
219 if ( !$message->exists() ) {
220 $this->logger->warning( 'Failed to find {messageKey} ({lang})', [
221 'messageKey' => $key,
222 'lang' => $lang,
223 ] );
224 }
225 return $value;
226 }
227
235 private function generateMessageBlob( ResourceLoaderModule $module, $lang ) {
236 $messages = [];
237 foreach ( $module->getMessages() as $key ) {
238 $messages[$key] = $this->fetchMessage( $key, $lang );
239 }
240
241 $json = FormatJson::encode( (object)$messages );
242 // @codeCoverageIgnoreStart
243 if ( $json === false ) {
244 $this->logger->warning( 'Failed to encode message blob for {module} ({lang})', [
245 'module' => $module->getName(),
246 'lang' => $lang,
247 ] );
248 $json = '{}';
249 }
250 // codeCoverageIgnoreEnd
251 return $json;
252 }
253}
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
$messages
This class generates message blobs for use by ResourceLoader modules.
getBlobs(array $modules, $lang)
Get the message blobs for a set of modules.
fetchMessage( $key, $lang)
generateMessageBlob(ResourceLoaderModule $module, $lang)
Generate the message blob for a given module in a given language.
WANObjectCache $wanCache
recacheMessageBlob( $cacheKey, ResourceLoaderModule $module, $lang)
getBlob(ResourceLoaderModule $module, $lang)
Get the message blob for a module.
insertMessageBlob( $name, ResourceLoaderModule $module, $lang)
LoggerInterface $logger
__construct(ResourceLoader $rl=null, LoggerInterface $logger=null)
setLogger(LoggerInterface $logger)
clear()
Invalidate cache keys for all known modules.
updateMessage( $key)
Invalidate cache keys for modules using this message key.
makeCacheKey(ResourceLoaderModule $module, $lang)
Abstraction for ResourceLoader modules, with name registration and maxage functionality.
getMessages()
Get the messages needed for this module.
getName()
Get this module's name.
Dynamic JavaScript and CSS resource loading system.
Multi-datacenter aware caching interface.
touchCheckKey( $key, $holdoff=self::HOLDOFF_TTL)
Purge a "check" key from all datacenters, invalidating keys that use it.
set( $key, $value, $ttl=0, array $opts=[])
Set the value of a key in cache.
Relational database abstraction object.
Definition Database.php:45
either a unescaped string or a HtmlArmor object after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock() - offset Set to overwrite offset parameter in $wgRequest set to '' to unset offset - wrap String Wrap the message in html(usually something like "&lt;div ...>$1&lt;/div>"). - flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException':Called before an exception(or PHP error) is logged. This is meant for integration with external error aggregation services
Allows to change the fields on the form that will be generated $name
Definition hooks.txt:302
do that in ParserLimitReportFormat instead use this to modify the parameters of the image all existing parser cache entries will be invalid To avoid you ll need to handle that somehow(e.g. with the RejectParserCacheValue hook) because MediaWiki won 't do it for you. & $defaults also a ContextSource after deleting those rows but within the same transaction you ll probably need to make sure the header is varied on and they can depend only on the ResourceLoaderContext such as when responding to a resource loader request or generating HTML output & $resourceLoader
Definition hooks.txt:2787
$cache
Definition mcc.php:33
const DB_REPLICA
Definition defines.php:25
if(!isset( $args[0])) $lang