MediaWiki  1.23.6
MessageBlobStore.php
Go to the documentation of this file.
1 <?php
35 
44  public static function get( ResourceLoader $resourceLoader, $modules, $lang ) {
45  wfProfileIn( __METHOD__ );
46  if ( !count( $modules ) ) {
47  wfProfileOut( __METHOD__ );
48  return array();
49  }
50  // Try getting from the DB first
51  $blobs = self::getFromDB( $resourceLoader, array_keys( $modules ), $lang );
52 
53  // Generate blobs for any missing modules and store them in the DB
54  $missing = array_diff( array_keys( $modules ), array_keys( $blobs ) );
55  foreach ( $missing as $name ) {
56  $blob = self::insertMessageBlob( $name, $modules[$name], $lang );
57  if ( $blob ) {
58  $blobs[$name] = $blob;
59  }
60  }
61 
62  wfProfileOut( __METHOD__ );
63  return $blobs;
64  }
65 
76  public static function insertMessageBlob( $name, ResourceLoaderModule $module, $lang ) {
77  $blob = self::generateMessageBlob( $module, $lang );
78 
79  if ( !$blob ) {
80  return false;
81  }
82 
83  try {
84  $dbw = wfGetDB( DB_MASTER );
85  $success = $dbw->insert( 'msg_resource', array(
86  'mr_lang' => $lang,
87  'mr_resource' => $name,
88  'mr_blob' => $blob,
89  'mr_timestamp' => $dbw->timestamp()
90  ),
91  __METHOD__,
92  array( 'IGNORE' )
93  );
94 
95  if ( $success ) {
96  if ( $dbw->affectedRows() == 0 ) {
97  // Blob was already present, fetch it
98  $blob = $dbw->selectField( 'msg_resource', 'mr_blob', array(
99  'mr_resource' => $name,
100  'mr_lang' => $lang,
101  ),
102  __METHOD__
103  );
104  } else {
105  // Update msg_resource_links
106  $rows = array();
107 
108  foreach ( $module->getMessages() as $key ) {
109  $rows[] = array(
110  'mrl_resource' => $name,
111  'mrl_message' => $key
112  );
113  }
114  $dbw->insert( 'msg_resource_links', $rows,
115  __METHOD__, array( 'IGNORE' )
116  );
117  }
118  }
119  } catch ( Exception $e ) {
120  wfDebug( __METHOD__ . " failed to update DB: $e\n" );
121  }
122  return $blob;
123  }
124 
133  public static function updateModule( $name, ResourceLoaderModule $module, $lang ) {
134  $dbw = wfGetDB( DB_MASTER );
135  $row = $dbw->selectRow( 'msg_resource', 'mr_blob',
136  array( 'mr_resource' => $name, 'mr_lang' => $lang ),
137  __METHOD__
138  );
139  if ( !$row ) {
140  return null;
141  }
142 
143  // Save the old and new blobs for later
144  $oldBlob = $row->mr_blob;
145  $newBlob = self::generateMessageBlob( $module, $lang );
146 
147  try {
148  $newRow = array(
149  'mr_resource' => $name,
150  'mr_lang' => $lang,
151  'mr_blob' => $newBlob,
152  'mr_timestamp' => $dbw->timestamp()
153  );
154 
155  $dbw->replace( 'msg_resource',
156  array( array( 'mr_resource', 'mr_lang' ) ),
157  $newRow, __METHOD__
158  );
159 
160  // Figure out which messages were added and removed
161  $oldMessages = array_keys( FormatJson::decode( $oldBlob, true ) );
162  $newMessages = array_keys( FormatJson::decode( $newBlob, true ) );
163  $added = array_diff( $newMessages, $oldMessages );
164  $removed = array_diff( $oldMessages, $newMessages );
165 
166  // Delete removed messages, insert added ones
167  if ( $removed ) {
168  $dbw->delete( 'msg_resource_links', array(
169  'mrl_resource' => $name,
170  'mrl_message' => $removed
171  ), __METHOD__
172  );
173  }
174 
175  $newLinksRows = array();
176 
177  foreach ( $added as $message ) {
178  $newLinksRows[] = array(
179  'mrl_resource' => $name,
180  'mrl_message' => $message
181  );
182  }
183 
184  if ( $newLinksRows ) {
185  $dbw->insert( 'msg_resource_links', $newLinksRows, __METHOD__,
186  array( 'IGNORE' ) // just in case
187  );
188  }
189  } catch ( Exception $e ) {
190  wfDebug( __METHOD__ . " failed to update DB: $e\n" );
191  }
192  return $newBlob;
193  }
194 
200  public static function updateMessage( $key ) {
201  try {
202  $dbw = wfGetDB( DB_MASTER );
203 
204  // Keep running until the updates queue is empty.
205  // Due to update conflicts, the queue might not be emptied
206  // in one iteration.
207  $updates = null;
208  do {
209  $updates = self::getUpdatesForMessage( $key, $updates );
210 
211  foreach ( $updates as $k => $update ) {
212  // Update the row on the condition that it
213  // didn't change since we fetched it by putting
214  // the timestamp in the WHERE clause.
215  $success = $dbw->update( 'msg_resource',
216  array(
217  'mr_blob' => $update['newBlob'],
218  'mr_timestamp' => $dbw->timestamp() ),
219  array(
220  'mr_resource' => $update['resource'],
221  'mr_lang' => $update['lang'],
222  'mr_timestamp' => $update['timestamp'] ),
223  __METHOD__
224  );
225 
226  // Only requeue conflicted updates.
227  // If update() returned false, don't retry, for
228  // fear of getting into an infinite loop
229  if ( !( $success && $dbw->affectedRows() == 0 ) ) {
230  // Not conflicted
231  unset( $updates[$k] );
232  }
233  }
234  } while ( count( $updates ) );
235 
236  // No need to update msg_resource_links because we didn't add
237  // or remove any messages, we just changed their contents.
238  } catch ( Exception $e ) {
239  wfDebug( __METHOD__ . " failed to update DB: $e\n" );
240  }
241  }
242 
243  public static function clear() {
244  // TODO: Give this some more thought
245  try {
246  // Not using TRUNCATE, because that needs extra permissions,
247  // which maybe not granted to the database user.
248  $dbw = wfGetDB( DB_MASTER );
249  $dbw->delete( 'msg_resource', '*', __METHOD__ );
250  $dbw->delete( 'msg_resource_links', '*', __METHOD__ );
251  } catch ( Exception $e ) {
252  wfDebug( __METHOD__ . " failed to update DB: $e\n" );
253  }
254  }
255 
263  private static function getUpdatesForMessage( $key, $prevUpdates = null ) {
264  $dbw = wfGetDB( DB_MASTER );
265 
266  if ( is_null( $prevUpdates ) ) {
267  // Fetch all blobs referencing $key
268  $res = $dbw->select(
269  array( 'msg_resource', 'msg_resource_links' ),
270  array( 'mr_resource', 'mr_lang', 'mr_blob', 'mr_timestamp' ),
271  array( 'mrl_message' => $key, 'mr_resource=mrl_resource' ),
272  __METHOD__
273  );
274  } else {
275  // Refetch the blobs referenced by $prevUpdates
276 
277  // Reorganize the (resource, lang) pairs in the format
278  // expected by makeWhereFrom2d()
279  $twoD = array();
280 
281  foreach ( $prevUpdates as $update ) {
282  $twoD[$update['resource']][$update['lang']] = true;
283  }
284 
285  $res = $dbw->select( 'msg_resource',
286  array( 'mr_resource', 'mr_lang', 'mr_blob', 'mr_timestamp' ),
287  $dbw->makeWhereFrom2d( $twoD, 'mr_resource', 'mr_lang' ),
288  __METHOD__
289  );
290  }
291 
292  // Build the new updates queue
293  $updates = array();
294 
295  foreach ( $res as $row ) {
296  $updates[] = array(
297  'resource' => $row->mr_resource,
298  'lang' => $row->mr_lang,
299  'timestamp' => $row->mr_timestamp,
300  'newBlob' => self::reencodeBlob( $row->mr_blob, $key, $row->mr_lang )
301  );
302  }
303 
304  return $updates;
305  }
306 
315  private static function reencodeBlob( $blob, $key, $lang ) {
316  $decoded = FormatJson::decode( $blob, true );
317  $decoded[$key] = wfMessage( $key )->inLanguage( $lang )->plain();
318 
319  return FormatJson::encode( (object)$decoded );
320  }
321 
332  private static function getFromDB( ResourceLoader $resourceLoader, $modules, $lang ) {
333  global $wgCacheEpoch;
334  $retval = array();
335  $dbr = wfGetDB( DB_SLAVE );
336  $res = $dbr->select( 'msg_resource',
337  array( 'mr_blob', 'mr_resource', 'mr_timestamp' ),
338  array( 'mr_resource' => $modules, 'mr_lang' => $lang ),
339  __METHOD__
340  );
341 
342  foreach ( $res as $row ) {
343  $module = $resourceLoader->getModule( $row->mr_resource );
344  if ( !$module ) {
345  // This shouldn't be possible
346  throw new MWException( __METHOD__ . ' passed an invalid module name' );
347  }
348  // Update the module's blobs if the set of messages changed or if the blob is
349  // older than $wgCacheEpoch
350  if ( array_keys( FormatJson::decode( $row->mr_blob, true ) ) !== array_values( array_unique( $module->getMessages() ) ) ||
351  wfTimestamp( TS_MW, $row->mr_timestamp ) <= $wgCacheEpoch ) {
352  $retval[$row->mr_resource] = self::updateModule( $row->mr_resource, $module, $lang );
353  } else {
354  $retval[$row->mr_resource] = $row->mr_blob;
355  }
356  }
357 
358  return $retval;
359  }
360 
368  private static function generateMessageBlob( ResourceLoaderModule $module, $lang ) {
369  $messages = array();
370 
371  foreach ( $module->getMessages() as $key ) {
372  $messages[$key] = wfMessage( $key )->inLanguage( $lang )->plain();
373  }
374 
375  return FormatJson::encode( (object)$messages );
376  }
377 }
MessageBlobStore\generateMessageBlob
static generateMessageBlob(ResourceLoaderModule $module, $lang)
Generate the message blob for a given module in a given language.
Definition: MessageBlobStore.php:368
DB_MASTER
const DB_MASTER
Definition: Defines.php:56
php
skin txt MediaWiki includes four core it has been set as the default in MediaWiki since the replacing Monobook it had been been the default skin since before being replaced by Vector largely rewritten in while keeping its appearance Several legacy skins were removed in the as the burden of supporting them became too heavy to bear Those in etc for skin dependent CSS etc for skin dependent JavaScript These can also be customised on a per user by etc This feature has led to a wide variety of user styles becoming that gallery is a good place to ending in php
Definition: skin.txt:62
MessageBlobStore\insertMessageBlob
static insertMessageBlob( $name, ResourceLoaderModule $module, $lang)
Generate and insert a new message blob.
Definition: MessageBlobStore.php:76
wfGetDB
& wfGetDB( $db, $groups=array(), $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:3659
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:2483
MessageBlobStore\updateMessage
static updateMessage( $key)
Update a single message in all message blobs it occurs in.
Definition: MessageBlobStore.php:200
wfProfileIn
wfProfileIn( $functionname)
Begin profiling of a function.
Definition: Profiler.php:33
MessageBlobStore\getFromDB
static getFromDB(ResourceLoader $resourceLoader, $modules, $lang)
Get the message blobs for a set of modules from the database.
Definition: MessageBlobStore.php:332
$resourceLoader
do that in ParserLimitReportFormat instead use this to modify the parameters of the image and a DIV can begin in one section and end in another Make sure your code can handle that case gracefully See the EditSectionClearerLink extension for an example zero but section is usually empty its values are the globals values my talk my contributions etc etc otherwise the built in rate limiting checks are if enabled also a ContextSource error or success such as when responding to a resource loader request or generating HTML output & $resourceLoader
Definition: hooks.txt:1956
$messages
$messages
Definition: LogTests.i18n.php:8
$dbr
$dbr
Definition: testCompression.php:48
FormatJson\decode
static decode( $value, $assoc=false)
Decodes a JSON string.
Definition: FormatJson.php:126
FormatJson\encode
static encode( $value, $pretty=false, $escaping=0)
Returns the JSON representation of a value.
Definition: FormatJson.php:104
$success
$success
Definition: Utf8Test.php:91
MWException
MediaWiki exception.
Definition: MWException.php:26
$blob
$blob
Definition: testCompression.php:61
wfProfileOut
wfProfileOut( $functionname='missing')
Stop profiling of a function.
Definition: Profiler.php:46
wfMessage
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses after processing after in associative array form externallinks including delete and has completed for all link tables 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
array
the array() calling protocol came about after MediaWiki 1.4rc1.
List of Api Query prop modules.
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
TS_MW
const TS_MW
MediaWiki concatenated string timestamp (YYYYMMDDHHMMSS)
Definition: GlobalFunctions.php:2431
wfDebug
wfDebug( $text, $dest='all')
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:933
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:336
ResourceLoaderModule\getMessages
getMessages()
Get the messages needed for this module.
Definition: ResourceLoaderModule.php:216
MessageBlobStore\updateModule
static updateModule( $name, ResourceLoaderModule $module, $lang)
Update the message blob for a given module in a given language.
Definition: MessageBlobStore.php:133
MessageBlobStore\reencodeBlob
static reencodeBlob( $blob, $key, $lang)
Reencode a message blob with the updated value for a message.
Definition: MessageBlobStore.php:315
DB_SLAVE
const DB_SLAVE
Definition: Defines.php:55
ResourceLoaderModule
Abstraction for resource loader modules, with name registration and maxage functionality.
Definition: ResourceLoaderModule.php:28
ResourceLoader
Dynamic JavaScript and CSS resource loading system.
Definition: ResourceLoader.php:31
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
MessageBlobStore
This class provides access to the resource message blobs storage used by the ResourceLoader.
Definition: MessageBlobStore.php:34
$e
if( $useReadline) $e
Definition: eval.php:66
$res
$res
Definition: database.txt:21
MessageBlobStore\clear
static clear()
Definition: MessageBlobStore.php:243
$retval
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account incomplete not yet checked for validity & $retval
Definition: hooks.txt:237
MessageBlobStore\getUpdatesForMessage
static getUpdatesForMessage( $key, $prevUpdates=null)
Create an update queue for updateMessage()
Definition: MessageBlobStore.php:263