]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - includes/MessageCache.php
MediaWiki 1.17.4
[autoinstalls/mediawiki.git] / includes / MessageCache.php
1 <?php
2 /**
3  * @file
4  * @ingroup Cache
5  */
6
7 /**
8  *
9  */
10 define( 'MSG_LOAD_TIMEOUT', 60);
11 define( 'MSG_LOCK_TIMEOUT', 10);
12 define( 'MSG_WAIT_TIMEOUT', 10);
13 define( 'MSG_CACHE_VERSION', 1 );
14
15 /**
16  * Message cache
17  * Performs various MediaWiki namespace-related functions
18  * @ingroup Cache
19  */
20 class MessageCache {
21         /**
22          * Process local cache of loaded messages that are defined in
23          * MediaWiki namespace. First array level is a language code,
24          * second level is message key and the values are either message
25          * content prefixed with space, or !NONEXISTENT for negative
26          * caching.
27          */
28         protected $mCache;
29
30         // Should  mean that database cannot be used, but check
31         protected $mDisable;
32
33         /// Lifetime for cache, used by object caching
34         protected $mExpiry;
35
36         /**
37          * Message cache has it's own parser which it uses to transform
38          * messages.
39          */
40         protected $mParserOptions, $mParser;
41
42         /// Variable for tracking which variables are already loaded
43         protected $mLoadedLanguages = array();
44
45         function __construct( $memCached, $useDB, $expiry ) {
46                 if ( !$memCached ) {
47                         $memCached = wfGetCache( CACHE_NONE );
48                 }
49
50                 $this->mMemc = $memCached;
51                 $this->mDisable = !$useDB;
52                 $this->mExpiry = $expiry;
53         }
54
55
56         /**
57          * ParserOptions is lazy initialised.
58          */
59         function getParserOptions() {
60                 if ( !$this->mParserOptions ) {
61                         $this->mParserOptions = new ParserOptions;
62                 }
63                 return $this->mParserOptions;
64         }
65
66         /**
67          * Try to load the cache from a local file.
68          * Actual format of the file depends on the $wgLocalMessageCacheSerialized
69          * setting.
70          *
71          * @param $hash String: the hash of contents, to check validity.
72          * @param $code Mixed: Optional language code, see documenation of load().
73          * @return false on failure.
74          */
75         function loadFromLocal( $hash, $code ) {
76                 global $wgCacheDirectory, $wgLocalMessageCacheSerialized;
77
78                 $filename = "$wgCacheDirectory/messages-" . wfWikiID() . "-$code";
79
80                 # Check file existence
81                 wfSuppressWarnings();
82                 $file = fopen( $filename, 'r' );
83                 wfRestoreWarnings();
84                 if ( !$file ) {
85                         return false; // No cache file
86                 }
87
88                 if ( $wgLocalMessageCacheSerialized ) {
89                         // Check to see if the file has the hash specified
90                         $localHash = fread( $file, 32 );
91                         if ( $hash === $localHash ) {
92                                 // All good, get the rest of it
93                                 $serialized = '';
94                                 while ( !feof( $file ) ) {
95                                         $serialized .= fread( $file, 100000 );
96                                 }
97                                 fclose( $file );
98                                 return $this->setCache( unserialize( $serialized ), $code );
99                         } else {
100                                 fclose( $file );
101                                 return false; // Wrong hash
102                         }
103                 } else {
104                         $localHash=substr(fread($file,40),8);
105                         fclose($file);
106                         if ($hash!=$localHash) {
107                                 return false; // Wrong hash
108                         }
109
110                         # Require overwrites the member variable or just shadows it?
111                         require( $filename );
112                         return $this->setCache( $this->mCache, $code );
113                 }
114         }
115
116         /**
117          * Save the cache to a local file.
118          */
119         function saveToLocal( $serialized, $hash, $code ) {
120                 global $wgCacheDirectory;
121
122                 $filename = "$wgCacheDirectory/messages-" . wfWikiID() . "-$code";
123                 wfMkdirParents( $wgCacheDirectory ); // might fail
124
125                 wfSuppressWarnings();
126                 $file = fopen( $filename, 'w' );
127                 wfRestoreWarnings();
128
129                 if ( !$file ) {
130                         wfDebug( "Unable to open local cache file for writing\n" );
131                         return;
132                 }
133
134                 fwrite( $file, $hash . $serialized );
135                 fclose( $file );
136                 @chmod( $filename, 0666 );
137         }
138
139         function saveToScript( $array, $hash, $code ) {
140                 global $wgCacheDirectory;
141
142                 $filename = "$wgCacheDirectory/messages-" . wfWikiID() . "-$code";
143                 $tempFilename = $filename . '.tmp';
144                 wfMkdirParents( $wgCacheDirectory ); // might fail
145
146                 wfSuppressWarnings();
147                 $file = fopen( $tempFilename, 'w');
148                 wfRestoreWarnings();
149
150                 if ( !$file ) {
151                         wfDebug( "Unable to open local cache file for writing\n" );
152                         return;
153                 }
154
155                 fwrite($file,"<?php\n//$hash\n\n \$this->mCache = array(");
156
157                 foreach ( $array as $key => $message ) {
158                         $key = $this->escapeForScript($key);
159                         $message = $this->escapeForScript($message);
160                         fwrite($file, "'$key' => '$message',\n");
161                 }
162
163                 fwrite($file,");\n?>");
164                 fclose($file);
165                 rename($tempFilename, $filename);
166         }
167
168         function escapeForScript($string) {
169                 $string = str_replace( '\\', '\\\\', $string );
170                 $string = str_replace( '\'', '\\\'', $string );
171                 return $string;
172         }
173
174         /**
175          * Set the cache to $cache, if it is valid. Otherwise set the cache to false.
176          */
177         function setCache( $cache, $code ) {
178                 if ( isset( $cache['VERSION'] ) && $cache['VERSION'] == MSG_CACHE_VERSION ) {
179                         $this->mCache[$code] = $cache;
180                         return true;
181                 } else {
182                         return false;
183                 }
184         }
185
186         /**
187          * Loads messages from caches or from database in this order:
188          * (1) local message cache (if $wgUseLocalMessageCache is enabled)
189          * (2) memcached
190          * (3) from the database.
191          *
192          * When succesfully loading from (2) or (3), all higher level caches are
193          * updated for the newest version.
194          *
195          * Nothing is loaded if member variable mDisable is true, either manually
196          * set by calling code or if message loading fails (is this possible?).
197          *
198          * Returns true if cache is already populated or it was succesfully populated,
199          * or false if populating empty cache fails. Also returns true if MessageCache
200          * is disabled.
201          *
202          * @param $code String: language to which load messages
203          */
204         function load( $code = false ) {
205                 global $wgUseLocalMessageCache;
206
207                 if( !is_string( $code ) ) {
208                         # This isn't really nice, so at least make a note about it and try to
209                         # fall back
210                         wfDebug( __METHOD__ . " called without providing a language code\n" );
211                         $code = 'en';
212                 }
213
214                 # Don't do double loading...
215                 if ( isset($this->mLoadedLanguages[$code]) ) return true;
216
217                 # 8 lines of code just to say (once) that message cache is disabled
218                 if ( $this->mDisable ) {
219                         static $shownDisabled = false;
220                         if ( !$shownDisabled ) {
221                                 wfDebug( __METHOD__ . ": disabled\n" );
222                                 $shownDisabled = true;
223                         }
224                         return true;
225                 }
226
227                 # Loading code starts
228                 wfProfileIn( __METHOD__ );
229                 $success = false; # Keep track of success
230                 $where = array(); # Debug info, delayed to avoid spamming debug log too much
231                 $cacheKey = wfMemcKey( 'messages', $code ); # Key in memc for messages
232
233
234                 # (1) local cache
235                 # Hash of the contents is stored in memcache, to detect if local cache goes
236                 # out of date (due to update in other thread?)
237                 if ( $wgUseLocalMessageCache ) {
238                         wfProfileIn( __METHOD__ . '-fromlocal' );
239
240                         $hash = $this->mMemc->get( wfMemcKey( 'messages', $code, 'hash' ) );
241                         if ( $hash ) {
242                                 $success = $this->loadFromLocal( $hash, $code );
243                                 if ( $success ) $where[] = 'got from local cache';
244                         }
245                         wfProfileOut( __METHOD__ . '-fromlocal' );
246                 }
247
248                 # (2) memcache
249                 # Fails if nothing in cache, or in the wrong version.
250                 if ( !$success ) {
251                         wfProfileIn( __METHOD__ . '-fromcache' );
252                         $cache = $this->mMemc->get( $cacheKey );
253                         $success = $this->setCache( $cache, $code );
254                         if ( $success ) {
255                                 $where[] = 'got from global cache';
256                                 $this->saveToCaches( $cache, false, $code );
257                         }
258                         wfProfileOut( __METHOD__ . '-fromcache' );
259                 }
260
261
262                 # (3)
263                 # Nothing in caches... so we need create one and store it in caches
264                 if ( !$success ) {
265                         $where[] = 'cache is empty';
266                         $where[] = 'loading from database';
267
268                         $this->lock($cacheKey);
269
270                         # Limit the concurrency of loadFromDB to a single process
271                         # This prevents the site from going down when the cache expires
272                         $statusKey = wfMemcKey( 'messages', $code, 'status' );
273                         $success = $this->mMemc->add( $statusKey, 'loading', MSG_LOAD_TIMEOUT );
274                         if ( $success ) {
275                                 $cache = $this->loadFromDB( $code );
276                                 $success = $this->setCache( $cache, $code );
277                         }
278                         if ( $success ) {
279                                 $success = $this->saveToCaches( $cache, true, $code );
280                                 if ( $success ) {
281                                         $this->mMemc->delete( $statusKey );
282                                 } else {
283                                         $this->mMemc->set( $statusKey, 'error', 60*5 );
284                                         wfDebug( "MemCached set error in MessageCache: restart memcached server!\n" );
285                                 }
286                         }
287                         $this->unlock($cacheKey);
288                 }
289
290                 if ( !$success ) {
291                         # Bad luck... this should not happen
292                         $where[] = 'loading FAILED - cache is disabled';
293                         $info = implode( ', ', $where );
294                         wfDebug( __METHOD__ . ": Loading $code... $info\n" );
295                         $this->mDisable = true;
296                         $this->mCache = false;
297                 } else {
298                         # All good, just record the success
299                         $info = implode( ', ', $where );
300                         wfDebug( __METHOD__ . ": Loading $code... $info\n" );
301                         $this->mLoadedLanguages[$code] = true;
302                 }
303                 wfProfileOut( __METHOD__ );
304                 return $success;
305         }
306
307         /**
308          * Loads cacheable messages from the database. Messages bigger than
309          * $wgMaxMsgCacheEntrySize are assigned a special value, and are loaded
310          * on-demand from the database later.
311          *
312          * @param $code Optional language code, see documenation of load().
313          * @return Array: Loaded messages for storing in caches.
314          */
315         function loadFromDB( $code = false ) {
316                 wfProfileIn( __METHOD__ );
317                 global $wgMaxMsgCacheEntrySize, $wgContLanguageCode;
318                 $dbr = wfGetDB( DB_SLAVE );
319                 $cache = array();
320
321                 # Common conditions
322                 $conds = array(
323                         'page_is_redirect' => 0,
324                         'page_namespace' => NS_MEDIAWIKI,
325                 );
326
327                 if ( $code ) {
328                         # Is this fast enough. Should not matter if the filtering is done in the
329                         # database or in code.
330                         if ( $code !== $wgContLanguageCode ) {
331                                 # Messages for particular language
332                                 $conds[] = 'page_title' . $dbr->buildLike( $dbr->anyString(), "/$code" );
333                         } else {
334                                 # Effectively disallows use of '/' character in NS_MEDIAWIKI for uses
335                                 # other than language code.
336                                 $conds[] = 'page_title NOT' . $dbr->buildLike( $dbr->anyString(), '/', $dbr->anyString() );
337                         }
338                 }
339
340                 # Conditions to fetch oversized pages to ignore them
341                 $bigConds = $conds;
342                 $bigConds[] = 'page_len > ' . intval( $wgMaxMsgCacheEntrySize );
343
344                 # Load titles for all oversized pages in the MediaWiki namespace
345                 $res = $dbr->select( 'page', 'page_title', $bigConds, __METHOD__ . "($code)-big" );
346                 foreach ( $res as $row ) {
347                         $cache[$row->page_title] = '!TOO BIG';
348                 }
349
350                 # Conditions to load the remaining pages with their contents
351                 $smallConds = $conds;
352                 $smallConds[] = 'page_latest=rev_id';
353                 $smallConds[] = 'rev_text_id=old_id';
354                 $smallConds[] = 'page_len <= ' . intval( $wgMaxMsgCacheEntrySize );
355
356                 $res = $dbr->select( array( 'page', 'revision', 'text' ),
357                         array( 'page_title', 'old_text', 'old_flags' ),
358                         $smallConds, __METHOD__ . "($code)-small" );
359
360                 foreach ( $res as $row ) {
361                         $cache[$row->page_title] = ' ' . Revision::getRevisionText( $row );
362                 }
363
364                 $cache['VERSION'] = MSG_CACHE_VERSION;
365                 wfProfileOut( __METHOD__ );
366                 return $cache;
367         }
368
369         /**
370          * Updates cache as necessary when message page is changed
371          *
372          * @param $title String: name of the page changed.
373          * @param $text Mixed: new contents of the page.
374          */
375         public function replace( $title, $text ) {
376                 global $wgMaxMsgCacheEntrySize;
377                 wfProfileIn( __METHOD__ );
378
379                 if ( $this->mDisable ) {
380                         wfProfileOut( __METHOD__ );
381                         return;
382                 }
383
384                 list( $msg, $code ) = $this->figureMessage( $title );
385
386                 $cacheKey = wfMemcKey( 'messages', $code );
387                 $this->load($code);
388                 $this->lock($cacheKey);
389
390                 if ( is_array($this->mCache[$code]) ) {
391                         $titleKey = wfMemcKey( 'messages', 'individual', $title );
392
393                         if ( $text === false ) {
394                                 # Article was deleted
395                                 unset( $this->mCache[$code][$title] );
396                                 $this->mMemc->delete( $titleKey );
397
398                         } elseif ( strlen( $text ) > $wgMaxMsgCacheEntrySize ) {
399                                 # Check for size
400                                 $this->mCache[$code][$title] = '!TOO BIG';
401                                 $this->mMemc->set( $titleKey, ' ' . $text, $this->mExpiry );
402
403                         } else {
404                                 $this->mCache[$code][$title] = ' ' . $text;
405                                 $this->mMemc->delete( $titleKey );
406                         }
407
408                         # Update caches
409                         $this->saveToCaches( $this->mCache[$code], true, $code );
410                 }
411                 $this->unlock($cacheKey);
412
413                 // Also delete cached sidebar... just in case it is affected
414                 global $parserMemc;
415                 $codes = array( $code );
416                 if ( $code === 'en'  ) {
417                         // Delete all sidebars, like for example on action=purge on the
418                         // sidebar messages
419                         $codes = array_keys( Language::getLanguageNames() );
420                 }
421
422                 foreach ( $codes as $code ) {
423                         $sidebarKey = wfMemcKey( 'sidebar', $code );
424                         $parserMemc->delete( $sidebarKey );
425                 }
426                 
427                 // Update the message in the message blob store
428                 global $wgContLang;
429                 MessageBlobStore::updateMessage( $wgContLang->lcfirst( $msg ) );
430
431                 wfRunHooks( "MessageCacheReplace", array( $title, $text ) );
432
433                 wfProfileOut( __METHOD__ );
434         }
435
436         /**
437          * Shortcut to update caches.
438          *
439          * @param $cache Array: cached messages with a version.
440          * @param $memc Bool: Wether to update or not memcache.
441          * @param $code String: Language code.
442          * @return False on somekind of error.
443          */
444         protected function saveToCaches( $cache, $memc = true, $code = false ) {
445                 wfProfileIn( __METHOD__ );
446                 global $wgUseLocalMessageCache, $wgLocalMessageCacheSerialized;
447
448                 $cacheKey = wfMemcKey( 'messages', $code );
449
450                 if ( $memc ) {
451                         $success = $this->mMemc->set( $cacheKey, $cache, $this->mExpiry );
452                 } else {
453                         $success = true;
454                 }
455
456                 # Save to local cache
457                 if ( $wgUseLocalMessageCache ) {
458                         $serialized = serialize( $cache );
459                         $hash = md5( $serialized );
460                         $this->mMemc->set( wfMemcKey( 'messages', $code, 'hash' ), $hash, $this->mExpiry );
461                         if ($wgLocalMessageCacheSerialized) {
462                                 $this->saveToLocal( $serialized, $hash, $code );
463                         } else {
464                                 $this->saveToScript( $cache, $hash, $code );
465                         }
466                 }
467
468                 wfProfileOut( __METHOD__ );
469                 return $success;
470         }
471
472         /**
473          * Represents a write lock on the messages key
474          *
475          * @return Boolean: success
476          */
477         function lock($key) {
478                 $lockKey = $key . ':lock';
479                 for ($i=0; $i < MSG_WAIT_TIMEOUT && !$this->mMemc->add( $lockKey, 1, MSG_LOCK_TIMEOUT ); $i++ ) {
480                         sleep(1);
481                 }
482
483                 return $i >= MSG_WAIT_TIMEOUT;
484         }
485
486         function unlock($key) {
487                 $lockKey = $key . ':lock';
488                 $this->mMemc->delete( $lockKey );
489         }
490
491         /**
492          * Get a message from either the content language or the user language.
493          *
494          * @param $key String: the message cache key
495          * @param $useDB Boolean: get the message from the DB, false to use only
496          *               the localisation
497          * @param $langcode String: code of the language to get the message for, if
498          *                  it is a valid code create a language for that language,
499          *                  if it is a string but not a valid code then make a basic
500          *                  language object, if it is a false boolean then use the
501          *                  current users language (as a fallback for the old
502          *                  parameter functionality), or if it is a true boolean
503          *                  then use the wikis content language (also as a
504          *                  fallback).
505          * @param $isFullKey Boolean: specifies whether $key is a two part key
506          *                   "msg/lang".
507          */
508         function get( $key, $useDB = true, $langcode = true, $isFullKey = false ) {
509                 global $wgLanguageCode, $wgContLang;
510
511                 if ( !is_string( $key ) ) {
512                         throw new MWException( "Non-string key given" );
513                 }
514
515                 if ( strval( $key ) === '' ) {
516                         # Shortcut: the empty key is always missing
517                         return false;
518                 }
519
520                 $lang = wfGetLangObj( $langcode );
521                 if ( !$lang ) {
522                         throw new MWException( "Bad lang code $langcode given" );
523                 }
524
525                 $langcode = $lang->getCode();
526
527                 $message = false;
528
529                 # Normalise title-case input (with some inlining)
530                 $lckey = str_replace( ' ', '_', $key );
531                 if ( ord( $key ) < 128 ) {
532                         $lckey[0] = strtolower( $lckey[0] );
533                         $uckey = ucfirst( $lckey );
534                 } else {
535                         $lckey = $wgContLang->lcfirst( $lckey );
536                         $uckey = $wgContLang->ucfirst( $lckey );
537                 }
538
539                 # Try the MediaWiki namespace
540                 if( !$this->mDisable && $useDB ) {
541                         $title = $uckey;
542                         if(!$isFullKey && ( $langcode != $wgLanguageCode ) ) {
543                                 $title .= '/' . $langcode;
544                         }
545                         $message = $this->getMsgFromNamespace( $title, $langcode );
546                 }
547
548                 # Try the array in the language object
549                 if ( $message === false ) {
550                         $message = $lang->getMessage( $lckey );
551                         if ( is_null( $message ) ) {
552                                 $message = false;
553                         }
554                 }
555
556                 # Try the array of another language
557                 if( $message === false ) {
558                         $parts = explode( '/', $lckey );
559                         # We may get calls for things that are http-urls from sidebar
560                         # Let's not load nonexistent languages for those
561                         # They usually have more than one slash.
562                         if ( count( $parts ) == 2 && $parts[1] !== '' ) {
563                                 $message = Language::getMessageFor( $parts[0], $parts[1] );
564                                 if ( is_null( $message ) ) {
565                                         $message = false;
566                                 }
567                         }
568                 }
569
570                 # Is this a custom message? Try the default language in the db...
571                 if( ($message === false || $message === '-' ) &&
572                         !$this->mDisable && $useDB &&
573                         !$isFullKey && ($langcode != $wgLanguageCode) ) {
574                         $message = $this->getMsgFromNamespace( $uckey, $wgLanguageCode );
575                 }
576
577                 # Final fallback
578                 if( $message === false ) {
579                         return false;
580                 }
581
582                 # Fix whitespace
583                 $message = strtr( $message,
584                         array(
585                                 # Fix for trailing whitespace, removed by textarea
586                                 '&#32;' => ' ',
587                                 # Fix for NBSP, converted to space by firefox
588                                 '&nbsp;' => "\xc2\xa0",
589                                 '&#160;' => "\xc2\xa0",
590                         ) );
591
592                 return $message;
593         }
594
595         /**
596          * Get a message from the MediaWiki namespace, with caching. The key must
597          * first be converted to two-part lang/msg form if necessary.
598          *
599          * @param $title String: Message cache key with initial uppercase letter.
600          * @param $code String: code denoting the language to try.
601          */
602         function getMsgFromNamespace( $title, $code ) {
603                 $type = false;
604                 $message = false;
605
606                 $this->load( $code );
607                 if ( isset( $this->mCache[$code][$title] ) ) {
608                         $entry = $this->mCache[$code][$title];
609                         $type = substr( $entry, 0, 1 );
610                         if ( $type == ' ' ) {
611                                 return substr( $entry, 1 );
612                         }
613                 }
614
615                 # Call message hooks, in case they are defined
616                 wfRunHooks('MessagesPreLoad', array( $title, &$message ) );
617                 if ( $message !== false ) {
618                         return $message;
619                 }
620
621                 $titleKey = wfMemcKey( 'messages', 'individual', $title );
622
623                 # Try the individual message cache
624                 $entry = $this->mMemc->get( $titleKey );
625                 if ( $entry ) {
626                         $type = substr( $entry, 0, 1 );
627
628                         if ( $type === ' ' ) {
629                                 # Ok!
630                                 $message = substr( $entry, 1 );
631                                 $this->mCache[$code][$title] = $entry;
632                                 return $message;
633                         } elseif ( $entry === '!NONEXISTENT' ) {
634                                 return false;
635                         } else {
636                                 # Corrupt/obsolete entry, delete it
637                                 $this->mMemc->delete( $titleKey );
638                         }
639                 }
640
641                 # Try loading it from the DB
642                 $revision = Revision::newFromTitle( Title::makeTitle( NS_MEDIAWIKI, $title ) );
643                 if( $revision ) {
644                         $message = $revision->getText();
645                         $this->mCache[$code][$title] = ' ' . $message;
646                         $this->mMemc->set( $titleKey, ' ' . $message, $this->mExpiry );
647                 } else {
648                         # Negative caching
649                         # Use some special text instead of false, because false gets converted to '' somewhere
650                         $this->mMemc->set( $titleKey, '!NONEXISTENT', $this->mExpiry );
651                         $this->mCache[$code][$title] = false;
652                 }
653                 return $message;
654         }
655
656         function transform( $message, $interface = false, $language = null ) {
657                 // Avoid creating parser if nothing to transform
658                 if( strpos( $message, '{{' ) === false ) {
659                         return $message;
660                 }
661
662                 global $wgParser, $wgParserConf;
663                 if ( !$this->mParser && isset( $wgParser ) ) {
664                         # Do some initialisation so that we don't have to do it twice
665                         $wgParser->firstCallInit();
666                         # Clone it and store it
667                         $class = $wgParserConf['class'];
668                         if ( $class == 'Parser_DiffTest' ) {
669                                 # Uncloneable
670                                 $this->mParser = new $class( $wgParserConf );
671                         } else {
672                                 $this->mParser = clone $wgParser;
673                         }
674                         #wfDebug( __METHOD__ . ": following contents triggered transform: $message\n" );
675                 }
676                 if ( $this->mParser ) {
677                         $popts = $this->getParserOptions();
678                         $popts->setInterfaceMessage( $interface );
679                         $popts->setTargetLanguage( $language );
680                         $userlang = $popts->setUserLang( $language );
681                         $message = $this->mParser->transformMsg( $message, $popts );
682                         $popts->setUserLang( $userlang );
683                 }
684                 return $message;
685         }
686
687         function disable() { $this->mDisable = true; }
688         function enable() { $this->mDisable = false; }
689
690         /** @deprecated */
691         function disableTransform(){
692                 wfDeprecated( __METHOD__ );
693         }
694         function enableTransform() {
695                 wfDeprecated( __METHOD__ );
696         }
697         function setTransform( $x ) {
698                 wfDeprecated( __METHOD__ );
699         }
700         function getTransform() {
701                 wfDeprecated( __METHOD__ );
702                 return false;
703         }
704
705         /**
706          * Clear all stored messages. Mainly used after a mass rebuild.
707          */
708         function clear() {
709                 $langs = Language::getLanguageNames( false );
710                 foreach ( array_keys($langs) as $code ) {
711                         # Global cache
712                         $this->mMemc->delete( wfMemcKey( 'messages', $code ) );
713                         # Invalidate all local caches
714                         $this->mMemc->delete( wfMemcKey( 'messages', $code, 'hash' ) );
715                 }
716                 $this->mLoadedLanguages = array();
717         }
718
719         /**
720          * Add a message to the cache
721          * @deprecated Use $wgExtensionMessagesFiles
722          *
723          * @param $key Mixed
724          * @param $value Mixed
725          * @param $lang String: the messages language, English by default
726          */
727         function addMessage( $key, $value, $lang = 'en' ) {
728                 wfDeprecated( __METHOD__ );
729                 $lc = Language::getLocalisationCache();
730                 $lc->addLegacyMessages( array( $lang => array( $key => $value ) ) );
731         }
732
733         /**
734          * Add an associative array of message to the cache
735          * @deprecated Use $wgExtensionMessagesFiles
736          *
737          * @param $messages Array: an associative array of key => values to be added
738          * @param $lang String: the messages language, English by default
739          */
740         function addMessages( $messages, $lang = 'en' ) {
741                 wfDeprecated( __METHOD__ );
742                 $lc = Language::getLocalisationCache();
743                 $lc->addLegacyMessages( array( $lang => $messages ) );
744         }
745
746         /**
747          * Add a 2-D array of messages by lang. Useful for extensions.
748          * @deprecated Use $wgExtensionMessagesFiles
749          *
750          * @param $messages Array: the array to be added
751          */
752         function addMessagesByLang( $messages ) {
753                 wfDeprecated( __METHOD__ );
754                 $lc = Language::getLocalisationCache();
755                 $lc->addLegacyMessages( $messages );
756         }
757
758         /**
759          * Set a hook for addMessagesByLang()
760          */
761         function setExtensionMessagesHook( $callback ) {
762                 $this->mAddMessagesHook = $callback;
763         }
764
765         /**
766          * @deprecated
767          */
768         function loadAllMessages( $lang = false ) {
769         }
770
771         /**
772          * @deprecated
773          */
774         function loadMessagesFile( $filename, $langcode = false ) {
775         }
776
777         public function figureMessage( $key ) {
778                 global $wgLanguageCode;
779                 $pieces = explode( '/', $key );
780                 if( count( $pieces ) < 2 )
781                         return array( $key, $wgLanguageCode );
782
783                 $lang = array_pop( $pieces );
784                 $validCodes = Language::getLanguageNames();
785                 if( !array_key_exists( $lang, $validCodes ) )
786                         return array( $key, $wgLanguageCode );
787
788                 $message = implode( '/', $pieces );
789                 return array( $message, $lang );
790         }
791
792 }