MediaWiki
REL1_24
|
00001 <?php 00159 class Message { 00160 00167 protected $interface = true; 00168 00175 protected $language = null; 00176 00181 protected $key; 00182 00186 protected $keysToTry; 00187 00191 protected $parameters = array(); 00192 00204 protected $format = 'parse'; 00205 00209 protected $useDatabase = true; 00210 00214 protected $title = null; 00215 00219 protected $content = null; 00220 00224 protected $message; 00225 00236 public function __construct( $key, $params = array(), Language $language = null ) { 00237 global $wgLang; 00238 00239 if ( !is_string( $key ) && !is_array( $key ) ) { 00240 throw new InvalidArgumentException( '$key must be a string or an array' ); 00241 } 00242 00243 $this->keysToTry = (array)$key; 00244 00245 if ( empty( $this->keysToTry ) ) { 00246 throw new InvalidArgumentException( '$key must not be an empty list' ); 00247 } 00248 00249 $this->key = reset( $this->keysToTry ); 00250 00251 $this->parameters = array_values( $params ); 00252 $this->language = $language ? $language : $wgLang; 00253 } 00254 00261 public function isMultiKey() { 00262 return count( $this->keysToTry ) > 1; 00263 } 00264 00271 public function getKeysToTry() { 00272 return $this->keysToTry; 00273 } 00274 00286 public function getKey() { 00287 return $this->key; 00288 } 00289 00297 public function getParams() { 00298 return $this->parameters; 00299 } 00300 00308 public function getFormat() { 00309 return $this->format; 00310 } 00311 00319 public function getLanguage() { 00320 return $this->language; 00321 } 00322 00335 public static function newFromKey( $key /*...*/ ) { 00336 $params = func_get_args(); 00337 array_shift( $params ); 00338 return new self( $key, $params ); 00339 } 00340 00353 public static function newFallbackSequence( /*...*/ ) { 00354 $keys = func_get_args(); 00355 if ( func_num_args() == 1 ) { 00356 if ( is_array( $keys[0] ) ) { 00357 // Allow an array to be passed as the first argument instead 00358 $keys = array_values( $keys[0] ); 00359 } else { 00360 // Optimize a single string to not need special fallback handling 00361 $keys = $keys[0]; 00362 } 00363 } 00364 return new self( $keys ); 00365 } 00366 00377 public function params( /*...*/ ) { 00378 $args = func_get_args(); 00379 if ( isset( $args[0] ) && is_array( $args[0] ) ) { 00380 $args = $args[0]; 00381 } 00382 $args_values = array_values( $args ); 00383 $this->parameters = array_merge( $this->parameters, $args_values ); 00384 return $this; 00385 } 00386 00400 public function rawParams( /*...*/ ) { 00401 $params = func_get_args(); 00402 if ( isset( $params[0] ) && is_array( $params[0] ) ) { 00403 $params = $params[0]; 00404 } 00405 foreach ( $params as $param ) { 00406 $this->parameters[] = self::rawParam( $param ); 00407 } 00408 return $this; 00409 } 00410 00422 public function numParams( /*...*/ ) { 00423 $params = func_get_args(); 00424 if ( isset( $params[0] ) && is_array( $params[0] ) ) { 00425 $params = $params[0]; 00426 } 00427 foreach ( $params as $param ) { 00428 $this->parameters[] = self::numParam( $param ); 00429 } 00430 return $this; 00431 } 00432 00444 public function durationParams( /*...*/ ) { 00445 $params = func_get_args(); 00446 if ( isset( $params[0] ) && is_array( $params[0] ) ) { 00447 $params = $params[0]; 00448 } 00449 foreach ( $params as $param ) { 00450 $this->parameters[] = self::durationParam( $param ); 00451 } 00452 return $this; 00453 } 00454 00466 public function expiryParams( /*...*/ ) { 00467 $params = func_get_args(); 00468 if ( isset( $params[0] ) && is_array( $params[0] ) ) { 00469 $params = $params[0]; 00470 } 00471 foreach ( $params as $param ) { 00472 $this->parameters[] = self::expiryParam( $param ); 00473 } 00474 return $this; 00475 } 00476 00488 public function timeperiodParams( /*...*/ ) { 00489 $params = func_get_args(); 00490 if ( isset( $params[0] ) && is_array( $params[0] ) ) { 00491 $params = $params[0]; 00492 } 00493 foreach ( $params as $param ) { 00494 $this->parameters[] = self::timeperiodParam( $param ); 00495 } 00496 return $this; 00497 } 00498 00510 public function sizeParams( /*...*/ ) { 00511 $params = func_get_args(); 00512 if ( isset( $params[0] ) && is_array( $params[0] ) ) { 00513 $params = $params[0]; 00514 } 00515 foreach ( $params as $param ) { 00516 $this->parameters[] = self::sizeParam( $param ); 00517 } 00518 return $this; 00519 } 00520 00532 public function bitrateParams( /*...*/ ) { 00533 $params = func_get_args(); 00534 if ( isset( $params[0] ) && is_array( $params[0] ) ) { 00535 $params = $params[0]; 00536 } 00537 foreach ( $params as $param ) { 00538 $this->parameters[] = self::bitrateParam( $param ); 00539 } 00540 return $this; 00541 } 00542 00552 public function setContext( IContextSource $context ) { 00553 $this->inLanguage( $context->getLanguage() ); 00554 $this->title( $context->getTitle() ); 00555 $this->interface = true; 00556 00557 return $this; 00558 } 00559 00572 public function inLanguage( $lang ) { 00573 if ( $lang instanceof Language || $lang instanceof StubUserLang ) { 00574 $this->language = $lang; 00575 } elseif ( is_string( $lang ) ) { 00576 if ( $this->language->getCode() != $lang ) { 00577 $this->language = Language::factory( $lang ); 00578 } 00579 } else { 00580 $type = gettype( $lang ); 00581 throw new MWException( __METHOD__ . " must be " 00582 . "passed a String or Language object; $type given" 00583 ); 00584 } 00585 $this->message = null; 00586 $this->interface = false; 00587 return $this; 00588 } 00589 00599 public function inContentLanguage() { 00600 global $wgForceUIMsgAsContentMsg; 00601 if ( in_array( $this->key, (array)$wgForceUIMsgAsContentMsg ) ) { 00602 return $this; 00603 } 00604 00605 global $wgContLang; 00606 $this->inLanguage( $wgContLang ); 00607 return $this; 00608 } 00609 00620 public function setInterfaceMessageFlag( $interface ) { 00621 $this->interface = (bool)$interface; 00622 return $this; 00623 } 00624 00634 public function useDatabase( $useDatabase ) { 00635 $this->useDatabase = (bool)$useDatabase; 00636 return $this; 00637 } 00638 00648 public function title( $title ) { 00649 $this->title = $title; 00650 return $this; 00651 } 00652 00658 public function content() { 00659 if ( !$this->content ) { 00660 $this->content = new MessageContent( $this ); 00661 } 00662 00663 return $this->content; 00664 } 00665 00673 public function toString() { 00674 $string = $this->fetchMessage(); 00675 00676 if ( $string === false ) { 00677 $key = htmlspecialchars( $this->key ); 00678 if ( $this->format === 'plain' ) { 00679 return '<' . $key . '>'; 00680 } 00681 return '<' . $key . '>'; 00682 } 00683 00684 # Replace $* with a list of parameters for &uselang=qqx. 00685 if ( strpos( $string, '$*' ) !== false ) { 00686 $paramlist = ''; 00687 if ( $this->parameters !== array() ) { 00688 $paramlist = ': $' . implode( ', $', range( 1, count( $this->parameters ) ) ); 00689 } 00690 $string = str_replace( '$*', $paramlist, $string ); 00691 } 00692 00693 # Replace parameters before text parsing 00694 $string = $this->replaceParameters( $string, 'before' ); 00695 00696 # Maybe transform using the full parser 00697 if ( $this->format === 'parse' ) { 00698 $string = $this->parseText( $string ); 00699 $string = Parser::stripOuterParagraph( $string ); 00700 } elseif ( $this->format === 'block-parse' ) { 00701 $string = $this->parseText( $string ); 00702 } elseif ( $this->format === 'text' ) { 00703 $string = $this->transformText( $string ); 00704 } elseif ( $this->format === 'escaped' ) { 00705 $string = $this->transformText( $string ); 00706 $string = htmlspecialchars( $string, ENT_QUOTES, 'UTF-8', false ); 00707 } 00708 00709 # Raw parameter replacement 00710 $string = $this->replaceParameters( $string, 'after' ); 00711 00712 return $string; 00713 } 00714 00724 public function __toString() { 00725 // PHP doesn't allow __toString to throw exceptions and will 00726 // trigger a fatal error if it does. So, catch any exceptions. 00727 00728 try { 00729 return $this->toString(); 00730 } catch ( Exception $ex ) { 00731 try { 00732 trigger_error( "Exception caught in " . __METHOD__ . " (message " . $this->key . "): " 00733 . $ex, E_USER_WARNING ); 00734 } catch ( Exception $ex ) { 00735 // Doh! Cause a fatal error after all? 00736 } 00737 00738 if ( $this->format === 'plain' ) { 00739 return '<' . $this->key . '>'; 00740 } 00741 return '<' . $this->key . '>'; 00742 } 00743 } 00744 00752 public function parse() { 00753 $this->format = 'parse'; 00754 return $this->toString(); 00755 } 00756 00764 public function text() { 00765 $this->format = 'text'; 00766 return $this->toString(); 00767 } 00768 00776 public function plain() { 00777 $this->format = 'plain'; 00778 return $this->toString(); 00779 } 00780 00788 public function parseAsBlock() { 00789 $this->format = 'block-parse'; 00790 return $this->toString(); 00791 } 00792 00801 public function escaped() { 00802 $this->format = 'escaped'; 00803 return $this->toString(); 00804 } 00805 00813 public function exists() { 00814 return $this->fetchMessage() !== false; 00815 } 00816 00825 public function isBlank() { 00826 $message = $this->fetchMessage(); 00827 return $message === false || $message === ''; 00828 } 00829 00837 public function isDisabled() { 00838 $message = $this->fetchMessage(); 00839 return $message === false || $message === '' || $message === '-'; 00840 } 00841 00849 public static function rawParam( $raw ) { 00850 return array( 'raw' => $raw ); 00851 } 00852 00860 public static function numParam( $num ) { 00861 return array( 'num' => $num ); 00862 } 00863 00871 public static function durationParam( $duration ) { 00872 return array( 'duration' => $duration ); 00873 } 00874 00882 public static function expiryParam( $expiry ) { 00883 return array( 'expiry' => $expiry ); 00884 } 00885 00893 public static function timeperiodParam( $period ) { 00894 return array( 'period' => $period ); 00895 } 00896 00904 public static function sizeParam( $size ) { 00905 return array( 'size' => $size ); 00906 } 00907 00915 public static function bitrateParam( $bitrate ) { 00916 return array( 'bitrate' => $bitrate ); 00917 } 00918 00929 protected function replaceParameters( $message, $type = 'before' ) { 00930 $replacementKeys = array(); 00931 foreach ( $this->parameters as $n => $param ) { 00932 list( $paramType, $value ) = $this->extractParam( $param ); 00933 if ( $type === $paramType ) { 00934 $replacementKeys['$' . ( $n + 1 )] = $value; 00935 } 00936 } 00937 $message = strtr( $message, $replacementKeys ); 00938 return $message; 00939 } 00940 00950 protected function extractParam( $param ) { 00951 if ( is_array( $param ) ) { 00952 if ( isset( $param['raw'] ) ) { 00953 return array( 'after', $param['raw'] ); 00954 } elseif ( isset( $param['num'] ) ) { 00955 // Replace number params always in before step for now. 00956 // No support for combined raw and num params 00957 return array( 'before', $this->language->formatNum( $param['num'] ) ); 00958 } elseif ( isset( $param['duration'] ) ) { 00959 return array( 'before', $this->language->formatDuration( $param['duration'] ) ); 00960 } elseif ( isset( $param['expiry'] ) ) { 00961 return array( 'before', $this->language->formatExpiry( $param['expiry'] ) ); 00962 } elseif ( isset( $param['period'] ) ) { 00963 return array( 'before', $this->language->formatTimePeriod( $param['period'] ) ); 00964 } elseif ( isset( $param['size'] ) ) { 00965 return array( 'before', $this->language->formatSize( $param['size'] ) ); 00966 } elseif ( isset( $param['bitrate'] ) ) { 00967 return array( 'before', $this->language->formatBitrate( $param['bitrate'] ) ); 00968 } else { 00969 $warning = 'Invalid parameter for message "' . $this->getKey() . '": ' . 00970 htmlspecialchars( serialize( $param ) ); 00971 trigger_error( $warning, E_USER_WARNING ); 00972 $e = new Exception; 00973 wfDebugLog( 'Bug58676', $warning . "\n" . $e->getTraceAsString() ); 00974 00975 return array( 'before', '[INVALID]' ); 00976 } 00977 } elseif ( $param instanceof Message ) { 00978 // Message objects should not be before parameters because 00979 // then they'll get double escaped. If the message needs to be 00980 // escaped, it'll happen right here when we call toString(). 00981 return array( 'after', $param->toString() ); 00982 } else { 00983 return array( 'before', $param ); 00984 } 00985 } 00986 00996 protected function parseText( $string ) { 00997 $out = MessageCache::singleton()->parse( 00998 $string, 00999 $this->title, 01000 /*linestart*/true, 01001 $this->interface, 01002 $this->language 01003 ); 01004 01005 return $out instanceof ParserOutput ? $out->getText() : $out; 01006 } 01007 01017 protected function transformText( $string ) { 01018 return MessageCache::singleton()->transform( 01019 $string, 01020 $this->interface, 01021 $this->language, 01022 $this->title 01023 ); 01024 } 01025 01034 protected function fetchMessage() { 01035 if ( $this->message === null ) { 01036 $cache = MessageCache::singleton(); 01037 01038 foreach ( $this->keysToTry as $key ) { 01039 $message = $cache->get( $key, $this->useDatabase, $this->language ); 01040 if ( $message !== false && $message !== '' ) { 01041 break; 01042 } 01043 } 01044 01045 // NOTE: The constructor makes sure keysToTry isn't empty, 01046 // so we know that $key and $message are initialized. 01047 $this->key = $key; 01048 $this->message = $message; 01049 } 01050 return $this->message; 01051 } 01052 01053 } 01054 01068 class RawMessage extends Message { 01069 01081 public function __construct( $text, $params = array() ) { 01082 if ( !is_string( $text ) ) { 01083 throw new InvalidArgumentException( '$text must be a string' ); 01084 } 01085 01086 parent::__construct( $text, $params ); 01087 01088 // The key is the message. 01089 $this->message = $text; 01090 } 01091 01097 public function fetchMessage() { 01098 // Just in case the message is unset somewhere. 01099 if ( $this->message === null ) { 01100 $this->message = $this->key; 01101 } 01102 01103 return $this->message; 01104 } 01105 01106 }