Completed
Branch master (33c24b)
by
unknown
30:03
created

Message   F

Complexity

Total Complexity 141

Size/Duplication

Total Lines 1051
Duplicated Lines 9.23 %

Coupling/Cohesion

Components 2
Dependencies 11

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 97
loc 1051
rs 3.9999
wmc 141
lcom 2
cbo 11

52 Methods

Rating   Name   Duplication   Size   Complexity  
A serialize() 0 12 2
A isMultiKey() 0 3 1
A getKeysToTry() 0 3 1
A getKey() 0 3 1
A getParams() 0 3 1
A getFormat() 0 3 1
A newFromKey() 0 5 1
A unserialize() 0 11 2
A getLanguage() 0 4 2
B newFromSpecifier() 0 17 5
A newFallbackSequence() 0 13 3
A getTitle() 0 14 3
A params() 3 9 3
A rawParams() 10 10 4
A numParams() 10 10 4
A durationParams() 10 10 4
A expiryParams() 10 10 4
A timeperiodParams() 10 10 4
A sizeParams() 10 10 4
A bitrateParams() 10 10 4
A plaintextParams() 10 10 4
A setContext() 0 7 1
B inLanguage() 0 19 6
A inContentLanguage() 0 10 2
A setInterfaceMessageFlag() 0 4 1
A useDatabase() 0 4 1
A title() 0 4 1
A content() 0 7 2
D toString() 3 40 10
B __toString() 3 20 5
A parse() 0 4 1
A text() 0 4 1
A plain() 0 4 1
A parseAsBlock() 0 4 1
A escaped() 0 4 1
A exists() 0 3 1
A isBlank() 0 4 2
A isDisabled() 0 4 3
A rawParam() 0 3 1
A numParam() 0 3 1
A durationParam() 0 3 1
A expiryParam() 0 3 1
A timeperiodParam() 0 3 1
A sizeParam() 0 3 1
A bitrateParam() 0 3 1
A plaintextParam() 0 3 1
A replaceParameters() 0 11 3
C extractParam() 8 38 11
A parseText() 0 11 2
A transformText() 0 8 1
B fetchMessage() 0 18 5
B formatPlaintext() 0 14 6

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Message often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Message, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Fetching and processing of interface messages.
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License along
16
 * with this program; if not, write to the Free Software Foundation, Inc.,
17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
 * http://www.gnu.org/copyleft/gpl.html
19
 *
20
 * @file
21
 * @author Niklas Laxström
22
 */
23
24
/**
25
 * The Message class provides methods which fulfil two basic services:
26
 *  - fetching interface messages
27
 *  - processing messages into a variety of formats
28
 *
29
 * First implemented with MediaWiki 1.17, the Message class is intended to
30
 * replace the old wfMsg* functions that over time grew unusable.
31
 * @see https://www.mediawiki.org/wiki/Manual:Messages_API for equivalences
32
 * between old and new functions.
33
 *
34
 * You should use the wfMessage() global function which acts as a wrapper for
35
 * the Message class. The wrapper let you pass parameters as arguments.
36
 *
37
 * The most basic usage cases would be:
38
 *
39
 * @code
40
 *     // Initialize a Message object using the 'some_key' message key
41
 *     $message = wfMessage( 'some_key' );
42
 *
43
 *     // Using two parameters those values are strings 'value1' and 'value2':
44
 *     $message = wfMessage( 'some_key',
45
 *          'value1', 'value2'
46
 *     );
47
 * @endcode
48
 *
49
 * @section message_global_fn Global function wrapper:
50
 *
51
 * Since wfMessage() returns a Message instance, you can chain its call with
52
 * a method. Some of them return a Message instance too so you can chain them.
53
 * You will find below several examples of wfMessage() usage.
54
 *
55
 * Fetching a message text for interface message:
56
 *
57
 * @code
58
 *    $button = Xml::button(
59
 *         wfMessage( 'submit' )->text()
60
 *    );
61
 * @endcode
62
 *
63
 * A Message instance can be passed parameters after it has been constructed,
64
 * use the params() method to do so:
65
 *
66
 * @code
67
 *     wfMessage( 'welcome-to' )
68
 *         ->params( $wgSitename )
69
 *         ->text();
70
 * @endcode
71
 *
72
 * {{GRAMMAR}} and friends work correctly:
73
 *
74
 * @code
75
 *    wfMessage( 'are-friends',
76
 *        $user, $friend
77
 *    );
78
 *    wfMessage( 'bad-message' )
79
 *         ->rawParams( '<script>...</script>' )
80
 *         ->escaped();
81
 * @endcode
82
 *
83
 * @section message_language Changing language:
84
 *
85
 * Messages can be requested in a different language or in whatever current
86
 * content language is being used. The methods are:
87
 *     - Message->inContentLanguage()
88
 *     - Message->inLanguage()
89
 *
90
 * Sometimes the message text ends up in the database, so content language is
91
 * needed:
92
 *
93
 * @code
94
 *    wfMessage( 'file-log',
95
 *        $user, $filename
96
 *    )->inContentLanguage()->text();
97
 * @endcode
98
 *
99
 * Checking whether a message exists:
100
 *
101
 * @code
102
 *    wfMessage( 'mysterious-message' )->exists()
103
 *    // returns a boolean whether the 'mysterious-message' key exist.
104
 * @endcode
105
 *
106
 * If you want to use a different language:
107
 *
108
 * @code
109
 *    $userLanguage = $user->getOption( 'language' );
110
 *    wfMessage( 'email-header' )
111
 *         ->inLanguage( $userLanguage )
112
 *         ->plain();
113
 * @endcode
114
 *
115
 * @note You can parse the text only in the content or interface languages
116
 *
117
 * @section message_compare_old Comparison with old wfMsg* functions:
118
 *
119
 * Use full parsing:
120
 *
121
 * @code
122
 *     // old style:
123
 *     wfMsgExt( 'key', array( 'parseinline' ), 'apple' );
124
 *     // new style:
125
 *     wfMessage( 'key', 'apple' )->parse();
126
 * @endcode
127
 *
128
 * Parseinline is used because it is more useful when pre-building HTML.
129
 * In normal use it is better to use OutputPage::(add|wrap)WikiMsg.
130
 *
131
 * Places where HTML cannot be used. {{-transformation is done.
132
 * @code
133
 *     // old style:
134
 *     wfMsgExt( 'key', array( 'parsemag' ), 'apple', 'pear' );
135
 *     // new style:
136
 *     wfMessage( 'key', 'apple', 'pear' )->text();
137
 * @endcode
138
 *
139
 * Shortcut for escaping the message too, similar to wfMsgHTML(), but
140
 * parameters are not replaced after escaping by default.
141
 * @code
142
 *     $escaped = wfMessage( 'key' )
143
 *          ->rawParams( 'apple' )
144
 *          ->escaped();
145
 * @endcode
146
 *
147
 * @section message_appendix Appendix:
148
 *
149
 * @todo
150
 * - test, can we have tests?
151
 * - this documentation needs to be extended
152
 *
153
 * @see https://www.mediawiki.org/wiki/WfMessage()
154
 * @see https://www.mediawiki.org/wiki/New_messages_API
155
 * @see https://www.mediawiki.org/wiki/Localisation
156
 *
157
 * @since 1.17
158
 */
159
class Message implements MessageSpecifier, Serializable {
160
161
	/**
162
	 * In which language to get this message. True, which is the default,
163
	 * means the current user language, false content language.
164
	 *
165
	 * @var bool
166
	 */
167
	protected $interface = true;
168
169
	/**
170
	 * In which language to get this message. Overrides the $interface setting.
171
	 *
172
	 * @var Language|bool Explicit language object, or false for user language
173
	 */
174
	protected $language = false;
175
176
	/**
177
	 * @var string The message key. If $keysToTry has more than one element,
178
	 * this may change to one of the keys to try when fetching the message text.
179
	 */
180
	protected $key;
181
182
	/**
183
	 * @var string[] List of keys to try when fetching the message.
184
	 */
185
	protected $keysToTry;
186
187
	/**
188
	 * @var array List of parameters which will be substituted into the message.
189
	 */
190
	protected $parameters = [];
191
192
	/**
193
	 * Format for the message.
194
	 * Supported formats are:
195
	 * * text (transform)
196
	 * * escaped (transform+htmlspecialchars)
197
	 * * block-parse
198
	 * * parse (default)
199
	 * * plain
200
	 *
201
	 * @var string
202
	 */
203
	protected $format = 'parse';
204
205
	/**
206
	 * @var bool Whether database can be used.
207
	 */
208
	protected $useDatabase = true;
209
210
	/**
211
	 * @var Title Title object to use as context.
212
	 */
213
	protected $title = null;
214
215
	/**
216
	 * @var Content Content object representing the message.
217
	 */
218
	protected $content = null;
219
220
	/**
221
	 * @var string
222
	 */
223
	protected $message;
224
225
	/**
226
	 * @since 1.17
227
	 * @param string|string[]|MessageSpecifier $key Message key, or array of
228
	 * message keys to try and use the first non-empty message for, or a
229
	 * MessageSpecifier to copy from.
230
	 * @param array $params Message parameters.
231
	 * @param Language $language [optional] Language to use (defaults to current user language).
232
	 * @throws InvalidArgumentException
233
	 */
234
	public function __construct( $key, $params = [], Language $language = null ) {
235
		if ( $key instanceof MessageSpecifier ) {
236
			if ( $params ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $params of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
237
				throw new InvalidArgumentException(
238
					'$params must be empty if $key is a MessageSpecifier'
239
				);
240
			}
241
			$params = $key->getParams();
242
			$key = $key->getKey();
243
		}
244
245
		if ( !is_string( $key ) && !is_array( $key ) ) {
246
			throw new InvalidArgumentException( '$key must be a string or an array' );
247
		}
248
249
		$this->keysToTry = (array)$key;
250
251
		if ( empty( $this->keysToTry ) ) {
252
			throw new InvalidArgumentException( '$key must not be an empty list' );
253
		}
254
255
		$this->key = reset( $this->keysToTry );
256
257
		$this->parameters = array_values( $params );
258
		// User language is only resolved in getLanguage(). This helps preserve the
259
		// semantic intent of "user language" across serialize() and unserialize().
260
		$this->language = $language ?: false;
261
	}
262
263
	/**
264
	 * @see Serializable::serialize()
265
	 * @since 1.26
266
	 * @return string
267
	 */
268
	public function serialize() {
269
		return serialize( [
270
			'interface' => $this->interface,
271
			'language' => $this->language ? $this->language->getCode() : false,
272
			'key' => $this->key,
273
			'keysToTry' => $this->keysToTry,
274
			'parameters' => $this->parameters,
275
			'format' => $this->format,
276
			'useDatabase' => $this->useDatabase,
277
			'title' => $this->title,
278
		] );
279
	}
280
281
	/**
282
	 * @see Serializable::unserialize()
283
	 * @since 1.26
284
	 * @param string $serialized
285
	 */
286
	public function unserialize( $serialized ) {
287
		$data = unserialize( $serialized );
288
		$this->interface = $data['interface'];
289
		$this->key = $data['key'];
290
		$this->keysToTry = $data['keysToTry'];
291
		$this->parameters = $data['parameters'];
292
		$this->format = $data['format'];
293
		$this->useDatabase = $data['useDatabase'];
294
		$this->language = $data['language'] ? Language::factory( $data['language'] ) : false;
295
		$this->title = $data['title'];
296
	}
297
298
	/**
299
	 * @since 1.24
300
	 *
301
	 * @return bool True if this is a multi-key message, that is, if the key provided to the
302
	 * constructor was a fallback list of keys to try.
303
	 */
304
	public function isMultiKey() {
305
		return count( $this->keysToTry ) > 1;
306
	}
307
308
	/**
309
	 * @since 1.24
310
	 *
311
	 * @return string[] The list of keys to try when fetching the message text,
312
	 * in order of preference.
313
	 */
314
	public function getKeysToTry() {
315
		return $this->keysToTry;
316
	}
317
318
	/**
319
	 * Returns the message key.
320
	 *
321
	 * If a list of multiple possible keys was supplied to the constructor, this method may
322
	 * return any of these keys. After the message has been fetched, this method will return
323
	 * the key that was actually used to fetch the message.
324
	 *
325
	 * @since 1.21
326
	 *
327
	 * @return string
328
	 */
329
	public function getKey() {
330
		return $this->key;
331
	}
332
333
	/**
334
	 * Returns the message parameters.
335
	 *
336
	 * @since 1.21
337
	 *
338
	 * @return array
339
	 */
340
	public function getParams() {
341
		return $this->parameters;
342
	}
343
344
	/**
345
	 * Returns the message format.
346
	 *
347
	 * @since 1.21
348
	 *
349
	 * @return string
350
	 */
351
	public function getFormat() {
352
		return $this->format;
353
	}
354
355
	/**
356
	 * Returns the Language of the Message.
357
	 *
358
	 * @since 1.23
359
	 *
360
	 * @return Language
361
	 */
362
	public function getLanguage() {
363
		// Defaults to false which means current user language
364
		return $this->language ?: RequestContext::getMain()->getLanguage();
365
	}
366
367
	/**
368
	 * Factory function that is just wrapper for the real constructor. It is
369
	 * intended to be used instead of the real constructor, because it allows
370
	 * chaining method calls, while new objects don't.
371
	 *
372
	 * @since 1.17
373
	 *
374
	 * @param string|string[]|MessageSpecifier $key
375
	 * @param mixed $param,... Parameters as strings.
0 ignored issues
show
Bug introduced by
There is no parameter named $param,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
376
	 *
377
	 * @return Message
378
	 */
379
	public static function newFromKey( $key /*...*/ ) {
380
		$params = func_get_args();
381
		array_shift( $params );
382
		return new self( $key, $params );
383
	}
384
385
	/**
386
	 * Transform a MessageSpecifier or a primitive value used interchangeably with
387
	 * specifiers (a message key string, or a key + params array) into a proper Message
388
	 * @param string|array|MessageSpecifier $value
389
	 * @return Message
390
	 * @throws InvalidArgumentException
391
	 */
392
	public static function newFromSpecifier( $value ) {
393
		if ( $value instanceof RawMessage ) {
394
			$message = new RawMessage( $value->getKey(), $value->getParams() );
395
		} elseif ( $value instanceof MessageSpecifier ) {
396
			$message = new Message( $value );
397
		} elseif ( is_array( $value ) ) {
398
			$key = array_shift( $value );
399
			$message = new Message( $key, $value );
400
		} elseif ( is_string( $value ) ) {
401
			$message = new Message( $value );
402
		} else {
403
			throw new InvalidArgumentException( __METHOD__ . ': invalid argument type '
404
				. gettype( $value ) );
405
		}
406
407
		return $message;
408
	}
409
410
	/**
411
	 * Factory function accepting multiple message keys and returning a message instance
412
	 * for the first message which is non-empty. If all messages are empty then an
413
	 * instance of the first message key is returned.
414
	 *
415
	 * @since 1.18
416
	 *
417
	 * @param string|string[] $keys,... Message keys, or first argument as an array of all the
0 ignored issues
show
Bug introduced by
There is no parameter named $keys,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
418
	 * message keys.
419
	 *
420
	 * @return Message
421
	 */
422
	public static function newFallbackSequence( /*...*/ ) {
423
		$keys = func_get_args();
424
		if ( func_num_args() == 1 ) {
425
			if ( is_array( $keys[0] ) ) {
426
				// Allow an array to be passed as the first argument instead
427
				$keys = array_values( $keys[0] );
428
			} else {
429
				// Optimize a single string to not need special fallback handling
430
				$keys = $keys[0];
431
			}
432
		}
433
		return new self( $keys );
434
	}
435
436
	/**
437
	 * Get a title object for a mediawiki message, where it can be found in the mediawiki namespace.
438
	 * The title will be for the current language, if the message key is in
439
	 * $wgForceUIMsgAsContentMsg it will be append with the language code (except content
440
	 * language), because Message::inContentLanguage will also return in user language.
441
	 *
442
	 * @see $wgForceUIMsgAsContentMsg
443
	 * @return Title
444
	 * @since 1.26
445
	 */
446
	public function getTitle() {
447
		global $wgContLang, $wgForceUIMsgAsContentMsg;
448
449
		$code = $this->getLanguage()->getCode();
450
		$title = $this->key;
451
		if (
452
			$wgContLang->getCode() !== $code
453
			&& in_array( $this->key, (array)$wgForceUIMsgAsContentMsg )
454
		) {
455
			$title .= '/' . $code;
456
		}
457
458
		return Title::makeTitle( NS_MEDIAWIKI, $wgContLang->ucfirst( strtr( $title, ' ', '_' ) ) );
459
	}
460
461
	/**
462
	 * Adds parameters to the parameter list of this message.
463
	 *
464
	 * @since 1.17
465
	 *
466
	 * @param mixed ... Parameters as strings, or a single argument that is
467
	 * an array of strings.
468
	 *
469
	 * @return Message $this
470
	 */
471
	public function params( /*...*/ ) {
472
		$args = func_get_args();
473 View Code Duplication
		if ( isset( $args[0] ) && is_array( $args[0] ) ) {
474
			$args = $args[0];
475
		}
476
		$args_values = array_values( $args );
477
		$this->parameters = array_merge( $this->parameters, $args_values );
478
		return $this;
479
	}
480
481
	/**
482
	 * Add parameters that are substituted after parsing or escaping.
483
	 * In other words the parsing process cannot access the contents
484
	 * of this type of parameter, and you need to make sure it is
485
	 * sanitized beforehand.  The parser will see "$n", instead.
486
	 *
487
	 * @since 1.17
488
	 *
489
	 * @param mixed $params,... Raw parameters as strings, or a single argument that is
0 ignored issues
show
Bug introduced by
There is no parameter named $params,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
490
	 * an array of raw parameters.
491
	 *
492
	 * @return Message $this
493
	 */
494 View Code Duplication
	public function rawParams( /*...*/ ) {
495
		$params = func_get_args();
496
		if ( isset( $params[0] ) && is_array( $params[0] ) ) {
497
			$params = $params[0];
498
		}
499
		foreach ( $params as $param ) {
500
			$this->parameters[] = self::rawParam( $param );
501
		}
502
		return $this;
503
	}
504
505
	/**
506
	 * Add parameters that are numeric and will be passed through
507
	 * Language::formatNum before substitution
508
	 *
509
	 * @since 1.18
510
	 *
511
	 * @param mixed $param,... Numeric parameters, or a single argument that is
0 ignored issues
show
Bug introduced by
There is no parameter named $param,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
512
	 * an array of numeric parameters.
513
	 *
514
	 * @return Message $this
515
	 */
516 View Code Duplication
	public function numParams( /*...*/ ) {
517
		$params = func_get_args();
518
		if ( isset( $params[0] ) && is_array( $params[0] ) ) {
519
			$params = $params[0];
520
		}
521
		foreach ( $params as $param ) {
522
			$this->parameters[] = self::numParam( $param );
523
		}
524
		return $this;
525
	}
526
527
	/**
528
	 * Add parameters that are durations of time and will be passed through
529
	 * Language::formatDuration before substitution
530
	 *
531
	 * @since 1.22
532
	 *
533
	 * @param int|int[] $param,... Duration parameters, or a single argument that is
0 ignored issues
show
Bug introduced by
There is no parameter named $param,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
534
	 * an array of duration parameters.
535
	 *
536
	 * @return Message $this
537
	 */
538 View Code Duplication
	public function durationParams( /*...*/ ) {
539
		$params = func_get_args();
540
		if ( isset( $params[0] ) && is_array( $params[0] ) ) {
541
			$params = $params[0];
542
		}
543
		foreach ( $params as $param ) {
544
			$this->parameters[] = self::durationParam( $param );
545
		}
546
		return $this;
547
	}
548
549
	/**
550
	 * Add parameters that are expiration times and will be passed through
551
	 * Language::formatExpiry before substitution
552
	 *
553
	 * @since 1.22
554
	 *
555
	 * @param string|string[] $param,... Expiry parameters, or a single argument that is
0 ignored issues
show
Bug introduced by
There is no parameter named $param,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
556
	 * an array of expiry parameters.
557
	 *
558
	 * @return Message $this
559
	 */
560 View Code Duplication
	public function expiryParams( /*...*/ ) {
561
		$params = func_get_args();
562
		if ( isset( $params[0] ) && is_array( $params[0] ) ) {
563
			$params = $params[0];
564
		}
565
		foreach ( $params as $param ) {
566
			$this->parameters[] = self::expiryParam( $param );
567
		}
568
		return $this;
569
	}
570
571
	/**
572
	 * Add parameters that are time periods and will be passed through
573
	 * Language::formatTimePeriod before substitution
574
	 *
575
	 * @since 1.22
576
	 *
577
	 * @param int|int[] $param,... Time period parameters, or a single argument that is
0 ignored issues
show
Bug introduced by
There is no parameter named $param,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
578
	 * an array of time period parameters.
579
	 *
580
	 * @return Message $this
581
	 */
582 View Code Duplication
	public function timeperiodParams( /*...*/ ) {
583
		$params = func_get_args();
584
		if ( isset( $params[0] ) && is_array( $params[0] ) ) {
585
			$params = $params[0];
586
		}
587
		foreach ( $params as $param ) {
588
			$this->parameters[] = self::timeperiodParam( $param );
589
		}
590
		return $this;
591
	}
592
593
	/**
594
	 * Add parameters that are file sizes and will be passed through
595
	 * Language::formatSize before substitution
596
	 *
597
	 * @since 1.22
598
	 *
599
	 * @param int|int[] $param,... Size parameters, or a single argument that is
0 ignored issues
show
Bug introduced by
There is no parameter named $param,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
600
	 * an array of size parameters.
601
	 *
602
	 * @return Message $this
603
	 */
604 View Code Duplication
	public function sizeParams( /*...*/ ) {
605
		$params = func_get_args();
606
		if ( isset( $params[0] ) && is_array( $params[0] ) ) {
607
			$params = $params[0];
608
		}
609
		foreach ( $params as $param ) {
610
			$this->parameters[] = self::sizeParam( $param );
611
		}
612
		return $this;
613
	}
614
615
	/**
616
	 * Add parameters that are bitrates and will be passed through
617
	 * Language::formatBitrate before substitution
618
	 *
619
	 * @since 1.22
620
	 *
621
	 * @param int|int[] $param,... Bit rate parameters, or a single argument that is
0 ignored issues
show
Bug introduced by
There is no parameter named $param,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
622
	 * an array of bit rate parameters.
623
	 *
624
	 * @return Message $this
625
	 */
626 View Code Duplication
	public function bitrateParams( /*...*/ ) {
627
		$params = func_get_args();
628
		if ( isset( $params[0] ) && is_array( $params[0] ) ) {
629
			$params = $params[0];
630
		}
631
		foreach ( $params as $param ) {
632
			$this->parameters[] = self::bitrateParam( $param );
633
		}
634
		return $this;
635
	}
636
637
	/**
638
	 * Add parameters that are plaintext and will be passed through without
639
	 * the content being evaluated.  Plaintext parameters are not valid as
640
	 * arguments to parser functions. This differs from self::rawParams in
641
	 * that the Message class handles escaping to match the output format.
642
	 *
643
	 * @since 1.25
644
	 *
645
	 * @param string|string[] $param,... plaintext parameters, or a single argument that is
0 ignored issues
show
Bug introduced by
There is no parameter named $param,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
646
	 * an array of plaintext parameters.
647
	 *
648
	 * @return Message $this
649
	 */
650 View Code Duplication
	public function plaintextParams( /*...*/ ) {
651
		$params = func_get_args();
652
		if ( isset( $params[0] ) && is_array( $params[0] ) ) {
653
			$params = $params[0];
654
		}
655
		foreach ( $params as $param ) {
656
			$this->parameters[] = self::plaintextParam( $param );
657
		}
658
		return $this;
659
	}
660
661
	/**
662
	 * Set the language and the title from a context object
663
	 *
664
	 * @since 1.19
665
	 *
666
	 * @param IContextSource $context
667
	 *
668
	 * @return Message $this
669
	 */
670
	public function setContext( IContextSource $context ) {
671
		$this->inLanguage( $context->getLanguage() );
672
		$this->title( $context->getTitle() );
0 ignored issues
show
Bug introduced by
It seems like $context->getTitle() can be null; however, title() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
673
		$this->interface = true;
674
675
		return $this;
676
	}
677
678
	/**
679
	 * Request the message in any language that is supported.
680
	 *
681
	 * As a side effect interface message status is unconditionally
682
	 * turned off.
683
	 *
684
	 * @since 1.17
685
	 * @param Language|string $lang Language code or Language object.
686
	 * @return Message $this
687
	 * @throws MWException
688
	 */
689
	public function inLanguage( $lang ) {
690
		if ( $lang instanceof Language ) {
691
			$this->language = $lang;
692
		} elseif ( is_string( $lang ) ) {
693
			if ( !$this->language instanceof Language || $this->language->getCode() != $lang ) {
694
				$this->language = Language::factory( $lang );
695
			}
696
		} elseif ( $lang instanceof StubUserLang ) {
697
			$this->language = false;
698
		} else {
699
			$type = gettype( $lang );
700
			throw new MWException( __METHOD__ . " must be "
701
				. "passed a String or Language object; $type given"
702
			);
703
		}
704
		$this->message = null;
705
		$this->interface = false;
706
		return $this;
707
	}
708
709
	/**
710
	 * Request the message in the wiki's content language,
711
	 * unless it is disabled for this message.
712
	 *
713
	 * @since 1.17
714
	 * @see $wgForceUIMsgAsContentMsg
715
	 *
716
	 * @return Message $this
717
	 */
718
	public function inContentLanguage() {
719
		global $wgForceUIMsgAsContentMsg;
720
		if ( in_array( $this->key, (array)$wgForceUIMsgAsContentMsg ) ) {
721
			return $this;
722
		}
723
724
		global $wgContLang;
725
		$this->inLanguage( $wgContLang );
726
		return $this;
727
	}
728
729
	/**
730
	 * Allows manipulating the interface message flag directly.
731
	 * Can be used to restore the flag after setting a language.
732
	 *
733
	 * @since 1.20
734
	 *
735
	 * @param bool $interface
736
	 *
737
	 * @return Message $this
738
	 */
739
	public function setInterfaceMessageFlag( $interface ) {
740
		$this->interface = (bool)$interface;
741
		return $this;
742
	}
743
744
	/**
745
	 * Enable or disable database use.
746
	 *
747
	 * @since 1.17
748
	 *
749
	 * @param bool $useDatabase
750
	 *
751
	 * @return Message $this
752
	 */
753
	public function useDatabase( $useDatabase ) {
754
		$this->useDatabase = (bool)$useDatabase;
755
		return $this;
756
	}
757
758
	/**
759
	 * Set the Title object to use as context when transforming the message
760
	 *
761
	 * @since 1.18
762
	 *
763
	 * @param Title $title
764
	 *
765
	 * @return Message $this
766
	 */
767
	public function title( $title ) {
768
		$this->title = $title;
769
		return $this;
770
	}
771
772
	/**
773
	 * Returns the message as a Content object.
774
	 *
775
	 * @return Content
776
	 */
777
	public function content() {
778
		if ( !$this->content ) {
779
			$this->content = new MessageContent( $this );
780
		}
781
782
		return $this->content;
783
	}
784
785
	/**
786
	 * Returns the message parsed from wikitext to HTML.
787
	 *
788
	 * @since 1.17
789
	 *
790
	 * @return string HTML
791
	 */
792
	public function toString() {
793
		$string = $this->fetchMessage();
794
795
		if ( $string === false ) {
796 View Code Duplication
			if ( $this->format === 'plain' || $this->format === 'text' ) {
797
				return '<' . $this->key . '>';
798
			}
799
			return '&lt;' . htmlspecialchars( $this->key ) . '&gt;';
800
		}
801
802
		# Replace $* with a list of parameters for &uselang=qqx.
803
		if ( strpos( $string, '$*' ) !== false ) {
804
			$paramlist = '';
805
			if ( $this->parameters !== [] ) {
806
				$paramlist = ': $' . implode( ', $', range( 1, count( $this->parameters ) ) );
807
			}
808
			$string = str_replace( '$*', $paramlist, $string );
809
		}
810
811
		# Replace parameters before text parsing
812
		$string = $this->replaceParameters( $string, 'before' );
813
814
		# Maybe transform using the full parser
815
		if ( $this->format === 'parse' ) {
816
			$string = $this->parseText( $string );
817
			$string = Parser::stripOuterParagraph( $string );
818
		} elseif ( $this->format === 'block-parse' ) {
819
			$string = $this->parseText( $string );
820
		} elseif ( $this->format === 'text' ) {
821
			$string = $this->transformText( $string );
822
		} elseif ( $this->format === 'escaped' ) {
823
			$string = $this->transformText( $string );
824
			$string = htmlspecialchars( $string, ENT_QUOTES, 'UTF-8', false );
825
		}
826
827
		# Raw parameter replacement
828
		$string = $this->replaceParameters( $string, 'after' );
829
830
		return $string;
831
	}
832
833
	/**
834
	 * Magic method implementation of the above (for PHP >= 5.2.0), so we can do, eg:
835
	 *     $foo = new Message( $key );
836
	 *     $string = "<abbr>$foo</abbr>";
837
	 *
838
	 * @since 1.18
839
	 *
840
	 * @return string
841
	 */
842
	public function __toString() {
843
		// PHP doesn't allow __toString to throw exceptions and will
844
		// trigger a fatal error if it does. So, catch any exceptions.
845
846
		try {
847
			return $this->toString();
848
		} catch ( Exception $ex ) {
849
			try {
850
				trigger_error( "Exception caught in " . __METHOD__ . " (message " . $this->key . "): "
851
					. $ex, E_USER_WARNING );
852
			} catch ( Exception $ex ) {
853
				// Doh! Cause a fatal error after all?
854
			}
855
856 View Code Duplication
			if ( $this->format === 'plain' || $this->format === 'text' ) {
857
				return '<' . $this->key . '>';
858
			}
859
			return '&lt;' . htmlspecialchars( $this->key ) . '&gt;';
860
		}
861
	}
862
863
	/**
864
	 * Fully parse the text from wikitext to HTML.
865
	 *
866
	 * @since 1.17
867
	 *
868
	 * @return string Parsed HTML.
869
	 */
870
	public function parse() {
871
		$this->format = 'parse';
872
		return $this->toString();
873
	}
874
875
	/**
876
	 * Returns the message text. {{-transformation is done.
877
	 *
878
	 * @since 1.17
879
	 *
880
	 * @return string Unescaped message text.
881
	 */
882
	public function text() {
883
		$this->format = 'text';
884
		return $this->toString();
885
	}
886
887
	/**
888
	 * Returns the message text as-is, only parameters are substituted.
889
	 *
890
	 * @since 1.17
891
	 *
892
	 * @return string Unescaped untransformed message text.
893
	 */
894
	public function plain() {
895
		$this->format = 'plain';
896
		return $this->toString();
897
	}
898
899
	/**
900
	 * Returns the parsed message text which is always surrounded by a block element.
901
	 *
902
	 * @since 1.17
903
	 *
904
	 * @return string HTML
905
	 */
906
	public function parseAsBlock() {
907
		$this->format = 'block-parse';
908
		return $this->toString();
909
	}
910
911
	/**
912
	 * Returns the message text. {{-transformation is done and the result
913
	 * is escaped excluding any raw parameters.
914
	 *
915
	 * @since 1.17
916
	 *
917
	 * @return string Escaped message text.
918
	 */
919
	public function escaped() {
920
		$this->format = 'escaped';
921
		return $this->toString();
922
	}
923
924
	/**
925
	 * Check whether a message key has been defined currently.
926
	 *
927
	 * @since 1.17
928
	 *
929
	 * @return bool
930
	 */
931
	public function exists() {
932
		return $this->fetchMessage() !== false;
933
	}
934
935
	/**
936
	 * Check whether a message does not exist, or is an empty string
937
	 *
938
	 * @since 1.18
939
	 * @todo FIXME: Merge with isDisabled()?
940
	 *
941
	 * @return bool
942
	 */
943
	public function isBlank() {
944
		$message = $this->fetchMessage();
945
		return $message === false || $message === '';
946
	}
947
948
	/**
949
	 * Check whether a message does not exist, is an empty string, or is "-".
950
	 *
951
	 * @since 1.18
952
	 *
953
	 * @return bool
954
	 */
955
	public function isDisabled() {
956
		$message = $this->fetchMessage();
957
		return $message === false || $message === '' || $message === '-';
958
	}
959
960
	/**
961
	 * @since 1.17
962
	 *
963
	 * @param mixed $raw
964
	 *
965
	 * @return array Array with a single "raw" key.
966
	 */
967
	public static function rawParam( $raw ) {
968
		return [ 'raw' => $raw ];
969
	}
970
971
	/**
972
	 * @since 1.18
973
	 *
974
	 * @param mixed $num
975
	 *
976
	 * @return array Array with a single "num" key.
977
	 */
978
	public static function numParam( $num ) {
979
		return [ 'num' => $num ];
980
	}
981
982
	/**
983
	 * @since 1.22
984
	 *
985
	 * @param int $duration
986
	 *
987
	 * @return int[] Array with a single "duration" key.
988
	 */
989
	public static function durationParam( $duration ) {
990
		return [ 'duration' => $duration ];
991
	}
992
993
	/**
994
	 * @since 1.22
995
	 *
996
	 * @param string $expiry
997
	 *
998
	 * @return string[] Array with a single "expiry" key.
999
	 */
1000
	public static function expiryParam( $expiry ) {
1001
		return [ 'expiry' => $expiry ];
1002
	}
1003
1004
	/**
1005
	 * @since 1.22
1006
	 *
1007
	 * @param number $period
1008
	 *
1009
	 * @return number[] Array with a single "period" key.
1010
	 */
1011
	public static function timeperiodParam( $period ) {
1012
		return [ 'period' => $period ];
1013
	}
1014
1015
	/**
1016
	 * @since 1.22
1017
	 *
1018
	 * @param int $size
1019
	 *
1020
	 * @return int[] Array with a single "size" key.
1021
	 */
1022
	public static function sizeParam( $size ) {
1023
		return [ 'size' => $size ];
1024
	}
1025
1026
	/**
1027
	 * @since 1.22
1028
	 *
1029
	 * @param int $bitrate
1030
	 *
1031
	 * @return int[] Array with a single "bitrate" key.
1032
	 */
1033
	public static function bitrateParam( $bitrate ) {
1034
		return [ 'bitrate' => $bitrate ];
1035
	}
1036
1037
	/**
1038
	 * @since 1.25
1039
	 *
1040
	 * @param string $plaintext
1041
	 *
1042
	 * @return string[] Array with a single "plaintext" key.
1043
	 */
1044
	public static function plaintextParam( $plaintext ) {
1045
		return [ 'plaintext' => $plaintext ];
1046
	}
1047
1048
	/**
1049
	 * Substitutes any parameters into the message text.
1050
	 *
1051
	 * @since 1.17
1052
	 *
1053
	 * @param string $message The message text.
1054
	 * @param string $type Either "before" or "after".
1055
	 *
1056
	 * @return string
1057
	 */
1058
	protected function replaceParameters( $message, $type = 'before' ) {
1059
		$replacementKeys = [];
1060
		foreach ( $this->parameters as $n => $param ) {
1061
			list( $paramType, $value ) = $this->extractParam( $param );
1062
			if ( $type === $paramType ) {
1063
				$replacementKeys['$' . ( $n + 1 )] = $value;
1064
			}
1065
		}
1066
		$message = strtr( $message, $replacementKeys );
1067
		return $message;
1068
	}
1069
1070
	/**
1071
	 * Extracts the parameter type and preprocessed the value if needed.
1072
	 *
1073
	 * @since 1.18
1074
	 *
1075
	 * @param mixed $param Parameter as defined in this class.
1076
	 *
1077
	 * @return array Array with the parameter type (either "before" or "after") and the value.
1078
	 */
1079
	protected function extractParam( $param ) {
1080
		if ( is_array( $param ) ) {
1081
			if ( isset( $param['raw'] ) ) {
1082
				return [ 'after', $param['raw'] ];
1083 View Code Duplication
			} elseif ( isset( $param['num'] ) ) {
1084
				// Replace number params always in before step for now.
1085
				// No support for combined raw and num params
1086
				return [ 'before', $this->getLanguage()->formatNum( $param['num'] ) ];
1087
			} elseif ( isset( $param['duration'] ) ) {
1088
				return [ 'before', $this->getLanguage()->formatDuration( $param['duration'] ) ];
1089
			} elseif ( isset( $param['expiry'] ) ) {
1090
				return [ 'before', $this->getLanguage()->formatExpiry( $param['expiry'] ) ];
1091
			} elseif ( isset( $param['period'] ) ) {
1092
				return [ 'before', $this->getLanguage()->formatTimePeriod( $param['period'] ) ];
1093 View Code Duplication
			} elseif ( isset( $param['size'] ) ) {
1094
				return [ 'before', $this->getLanguage()->formatSize( $param['size'] ) ];
1095
			} elseif ( isset( $param['bitrate'] ) ) {
1096
				return [ 'before', $this->getLanguage()->formatBitrate( $param['bitrate'] ) ];
1097
			} elseif ( isset( $param['plaintext'] ) ) {
1098
				return [ 'after', $this->formatPlaintext( $param['plaintext'] ) ];
1099
			} else {
1100
				$warning = 'Invalid parameter for message "' . $this->getKey() . '": ' .
1101
					htmlspecialchars( serialize( $param ) );
1102
				trigger_error( $warning, E_USER_WARNING );
1103
				$e = new Exception;
1104
				wfDebugLog( 'Bug58676', $warning . "\n" . $e->getTraceAsString() );
1105
1106
				return [ 'before', '[INVALID]' ];
1107
			}
1108
		} elseif ( $param instanceof Message ) {
1109
			// Message objects should not be before parameters because
1110
			// then they'll get double escaped. If the message needs to be
1111
			// escaped, it'll happen right here when we call toString().
1112
			return [ 'after', $param->toString() ];
1113
		} else {
1114
			return [ 'before', $param ];
1115
		}
1116
	}
1117
1118
	/**
1119
	 * Wrapper for what ever method we use to parse wikitext.
1120
	 *
1121
	 * @since 1.17
1122
	 *
1123
	 * @param string $string Wikitext message contents.
1124
	 *
1125
	 * @return string Wikitext parsed into HTML.
1126
	 */
1127
	protected function parseText( $string ) {
1128
		$out = MessageCache::singleton()->parse(
1129
			$string,
1130
			$this->title,
1131
			/*linestart*/true,
1132
			$this->interface,
1133
			$this->getLanguage()
1134
		);
1135
1136
		return $out instanceof ParserOutput ? $out->getText() : $out;
1137
	}
1138
1139
	/**
1140
	 * Wrapper for what ever method we use to {{-transform wikitext.
1141
	 *
1142
	 * @since 1.17
1143
	 *
1144
	 * @param string $string Wikitext message contents.
1145
	 *
1146
	 * @return string Wikitext with {{-constructs replaced with their values.
1147
	 */
1148
	protected function transformText( $string ) {
1149
		return MessageCache::singleton()->transform(
1150
			$string,
1151
			$this->interface,
1152
			$this->getLanguage(),
1153
			$this->title
1154
		);
1155
	}
1156
1157
	/**
1158
	 * Wrapper for what ever method we use to get message contents.
1159
	 *
1160
	 * @since 1.17
1161
	 *
1162
	 * @return string
1163
	 * @throws MWException If message key array is empty.
1164
	 */
1165
	protected function fetchMessage() {
1166
		if ( $this->message === null ) {
1167
			$cache = MessageCache::singleton();
1168
1169
			foreach ( $this->keysToTry as $key ) {
1170
				$message = $cache->get( $key, $this->useDatabase, $this->getLanguage() );
1171
				if ( $message !== false && $message !== '' ) {
1172
					break;
1173
				}
1174
			}
1175
1176
			// NOTE: The constructor makes sure keysToTry isn't empty,
1177
			//       so we know that $key and $message are initialized.
1178
			$this->key = $key;
0 ignored issues
show
Bug introduced by
The variable $key seems to be defined by a foreach iteration on line 1169. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
1179
			$this->message = $message;
0 ignored issues
show
Bug introduced by
The variable $message does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Documentation Bug introduced by
It seems like $message can also be of type false. However, the property $message is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
1180
		}
1181
		return $this->message;
1182
	}
1183
1184
	/**
1185
	 * Formats a message parameter wrapped with 'plaintext'. Ensures that
1186
	 * the entire string is displayed unchanged when displayed in the output
1187
	 * format.
1188
	 *
1189
	 * @since 1.25
1190
	 *
1191
	 * @param string $plaintext String to ensure plaintext output of
1192
	 *
1193
	 * @return string Input plaintext encoded for output to $this->format
1194
	 */
1195
	protected function formatPlaintext( $plaintext ) {
1196
		switch ( $this->format ) {
1197
		case 'text':
1198
		case 'plain':
1199
			return $plaintext;
1200
1201
		case 'parse':
1202
		case 'block-parse':
1203
		case 'escaped':
1204
		default:
1205
			return htmlspecialchars( $plaintext, ENT_QUOTES );
1206
1207
		}
1208
	}
1209
}
1210
1211
/**
1212
 * Variant of the Message class.
1213
 *
1214
 * Rather than treating the message key as a lookup
1215
 * value (which is passed to the MessageCache and
1216
 * translated as necessary), a RawMessage key is
1217
 * treated as the actual message.
1218
 *
1219
 * All other functionality (parsing, escaping, etc.)
1220
 * is preserved.
1221
 *
1222
 * @since 1.21
1223
 */
1224
class RawMessage extends Message {
1225
1226
	/**
1227
	 * Call the parent constructor, then store the key as
1228
	 * the message.
1229
	 *
1230
	 * @see Message::__construct
1231
	 *
1232
	 * @param string $text Message to use.
1233
	 * @param array $params Parameters for the message.
1234
	 *
1235
	 * @throws InvalidArgumentException
1236
	 */
1237
	public function __construct( $text, $params = [] ) {
1238
		if ( !is_string( $text ) ) {
1239
			throw new InvalidArgumentException( '$text must be a string' );
1240
		}
1241
1242
		parent::__construct( $text, $params );
1243
1244
		// The key is the message.
1245
		$this->message = $text;
1246
	}
1247
1248
	/**
1249
	 * Fetch the message (in this case, the key).
1250
	 *
1251
	 * @return string
1252
	 */
1253
	public function fetchMessage() {
1254
		// Just in case the message is unset somewhere.
1255
		if ( $this->message === null ) {
1256
			$this->message = $this->key;
1257
		}
1258
1259
		return $this->message;
1260
	}
1261
1262
}
1263