MediaWiki  master
Message.php
Go to the documentation of this file.
1 <?php
26 
138 class Message implements MessageSpecifier, Serializable {
140  public const FORMAT_PLAIN = 'plain';
142  public const FORMAT_BLOCK_PARSE = 'block-parse';
144  public const FORMAT_PARSE = 'parse';
146  public const FORMAT_TEXT = 'text';
148  public const FORMAT_ESCAPED = 'escaped';
149 
154  protected static $listTypeMap = [
155  'comma' => 'commaList',
156  'semicolon' => 'semicolonList',
157  'pipe' => 'pipeList',
158  'text' => 'listToText',
159  ];
160 
167  protected $interface = true;
168 
174  protected $language = false;
175 
180  protected $key;
181 
185  protected $keysToTry;
186 
190  protected $parameters = [];
191 
195  protected $useDatabase = true;
196 
200  protected $contextPage = null;
201 
205  protected $content = null;
206 
210  protected $message;
211 
222  public function __construct( $key, $params = [], Language $language = null ) {
223  if ( $key instanceof MessageSpecifier ) {
224  if ( $params ) {
225  throw new InvalidArgumentException(
226  '$params must be empty if $key is a MessageSpecifier'
227  );
228  }
229  $params = $key->getParams();
230  $key = $key->getKey();
231  }
232 
233  if ( !is_string( $key ) && !is_array( $key ) ) {
234  throw new InvalidArgumentException( '$key must be a string or an array' );
235  }
236 
237  $this->keysToTry = (array)$key;
238 
239  if ( empty( $this->keysToTry ) ) {
240  throw new InvalidArgumentException( '$key must not be an empty list' );
241  }
242 
243  $this->key = reset( $this->keysToTry );
244 
245  $this->parameters = array_values( $params );
246  // User language is only resolved in getLanguage(). This helps preserve the
247  // semantic intent of "user language" across serialize() and unserialize().
248  $this->language = $language ?: false;
249  }
250 
256  public function serialize() {
257  return serialize( [
258  'interface' => $this->interface,
259  'language' => $this->language ? $this->language->getCode() : false,
260  'key' => $this->key,
261  'keysToTry' => $this->keysToTry,
262  'parameters' => $this->parameters,
263  'useDatabase' => $this->useDatabase,
264  // Optimisation: Avoid cost of TitleFormatter on serialize,
265  // and especially cost of TitleParser (via Title::newFromText)
266  // on retrieval.
267  'titlevalue' => ( $this->contextPage
268  ? [ 0 => $this->contextPage->getNamespace(), 1 => $this->contextPage->getDBkey() ]
269  : null
270  ),
271  ] );
272  }
273 
279  public function unserialize( $serialized ) {
280  $data = unserialize( $serialized );
281  if ( !is_array( $data ) ) {
282  throw new InvalidArgumentException( __METHOD__ . ': Invalid serialized data' );
283  }
284 
285  $this->interface = $data['interface'];
286  $this->key = $data['key'];
287  $this->keysToTry = $data['keysToTry'];
288  $this->parameters = $data['parameters'];
289  $this->useDatabase = $data['useDatabase'];
290  $this->language = $data['language']
291  ? MediaWikiServices::getInstance()->getLanguageFactory()
292  ->getLanguage( $data['language'] )
293  : false;
294 
295  // Since 1.35, the key 'titlevalue' is set, instead of 'titlestr'.
296  if ( isset( $data['titlevalue'] ) ) {
297  $this->contextPage = new PageReferenceValue(
298  $data['titlevalue'][0],
299  $data['titlevalue'][1],
300  PageReference::LOCAL
301  );
302  } elseif ( isset( $data['titlestr'] ) ) {
303  // TODO: figure out what's needed to remove this codepath
304  $this->contextPage = Title::newFromText( $data['titlestr'] );
305  } else {
306  $this->contextPage = null; // Explicit for sanity
307  }
308  }
309 
316  public function isMultiKey() {
317  return count( $this->keysToTry ) > 1;
318  }
319 
326  public function getKeysToTry() {
327  return $this->keysToTry;
328  }
329 
341  public function getKey() {
342  return $this->key;
343  }
344 
352  public function getParams() {
353  return $this->parameters;
354  }
355 
363  public function getLanguage() {
364  // Defaults to false which means current user language
365  return $this->language ?: RequestContext::getMain()->getLanguage();
366  }
367 
380  public static function newFromKey( $key, ...$params ) {
381  return new self( $key, $params );
382  }
383 
398  public static function newFromSpecifier( $value ) {
399  $params = [];
400  if ( is_array( $value ) ) {
401  $params = $value;
402  $value = array_shift( $params );
403  }
404 
405  if ( $value instanceof Message ) { // Message, RawMessage, ApiMessage, etc
406  $message = clone $value;
407  } elseif ( $value instanceof MessageSpecifier ) {
408  $message = new Message( $value );
409  } elseif ( is_string( $value ) ) {
410  $message = new Message( $value, $params );
411  } else {
412  throw new InvalidArgumentException( __METHOD__ . ': invalid argument type '
413  . gettype( $value ) );
414  }
415 
416  return $message;
417  }
418 
432  public static function newFallbackSequence( ...$keys ) {
433  if ( func_num_args() == 1 ) {
434  if ( is_array( $keys[0] ) ) {
435  // Allow an array to be passed as the first argument instead
436  $keys = array_values( $keys[0] );
437  } else {
438  // Optimize a single string to not need special fallback handling
439  $keys = $keys[0];
440  }
441  }
442  return new self( $keys );
443  }
444 
455  public function getTitle() {
457 
458  $contLang = MediaWikiServices::getInstance()->getContentLanguage();
459  $lang = $this->getLanguage();
460  $title = $this->key;
461  if (
462  !$lang->equals( $contLang )
463  && in_array( $this->key, (array)$wgForceUIMsgAsContentMsg )
464  ) {
465  $title .= '/' . $lang->getCode();
466  }
467 
468  return Title::makeTitle(
469  NS_MEDIAWIKI, $contLang->ucfirst( strtr( $title, ' ', '_' ) ) );
470  }
471 
482  public function params( ...$args ) {
483  // If $args has only one entry and it's an array, then it's either a
484  // non-varargs call or it happens to be a call with just a single
485  // "special" parameter. Since the "special" parameters don't have any
486  // numeric keys, we'll test that to differentiate the cases.
487  if ( count( $args ) === 1 && isset( $args[0] ) && is_array( $args[0] ) ) {
488  if ( $args[0] === [] ) {
489  $args = [];
490  } else {
491  foreach ( $args[0] as $key => $value ) {
492  if ( is_int( $key ) ) {
493  $args = $args[0];
494  break;
495  }
496  }
497  }
498  }
499 
500  $this->parameters = array_merge( $this->parameters, array_values( $args ) );
501  return $this;
502  }
503 
517  public function rawParams( ...$params ) {
518  if ( isset( $params[0] ) && is_array( $params[0] ) ) {
519  $params = $params[0];
520  }
521  foreach ( $params as $param ) {
522  $this->parameters[] = self::rawParam( $param );
523  }
524  return $this;
525  }
526 
538  public function numParams( ...$params ) {
539  if ( isset( $params[0] ) && is_array( $params[0] ) ) {
540  $params = $params[0];
541  }
542  foreach ( $params as $param ) {
543  $this->parameters[] = self::numParam( $param );
544  }
545  return $this;
546  }
547 
559  public function durationParams( ...$params ) {
560  if ( isset( $params[0] ) && is_array( $params[0] ) ) {
561  $params = $params[0];
562  }
563  foreach ( $params as $param ) {
564  $this->parameters[] = self::durationParam( $param );
565  }
566  return $this;
567  }
568 
580  public function expiryParams( ...$params ) {
581  if ( isset( $params[0] ) && is_array( $params[0] ) ) {
582  $params = $params[0];
583  }
584  foreach ( $params as $param ) {
585  $this->parameters[] = self::expiryParam( $param );
586  }
587  return $this;
588  }
589 
601  public function dateTimeParams( ...$params ) {
602  if ( isset( $params[0] ) && is_array( $params[0] ) ) {
603  $params = $params[0];
604  }
605  foreach ( $params as $param ) {
606  $this->parameters[] = self::dateTimeParam( $param );
607  }
608  return $this;
609  }
610 
622  public function dateParams( ...$params ) {
623  if ( isset( $params[0] ) && is_array( $params[0] ) ) {
624  $params = $params[0];
625  }
626  foreach ( $params as $param ) {
627  $this->parameters[] = self::dateParam( $param );
628  }
629  return $this;
630  }
631 
642  public function userGroupParams( ...$params ) {
643  if ( isset( $params[0] ) && is_array( $params[0] ) ) {
644  $params = $params[0];
645  }
646  foreach ( $params as $param ) {
647  $this->parameters[] = self::userGroupParam( $param );
648  }
649  return $this;
650  }
651 
663  public function timeParams( ...$params ) {
664  if ( isset( $params[0] ) && is_array( $params[0] ) ) {
665  $params = $params[0];
666  }
667  foreach ( $params as $param ) {
668  $this->parameters[] = self::timeParam( $param );
669  }
670  return $this;
671  }
672 
684  public function timeperiodParams( ...$params ) {
685  if ( isset( $params[0] ) && is_array( $params[0] ) ) {
686  $params = $params[0];
687  }
688  foreach ( $params as $param ) {
689  $this->parameters[] = self::timeperiodParam( $param );
690  }
691  return $this;
692  }
693 
705  public function sizeParams( ...$params ) {
706  if ( isset( $params[0] ) && is_array( $params[0] ) ) {
707  $params = $params[0];
708  }
709  foreach ( $params as $param ) {
710  $this->parameters[] = self::sizeParam( $param );
711  }
712  return $this;
713  }
714 
726  public function bitrateParams( ...$params ) {
727  if ( isset( $params[0] ) && is_array( $params[0] ) ) {
728  $params = $params[0];
729  }
730  foreach ( $params as $param ) {
731  $this->parameters[] = self::bitrateParam( $param );
732  }
733  return $this;
734  }
735 
749  public function plaintextParams( ...$params ) {
750  if ( isset( $params[0] ) && is_array( $params[0] ) ) {
751  $params = $params[0];
752  }
753  foreach ( $params as $param ) {
754  $this->parameters[] = self::plaintextParam( $param );
755  }
756  return $this;
757  }
758 
768  public function setContext( IContextSource $context ) {
769  $this->inLanguage( $context->getLanguage() );
770  $this->page( $context->getTitle() );
771  $this->interface = true;
772 
773  return $this;
774  }
775 
787  public function inLanguage( $lang ) {
788  $previousLanguage = $this->language;
789 
790  if ( $lang instanceof Language ) {
791  $this->language = $lang;
792  } elseif ( is_string( $lang ) ) {
793  if ( !$this->language instanceof Language || $this->language->getCode() != $lang ) {
794  $this->language = MediaWikiServices::getInstance()->getLanguageFactory()
795  ->getLanguage( $lang );
796  }
797  } elseif ( $lang instanceof StubUserLang ) {
798  $this->language = false;
799  } else {
800  $type = gettype( $lang );
801  throw new MWException( __METHOD__ . " must be "
802  . "passed a String or Language object; $type given"
803  );
804  }
805 
806  if ( $this->language !== $previousLanguage ) {
807  // The language has changed. Clear the message cache.
808  $this->message = null;
809  }
810  $this->interface = false;
811  return $this;
812  }
813 
823  public function inContentLanguage() {
825  if ( in_array( $this->key, (array)$wgForceUIMsgAsContentMsg ) ) {
826  return $this;
827  }
828 
829  $this->inLanguage( MediaWikiServices::getInstance()->getContentLanguage() );
830  return $this;
831  }
832 
843  public function setInterfaceMessageFlag( $interface ) {
844  $this->interface = (bool)$interface;
845  return $this;
846  }
847 
857  public function useDatabase( $useDatabase ) {
858  $this->useDatabase = (bool)$useDatabase;
859  $this->message = null;
860  return $this;
861  }
862 
873  public function title( $title ) {
874  return $this->page( $title );
875  }
876 
886  public function page( ?PageReference $page ) {
887  $this->contextPage = $page;
888  return $this;
889  }
890 
896  public function content() {
897  wfDeprecated( __METHOD__, '1.38' );
898  if ( !$this->content ) {
899  $this->content = new MessageContent( $this );
900  }
901 
902  return $this->content;
903  }
904 
912  public function toString( string $format ): string {
913  return $this->format( $format );
914  }
915 
923  private function format( string $format ): string {
924  $string = $this->fetchMessage();
925 
926  if ( $string === false ) {
927  // Err on the side of safety, ensure that the output
928  // is always html safe in the event the message key is
929  // missing, since in that case its highly likely the
930  // message key is user-controlled.
931  // '⧼' is used instead of '<' to side-step any
932  // double-escaping issues.
933  // (Keep synchronised with mw.Message#toString in JS.)
934  return '⧼' . htmlspecialchars( $this->key ) . '⧽';
935  }
936 
937  # Replace $* with a list of parameters for &uselang=qqx.
938  if ( strpos( $string, '$*' ) !== false ) {
939  $paramlist = '';
940  if ( $this->parameters !== [] ) {
941  $paramlist = ': $' . implode( ', $', range( 1, count( $this->parameters ) ) );
942  }
943  $string = str_replace( '$*', $paramlist, $string );
944  }
945 
946  # Replace parameters before text parsing
947  $string = $this->replaceParameters( $string, 'before', $format );
948 
949  # Maybe transform using the full parser
950  if ( $format === self::FORMAT_PARSE ) {
951  $string = $this->parseText( $string );
952  $string = Parser::stripOuterParagraph( $string );
953  } elseif ( $format === self::FORMAT_BLOCK_PARSE ) {
954  $string = $this->parseText( $string );
955  } elseif ( $format === self::FORMAT_TEXT ) {
956  $string = $this->transformText( $string );
957  } elseif ( $format === self::FORMAT_ESCAPED ) {
958  $string = $this->transformText( $string );
959  $string = htmlspecialchars( $string, ENT_QUOTES, 'UTF-8', false );
960  }
961 
962  # Raw parameter replacement
963  $string = $this->replaceParameters( $string, 'after', $format );
964 
965  return $string;
966  }
967 
977  public function __toString() {
978  // PHP doesn't allow __toString to throw exceptions and will
979  // trigger a fatal error if it does. So, catch any exceptions.
980 
981  try {
982  return $this->format( self::FORMAT_PARSE );
983  } catch ( Exception $ex ) {
984  try {
985  trigger_error( "Exception caught in " . __METHOD__ . " (message " . $this->key . "): "
986  . $ex, E_USER_WARNING );
987  } catch ( Exception $ex ) {
988  // Doh! Cause a fatal error after all?
989  }
990 
991  return '⧼' . htmlspecialchars( $this->key ) . '⧽';
992  }
993  }
994 
1002  public function parse() {
1003  return $this->format( self::FORMAT_PARSE );
1004  }
1005 
1013  public function text() {
1014  return $this->format( self::FORMAT_TEXT );
1015  }
1016 
1024  public function plain() {
1025  return $this->format( self::FORMAT_PLAIN );
1026  }
1027 
1035  public function parseAsBlock() {
1036  return $this->format( self::FORMAT_BLOCK_PARSE );
1037  }
1038 
1047  public function escaped() {
1048  return $this->format( self::FORMAT_ESCAPED );
1049  }
1050 
1058  public function exists() {
1059  return $this->fetchMessage() !== false;
1060  }
1061 
1070  public function isBlank() {
1071  $message = $this->fetchMessage();
1072  return $message === false || $message === '';
1073  }
1074 
1082  public function isDisabled() {
1083  $message = $this->fetchMessage();
1084  return $message === false || $message === '' || $message === '-';
1085  }
1086 
1095  public static function rawParam( $raw ) {
1096  return [ 'raw' => $raw ];
1097  }
1098 
1106  public static function numParam( $num ) {
1107  return [ 'num' => $num ];
1108  }
1109 
1117  public static function durationParam( $duration ) {
1118  return [ 'duration' => $duration ];
1119  }
1120 
1128  public static function expiryParam( $expiry ) {
1129  return [ 'expiry' => $expiry ];
1130  }
1131 
1139  public static function dateTimeParam( string $dateTime ) {
1140  return [ 'datetime' => $dateTime ];
1141  }
1142 
1150  public static function dateParam( string $date ) {
1151  return [ 'date' => $date ];
1152  }
1153 
1161  public static function timeParam( string $time ) {
1162  return [ 'time' => $time ];
1163  }
1164 
1172  public static function userGroupParam( string $userGroup ) {
1173  return [ 'group' => $userGroup ];
1174  }
1175 
1183  public static function timeperiodParam( $period ) {
1184  return [ 'period' => $period ];
1185  }
1186 
1194  public static function sizeParam( $size ) {
1195  return [ 'size' => $size ];
1196  }
1197 
1205  public static function bitrateParam( $bitrate ) {
1206  return [ 'bitrate' => $bitrate ];
1207  }
1208 
1216  public static function plaintextParam( $plaintext ) {
1217  return [ 'plaintext' => $plaintext ];
1218  }
1219 
1227  public static function listParam( array $list, $type = 'text' ) {
1228  if ( !isset( self::$listTypeMap[$type] ) ) {
1229  throw new InvalidArgumentException(
1230  "Invalid type '$type'. Known types are: " . implode( ', ', array_keys( self::$listTypeMap ) )
1231  );
1232  }
1233  return [ 'list' => $list, 'type' => $type ];
1234  }
1235 
1247  protected function replaceParameters( $message, $type, $format ) {
1248  // A temporary marker for $1 parameters that is only valid
1249  // in non-attribute contexts. However if the entire message is escaped
1250  // then we don't want to use it because it will be mangled in all contexts
1251  // and its unnessary as ->escaped() messages aren't html.
1252  $marker = $format === self::FORMAT_ESCAPED ? '$' : '$\'"';
1253  $replacementKeys = [];
1254  foreach ( $this->parameters as $n => $param ) {
1255  list( $paramType, $value ) = $this->extractParam( $param, $format );
1256  if ( $type === 'before' ) {
1257  if ( $paramType === 'before' ) {
1258  $replacementKeys['$' . ( $n + 1 )] = $value;
1259  } else /* $paramType === 'after' */ {
1260  // To protect against XSS from replacing parameters
1261  // inside html attributes, we convert $1 to $'"1.
1262  // In the event that one of the parameters ends up
1263  // in an attribute, either the ' or the " will be
1264  // escaped, breaking the replacement and avoiding XSS.
1265  $replacementKeys['$' . ( $n + 1 )] = $marker . ( $n + 1 );
1266  }
1267  } elseif ( $paramType === 'after' ) {
1268  $replacementKeys[$marker . ( $n + 1 )] = $value;
1269  }
1270  }
1271  return strtr( $message, $replacementKeys );
1272  }
1273 
1284  protected function extractParam( $param, $format ) {
1285  if ( is_array( $param ) ) {
1286  if ( isset( $param['raw'] ) ) {
1287  return [ 'after', $param['raw'] ];
1288  } elseif ( isset( $param['num'] ) ) {
1289  // Replace number params always in before step for now.
1290  // No support for combined raw and num params
1291  return [ 'before', $this->getLanguage()->formatNum( $param['num'] ) ];
1292  } elseif ( isset( $param['duration'] ) ) {
1293  return [ 'before', $this->getLanguage()->formatDuration( $param['duration'] ) ];
1294  } elseif ( isset( $param['expiry'] ) ) {
1295  return [ 'before', $this->getLanguage()->formatExpiry( $param['expiry'] ) ];
1296  } elseif ( isset( $param['datetime'] ) ) {
1297  return [ 'before', $this->getLanguage()->timeanddate( $param['datetime'] ) ];
1298  } elseif ( isset( $param['date'] ) ) {
1299  return [ 'before', $this->getLanguage()->date( $param['date'] ) ];
1300  } elseif ( isset( $param['time'] ) ) {
1301  return [ 'before', $this->getLanguage()->time( $param['time'] ) ];
1302  } elseif ( isset( $param['group'] ) ) {
1303  return [ 'before', $this->getLanguage()->getGroupName( $param['group'] ) ];
1304  } elseif ( isset( $param['period'] ) ) {
1305  return [ 'before', $this->getLanguage()->formatTimePeriod( $param['period'] ) ];
1306  } elseif ( isset( $param['size'] ) ) {
1307  return [ 'before', $this->getLanguage()->formatSize( $param['size'] ) ];
1308  } elseif ( isset( $param['bitrate'] ) ) {
1309  return [ 'before', $this->getLanguage()->formatBitrate( $param['bitrate'] ) ];
1310  } elseif ( isset( $param['plaintext'] ) ) {
1311  return [ 'after', $this->formatPlaintext( $param['plaintext'], $format ) ];
1312  } elseif ( isset( $param['list'] ) ) {
1313  return $this->formatListParam( $param['list'], $param['type'], $format );
1314  } else {
1315  LoggerFactory::getInstance( 'Bug58676' )->warning(
1316  'Invalid parameter for message "{msgkey}": {param}',
1317  [
1318  'exception' => new Exception,
1319  'msgkey' => $this->getKey(),
1320  'param' => htmlspecialchars( serialize( $param ) ),
1321  ]
1322  );
1323 
1324  return [ 'before', '[INVALID]' ];
1325  }
1326  } elseif ( $param instanceof Message ) {
1327  // Match language, flags, etc. to the current message.
1328  $msg = clone $param;
1329  if ( $msg->language !== $this->language || $msg->useDatabase !== $this->useDatabase ) {
1330  // Cache depends on these parameters
1331  $msg->message = null;
1332  }
1333  $msg->interface = $this->interface;
1334  $msg->language = $this->language;
1335  $msg->useDatabase = $this->useDatabase;
1336  $msg->contextPage = $this->contextPage;
1337 
1338  // DWIM
1339  if ( $format === 'block-parse' ) {
1340  $format = 'parse';
1341  }
1342 
1343  // Message objects should not be before parameters because
1344  // then they'll get double escaped. If the message needs to be
1345  // escaped, it'll happen right here when we call toString().
1346  return [ 'after', $msg->format( $format ) ];
1347  } else {
1348  return [ 'before', $param ];
1349  }
1350  }
1351 
1361  protected function parseText( $string ) {
1362  $out = MediaWikiServices::getInstance()->getMessageCache()->parse(
1363  $string,
1364  $this->contextPage,
1365  /*linestart*/true,
1366  $this->interface,
1367  $this->getLanguage()
1368  );
1369 
1370  return $out instanceof ParserOutput
1371  ? $out->getText( [
1372  'enableSectionEditLinks' => false,
1373  // Wrapping messages in an extra <div> is probably not expected. If
1374  // they're outside the content area they probably shouldn't be
1375  // targeted by CSS that's targeting the parser output, and if
1376  // they're inside they already are from the outer div.
1377  'unwrap' => true,
1378  ] )
1379  : $out;
1380  }
1381 
1391  protected function transformText( $string ) {
1392  return MediaWikiServices::getInstance()->getMessageCache()->transform(
1393  $string,
1394  $this->interface,
1395  $this->getLanguage(),
1396  $this->contextPage
1397  );
1398  }
1399 
1408  protected function fetchMessage() {
1409  if ( $this->message === null ) {
1410  $cache = MediaWikiServices::getInstance()->getMessageCache();
1411 
1412  foreach ( $this->keysToTry as $key ) {
1413  $message = $cache->get( $key, $this->useDatabase, $this->getLanguage() );
1414  if ( $message !== false && $message !== '' ) {
1415  break;
1416  }
1417  }
1418 
1419  // NOTE: The constructor makes sure keysToTry isn't empty,
1420  // so we know that $key and $message are initialized.
1421  $this->key = $key;
1422  $this->message = $message;
1423  }
1424  return $this->message;
1425  }
1426 
1439  protected function formatPlaintext( $plaintext, $format ) {
1440  switch ( $format ) {
1441  case self::FORMAT_TEXT:
1442  case self::FORMAT_PLAIN:
1443  return $plaintext;
1444 
1445  case self::FORMAT_PARSE:
1447  case self::FORMAT_ESCAPED:
1448  default:
1449  return htmlspecialchars( $plaintext, ENT_QUOTES );
1450  }
1451  }
1452 
1461  protected function formatListParam( array $params, $listType, $format ) {
1462  if ( !isset( self::$listTypeMap[$listType] ) ) {
1463  $warning = 'Invalid list type for message "' . $this->getKey() . '": '
1464  . htmlspecialchars( $listType )
1465  . ' (params are ' . htmlspecialchars( serialize( $params ) ) . ')';
1466  trigger_error( $warning, E_USER_WARNING );
1467  $e = new Exception;
1468  wfDebugLog( 'Bug58676', $warning . "\n" . $e->getTraceAsString() );
1469  return [ 'before', '[INVALID]' ];
1470  }
1471  $func = self::$listTypeMap[$listType];
1472 
1473  // Handle an empty list sensibly
1474  if ( !$params ) {
1475  return [ 'before', $this->getLanguage()->$func( [] ) ];
1476  }
1477 
1478  // First, determine what kinds of list items we have
1479  $types = [];
1480  $vars = [];
1481  $list = [];
1482  foreach ( $params as $n => $p ) {
1483  list( $type, $value ) = $this->extractParam( $p, $format );
1484  $types[$type] = true;
1485  $list[] = $value;
1486  $vars[] = '$' . ( $n + 1 );
1487  }
1488 
1489  // Easy case: all are 'before' or 'after', so just join the
1490  // values and use the same type.
1491  if ( count( $types ) === 1 ) {
1492  return [ key( $types ), $this->getLanguage()->$func( $list ) ];
1493  }
1494 
1495  // Hard case: We need to process each value per its type, then
1496  // return the concatenated values as 'after'. We handle this by turning
1497  // the list into a RawMessage and processing that as a parameter.
1498  $vars = $this->getLanguage()->$func( $vars );
1499  // @phan-suppress-next-line SecurityCheck-DoubleEscaped RawMessage is safe here
1500  return $this->extractParam( new RawMessage( $vars, $params ), $format );
1501  }
1502 }
Message\numParam
static numParam( $num)
Definition: Message.php:1106
Message\newFromSpecifier
static newFromSpecifier( $value)
Transform a MessageSpecifier or a primitive value used interchangeably with specifiers (a message key...
Definition: Message.php:398
Title\newFromText
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:382
Message\getParams
getParams()
Returns the message parameters.
Definition: Message.php:352
Message\exists
exists()
Check whether a message key has been defined currently.
Definition: Message.php:1058
Message\dateParam
static dateParam(string $date)
Definition: Message.php:1150
ParserOutput
Definition: ParserOutput.php:36
Message\$listTypeMap
static array $listTypeMap
Mapping from Message::listParam() types to Language methods.
Definition: Message.php:154
NS_MEDIAWIKI
const NS_MEDIAWIKI
Definition: Defines.php:72
Message\$message
string $message
Definition: Message.php:210
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:200
$lang
if(!isset( $args[0])) $lang
Definition: testCompression.php:37
true
return true
Definition: router.php:90
Message\$contextPage
PageReference $contextPage
page object to use as context.
Definition: Message.php:200
MessageSpecifier
Definition: MessageSpecifier.php:24
Message\parseText
parseText( $string)
Wrapper for what ever method we use to parse wikitext.
Definition: Message.php:1361
Message\$keysToTry
string[] $keysToTry
List of keys to try when fetching the message.
Definition: Message.php:185
Message\timeperiodParam
static timeperiodParam( $period)
Definition: Message.php:1183
$serialized
foreach( $res as $row) $serialized
Definition: testCompression.php:88
Message\fetchMessage
fetchMessage()
Wrapper for what ever method we use to get message contents.
Definition: Message.php:1408
Message\format
format(string $format)
Returns the message formatted a certain way.
Definition: Message.php:923
Message\plain
plain()
Returns the message text as-is, only parameters are substituted.
Definition: Message.php:1024
Message\inContentLanguage
inContentLanguage()
Request the message in the wiki's content language, unless it is disabled for this message.
Definition: Message.php:823
Message\$content
Content $content
Content object representing the message.
Definition: Message.php:205
Message\isDisabled
isDisabled()
Check whether a message does not exist, is an empty string, or is "-".
Definition: Message.php:1082
Message\text
text()
Returns the message text.
Definition: Message.php:1013
Message\setInterfaceMessageFlag
setInterfaceMessageFlag( $interface)
Allows manipulating the interface message flag directly.
Definition: Message.php:843
wfDebugLog
wfDebugLog( $logGroup, $text, $dest='all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not.
Definition: GlobalFunctions.php:958
Page\PageReference
Interface for objects (potentially) representing a page that can be viewable and linked to on a wiki.
Definition: PageReference.php:49
Message\userGroupParam
static userGroupParam(string $userGroup)
Definition: Message.php:1172
Message\listParam
static listParam(array $list, $type='text')
Definition: Message.php:1227
Message\__toString
__toString()
Magic method implementation of the above (for PHP >= 5.2.0), so we can do, eg: $foo = new Message( $k...
Definition: Message.php:977
Message\$language
Language bool $language
In which language to get this message.
Definition: Message.php:174
Message\getKey
getKey()
Returns the message key.
Definition: Message.php:341
Message\getLanguage
getLanguage()
Returns the Language of the Message.
Definition: Message.php:363
Message\numParams
numParams(... $params)
Add parameters that are numeric and will be passed through Language::formatNum before substitution.
Definition: Message.php:538
Message\isBlank
isBlank()
Check whether a message does not exist, or is an empty string.
Definition: Message.php:1070
Message\FORMAT_BLOCK_PARSE
const FORMAT_BLOCK_PARSE
Use normal wikitext -> HTML parsing (the result will be wrapped in a block-level HTML tag)
Definition: Message.php:142
MWException
MediaWiki exception.
Definition: MWException.php:29
Message\isMultiKey
isMultiKey()
Definition: Message.php:316
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
Definition: GlobalFunctions.php:997
MediaWiki\Logger\LoggerFactory
PSR-3 logger instance factory.
Definition: LoggerFactory.php:45
Message\useDatabase
useDatabase( $useDatabase)
Enable or disable database use.
Definition: Message.php:857
Message\FORMAT_TEXT
const FORMAT_TEXT
Transform {{..}} constructs but don't transform to HTML.
Definition: Message.php:146
Message\durationParams
durationParams(... $params)
Add parameters that are durations of time and will be passed through Language::formatDuration before ...
Definition: Message.php:559
Message\serialize
serialize()
Definition: Message.php:256
Message\$interface
bool $interface
In which language to get this message.
Definition: Message.php:167
Message\userGroupParams
userGroupParams(... $params)
Add parameters that represent user groups.
Definition: Message.php:642
$args
if( $line===false) $args
Definition: mcc.php:124
$title
$title
Definition: testCompression.php:38
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:650
Message\rawParams
rawParams(... $params)
Add parameters that are substituted after parsing or escaping.
Definition: Message.php:517
Message\FORMAT_PARSE
const FORMAT_PARSE
Use normal wikitext -> HTML parsing but strip the block-level wrapper.
Definition: Message.php:144
Message\getKeysToTry
getKeysToTry()
Definition: Message.php:326
Message\parseAsBlock
parseAsBlock()
Returns the parsed message text which is always surrounded by a block element.
Definition: Message.php:1035
Message\sizeParam
static sizeParam( $size)
Definition: Message.php:1194
Language\getCode
getCode()
Get the internal language code for this language object.
Definition: Language.php:4367
Message\formatPlaintext
formatPlaintext( $plaintext, $format)
Formats a message parameter wrapped with 'plaintext'.
Definition: Message.php:1439
Message\plaintextParam
static plaintextParam( $plaintext)
Definition: Message.php:1216
Message\rawParam
static rawParam( $raw)
Definition: Message.php:1095
StubUserLang
Stub object for the user language.
Definition: StubUserLang.php:24
Message\expiryParam
static expiryParam( $expiry)
Definition: Message.php:1128
Message\parse
parse()
Fully parse the text from wikitext to HTML.
Definition: Message.php:1002
Message\setContext
setContext(IContextSource $context)
Set the language and the title from a context object.
Definition: Message.php:768
Message\transformText
transformText( $string)
Wrapper for what ever method we use to {{-transform wikitext.
Definition: Message.php:1391
Message\timeParams
timeParams(... $params)
Add parameters that are times and will be passed through Language::time before substitution.
Definition: Message.php:663
RequestContext\getMain
static getMain()
Get the RequestContext object associated with the main request.
Definition: RequestContext.php:484
IContextSource\getTitle
getTitle()
Message\plaintextParams
plaintextParams(... $params)
Add parameters that are plaintext and will be passed through without the content being evaluated.
Definition: Message.php:749
$wgForceUIMsgAsContentMsg
$wgForceUIMsgAsContentMsg
When translating messages with wfMessage(), it is not always clear what should be considered UI messa...
Definition: DefaultSettings.php:3651
IContextSource
Interface for objects which can provide a MediaWiki context on request.
Definition: IContextSource.php:58
Message\extractParam
extractParam( $param, $format)
Extracts the parameter type and preprocessed the value if needed.
Definition: Message.php:1284
Message\escaped
escaped()
Returns the message text.
Definition: Message.php:1047
Content
Base interface for content objects.
Definition: Content.php:35
Message\params
params(... $args)
Adds parameters to the parameter list of this message.
Definition: Message.php:482
Message\$key
string $key
The message key.
Definition: Message.php:180
Parser\stripOuterParagraph
static stripOuterParagraph( $html)
Strip outer.
Definition: Parser.php:6378
Message\newFromKey
static newFromKey( $key,... $params)
Factory function that is just wrapper for the real constructor.
Definition: Message.php:380
Message\timeParam
static timeParam(string $time)
Definition: Message.php:1161
Message\formatListParam
formatListParam(array $params, $listType, $format)
Formats a list of parameters as a concatenated string.
Definition: Message.php:1461
$cache
$cache
Definition: mcc.php:33
MessageContent
Wrapper allowing us to handle a system message as a Content object.
Definition: MessageContent.php:37
Page\PageReferenceValue
Immutable value object representing a page reference.
Definition: PageReferenceValue.php:42
Message\dateTimeParam
static dateTimeParam(string $dateTime)
Definition: Message.php:1139
Message\getTitle
getTitle()
Get a title object for a mediawiki message, where it can be found in the mediawiki namespace.
Definition: Message.php:455
Message\title
title( $title)
Set the Title object to use as context when transforming the message.
Definition: Message.php:873
Message\bitrateParam
static bitrateParam( $bitrate)
Definition: Message.php:1205
Message\replaceParameters
replaceParameters( $message, $type, $format)
Substitutes any parameters into the message text.
Definition: Message.php:1247
Message\bitrateParams
bitrateParams(... $params)
Add parameters that are bitrates and will be passed through Language::formatBitrate before substituti...
Definition: Message.php:726
Message\unserialize
unserialize( $serialized)
Definition: Message.php:279
Message
The Message class deals with fetching and processing of interface message into a variety of formats.
Definition: Message.php:138
$keys
$keys
Definition: testCompression.php:72
Message\$parameters
array $parameters
List of parameters which will be substituted into the message.
Definition: Message.php:190
Message\content
content()
Returns the message as a Content object.
Definition: Message.php:896
Message\expiryParams
expiryParams(... $params)
Add parameters that are expiration times and will be passed through Language::formatExpiry before sub...
Definition: Message.php:580
ParserOutput\getText
getText( $options=[])
Get the output HTML.
Definition: ParserOutput.php:360
Message\$useDatabase
bool $useDatabase
Whether database can be used.
Definition: Message.php:195
Message\timeperiodParams
timeperiodParams(... $params)
Add parameters that are time periods and will be passed through Language::formatTimePeriod before sub...
Definition: Message.php:684
Message\FORMAT_ESCAPED
const FORMAT_ESCAPED
Transform {{..}} constructs, HTML-escape the result.
Definition: Message.php:148
RawMessage
Variant of the Message class.
Definition: RawMessage.php:35
Message\__construct
__construct( $key, $params=[], Language $language=null)
Definition: Message.php:222
Message\sizeParams
sizeParams(... $params)
Add parameters that are file sizes and will be passed through Language::formatSize before substitutio...
Definition: Message.php:705
Message\inLanguage
inLanguage( $lang)
Request the message in any language that is supported.
Definition: Message.php:787
Message\FORMAT_PLAIN
const FORMAT_PLAIN
Use message text as-is.
Definition: Message.php:140
Message\page
page(?PageReference $page)
Set the page object to use as context when transforming the message.
Definition: Message.php:886
Message\newFallbackSequence
static newFallbackSequence(... $keys)
Factory function accepting multiple message keys and returning a message instance for the first messa...
Definition: Message.php:432
Message\durationParam
static durationParam( $duration)
Definition: Message.php:1117
Language
Internationalisation code See https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation for more...
Definition: Language.php:42
IContextSource\getLanguage
getLanguage()
Message\dateTimeParams
dateTimeParams(... $params)
Add parameters that are date-times and will be passed through Language::timeanddate before substituti...
Definition: Message.php:601
Message\dateParams
dateParams(... $params)
Add parameters that are dates and will be passed through Language::date before substitution.
Definition: Message.php:622
Message\toString
toString(string $format)
Returns the message formatted a certain way.
Definition: Message.php:912
$type
$type
Definition: testCompression.php:52