MediaWiki  REL1_24
Message.php
Go to the documentation of this file.
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 '&lt;' . $key . '&gt;';
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 '&lt;' . $this->key . '&gt;';
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 }