Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.87% covered (success)
97.87%
46 / 47
96.43% covered (success)
96.43%
27 / 28
CRAP
0.00% covered (danger)
0.00%
0 / 1
MessageValue
97.87% covered (success)
97.87%
46 / 47
96.43% covered (success)
96.43%
27 / 28
34
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 new
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 newFromSpecifier
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
 getKey
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getParams
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 params
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 textParamsOfType
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 listParamsOfType
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 textParams
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 numParams
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 longDurationParams
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 shortDurationParams
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 expiryParams
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 dateTimeParams
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 dateParams
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 timeParams
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 userGroupParams
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 sizeParams
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 bitrateParams
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 rawParams
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 plaintextParams
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 commaListParams
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 semicolonListParams
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 pipeListParams
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 textListParams
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 dump
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 toJsonArray
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 newFromJsonArray
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
17 *
18 * @file
19 */
20
21namespace Wikimedia\Message;
22
23use Wikimedia\JsonCodec\JsonCodecable;
24use Wikimedia\JsonCodec\JsonCodecableTrait;
25
26/**
27 * Value object representing a message for i18n.
28 *
29 * A MessageValue holds a key and an array of parameters. It can be converted
30 * to a string in a particular language using formatters obtained from an
31 * IMessageFormatterFactory.
32 *
33 * MessageValues are pure value objects and are newable and (de)serializable.
34 *
35 * @newable
36 */
37class MessageValue implements MessageSpecifier, JsonCodecable {
38    use JsonCodecableTrait;
39
40    private string $key;
41
42    /** @var MessageParam[] */
43    private array $params;
44
45    /**
46     * @stable to call
47     *
48     * @param string $key
49     * @param (MessageParam|MessageSpecifier|string|int|float)[] $params Values that are not instances
50     *  of MessageParam are wrapped using ParamType::TEXT.
51     */
52    public function __construct( string $key, array $params = [] ) {
53        $this->key = $key;
54        $this->params = [];
55        $this->params( ...$params );
56    }
57
58    /**
59     * Static constructor for easier chaining of `->params()` methods
60     * @param string $key
61     * @param (MessageParam|MessageSpecifier|string|int|float)[] $params
62     * @return MessageValue
63     */
64    public static function new( string $key, array $params = [] ): MessageValue {
65        return new MessageValue( $key, $params );
66    }
67
68    /**
69     * Convert from any MessageSpecifier to a MessageValue.
70     *
71     * When the given object is an instance of MessageValue, the same object is returned.
72     *
73     * @since MediaWiki 1.43
74     * @param MessageSpecifier $spec
75     * @return MessageValue
76     */
77    public static function newFromSpecifier( MessageSpecifier $spec ): MessageValue {
78        if ( $spec instanceof MessageValue ) {
79            return $spec;
80        }
81        return new MessageValue( $spec->getKey(), $spec->getParams() );
82    }
83
84    /**
85     * Get the message key
86     *
87     * @return string
88     */
89    public function getKey(): string {
90        return $this->key;
91    }
92
93    /**
94     * Get the parameter array
95     *
96     * @return MessageParam[]
97     */
98    public function getParams(): array {
99        return $this->params;
100    }
101
102    /**
103     * Chainable mutator which adds text parameters and MessageParam parameters
104     *
105     * @param MessageParam|MessageSpecifier|string|int|float ...$values
106     * @return $this
107     */
108    public function params( ...$values ): MessageValue {
109        foreach ( $values as $value ) {
110            if ( $value instanceof MessageParam ) {
111                $this->params[] = $value;
112            } else {
113                $this->params[] = new ScalarParam( ParamType::TEXT, $value );
114            }
115        }
116        return $this;
117    }
118
119    /**
120     * Chainable mutator which adds text parameters with a common type
121     *
122     * @param string $type One of the ParamType constants
123     * @param MessageSpecifier|string|int|float ...$values Scalar values
124     * @return $this
125     */
126    public function textParamsOfType( string $type, ...$values ): MessageValue {
127        foreach ( $values as $value ) {
128            $this->params[] = new ScalarParam( $type, $value );
129        }
130        return $this;
131    }
132
133    /**
134     * Chainable mutator which adds list parameters with a common type
135     *
136     * @param string $listType One of the ListType constants
137     * @param (MessageParam|MessageSpecifier|string|int|float)[] ...$values Each value
138     *  is an array of items suitable to pass as $params to ListParam::__construct()
139     * @return $this
140     */
141    public function listParamsOfType( string $listType, ...$values ): MessageValue {
142        foreach ( $values as $value ) {
143            $this->params[] = new ListParam( $listType, $value );
144        }
145        return $this;
146    }
147
148    /**
149     * Chainable mutator which adds parameters of type text (ParamType::TEXT).
150     *
151     * @param MessageSpecifier|string|int|float ...$values
152     * @return $this
153     */
154    public function textParams( ...$values ): MessageValue {
155        return $this->textParamsOfType( ParamType::TEXT, ...$values );
156    }
157
158    /**
159     * Chainable mutator which adds numeric parameters (ParamType::NUM).
160     *
161     * @param int|float ...$values
162     * @return $this
163     */
164    public function numParams( ...$values ): MessageValue {
165        return $this->textParamsOfType( ParamType::NUM, ...$values );
166    }
167
168    /**
169     * Chainable mutator which adds parameters which are a duration specified
170     * in seconds (ParamType::DURATION_LONG).
171     *
172     * This is similar to shorDurationParams() except that the result will be
173     * more verbose.
174     *
175     * @param int|float ...$values
176     * @return $this
177     */
178    public function longDurationParams( ...$values ): MessageValue {
179        return $this->textParamsOfType( ParamType::DURATION_LONG, ...$values );
180    }
181
182    /**
183     * Chainable mutator which adds parameters which are a duration specified
184     * in seconds (ParamType::DURATION_SHORT).
185     *
186     * This is similar to longDurationParams() except that the result will be more
187     * compact.
188     *
189     * @param int|float ...$values
190     * @return $this
191     */
192    public function shortDurationParams( ...$values ): MessageValue {
193        return $this->textParamsOfType( ParamType::DURATION_SHORT, ...$values );
194    }
195
196    /**
197     * Chainable mutator which adds parameters which are an expiry timestamp (ParamType::EXPIRY).
198     *
199     * @param string ...$values Timestamp as accepted by the Wikimedia\Timestamp library,
200     *  or "infinity"
201     * @return $this
202     */
203    public function expiryParams( ...$values ): MessageValue {
204        return $this->textParamsOfType( ParamType::EXPIRY, ...$values );
205    }
206
207    /**
208     * Chainable mutator which adds parameters which are a date-time timestamp (ParamType::DATETIME).
209     *
210     * @since MediaWiki 1.36
211     * @param string ...$values Timestamp as accepted by the Wikimedia\Timestamp library.
212     * @return $this
213     */
214    public function dateTimeParams( ...$values ): MessageValue {
215        return $this->textParamsOfType( ParamType::DATETIME, ...$values );
216    }
217
218    /**
219     * Chainable mutator which adds parameters which are a date timestamp (ParamType::DATE).
220     *
221     * @since MediaWiki 1.36
222     * @param string ...$values Timestamp as accepted by the Wikimedia\Timestamp library.
223     * @return $this
224     */
225    public function dateParams( ...$values ): MessageValue {
226        return $this->textParamsOfType( ParamType::DATE, ...$values );
227    }
228
229    /**
230     * Chainable mutator which adds parameters which are a time timestamp (ParamType::TIME).
231     *
232     * @since MediaWiki 1.36
233     * @param string ...$values Timestamp as accepted by the Wikimedia\Timestamp library.
234     * @return $this
235     */
236    public function timeParams( ...$values ): MessageValue {
237        return $this->textParamsOfType( ParamType::TIME, ...$values );
238    }
239
240    /**
241     * Chainable mutator which adds parameters which are a user group (ParamType::GROUP).
242     *
243     * @since MediaWiki 1.38
244     * @param string ...$values User Groups
245     * @return $this
246     */
247    public function userGroupParams( ...$values ): MessageValue {
248        return $this->textParamsOfType( ParamType::GROUP, ...$values );
249    }
250
251    /**
252     * Chainable mutator which adds parameters which are a number of bytes (ParamType::SIZE).
253     *
254     * @param int ...$values
255     * @return $this
256     */
257    public function sizeParams( ...$values ): MessageValue {
258        return $this->textParamsOfType( ParamType::SIZE, ...$values );
259    }
260
261    /**
262     * Chainable mutator which adds parameters which are a number of bits per
263     * second (ParamType::BITRATE).
264     *
265     * @param int|float ...$values
266     * @return $this
267     */
268    public function bitrateParams( ...$values ): MessageValue {
269        return $this->textParamsOfType( ParamType::BITRATE, ...$values );
270    }
271
272    /**
273     * Chainable mutator which adds "raw" parameters (ParamType::RAW).
274     *
275     * Raw parameters are substituted after formatter processing. The caller is responsible
276     * for ensuring that the value will be safe for the intended output format, and
277     * documenting what that intended output format is.
278     *
279     * @param string ...$values
280     * @return $this
281     */
282    public function rawParams( ...$values ): MessageValue {
283        return $this->textParamsOfType( ParamType::RAW, ...$values );
284    }
285
286    /**
287     * Chainable mutator which adds plaintext parameters (ParamType::PLAINTEXT).
288     *
289     * Plaintext parameters are substituted after formatter processing. The value
290     * will be escaped by the formatter as appropriate for the target output format
291     * so as to be represented as plain text rather than as any sort of markup.
292     *
293     * @param string ...$values
294     * @return $this
295     */
296    public function plaintextParams( ...$values ): MessageValue {
297        return $this->textParamsOfType( ParamType::PLAINTEXT, ...$values );
298    }
299
300    /**
301     * Chainable mutator which adds comma lists (ListType::COMMA).
302     *
303     * The list parameters thus created are formatted as a comma-separated list,
304     * or some local equivalent.
305     *
306     * @param (MessageParam|MessageSpecifier|string|int|float)[] ...$values Each value
307     *  is an array of items suitable to pass as $params to ListParam::__construct()
308     * @return $this
309     */
310    public function commaListParams( ...$values ): MessageValue {
311        return $this->listParamsOfType( ListType::COMMA, ...$values );
312    }
313
314    /**
315     * Chainable mutator which adds semicolon lists (ListType::SEMICOLON).
316     *
317     * The list parameters thus created are formatted as a semicolon-separated
318     * list, or some local equivalent.
319     *
320     * @param (MessageParam|MessageSpecifier|string|int|float)[] ...$values Each value
321     *  is an array of items suitable to pass as $params to ListParam::__construct()
322     * @return $this
323     */
324    public function semicolonListParams( ...$values ): MessageValue {
325        return $this->listParamsOfType( ListType::SEMICOLON, ...$values );
326    }
327
328    /**
329     * Chainable mutator which adds pipe lists (ListType::PIPE).
330     *
331     * The list parameters thus created are formatted as a pipe ("|") -separated
332     * list, or some local equivalent.
333     *
334     * @param (MessageParam|MessageSpecifier|string|int|float)[] ...$values Each value
335     *  is an array of items suitable to pass as $params to ListParam::__construct()
336     * @return $this
337     */
338    public function pipeListParams( ...$values ): MessageValue {
339        return $this->listParamsOfType( ListType::PIPE, ...$values );
340    }
341
342    /**
343     * Chainable mutator which adds natural-language lists (ListType::AND).
344     *
345     * The list parameters thus created, when formatted, are joined as in natural
346     * language. In English, this means a comma-separated list, with the last
347     * two elements joined with "and".
348     *
349     * @param (MessageParam|string)[] ...$values
350     * @return $this
351     */
352    public function textListParams( ...$values ): MessageValue {
353        return $this->listParamsOfType( ListType::AND, ...$values );
354    }
355
356    /**
357     * Dump the object for testing/debugging
358     *
359     * @return string
360     */
361    public function dump(): string {
362        $contents = '';
363        foreach ( $this->params as $param ) {
364            $contents .= $param->dump();
365        }
366        return '<message key="' . htmlspecialchars( $this->key ) . '">' .
367            $contents . '</message>';
368    }
369
370    public function toJsonArray(): array {
371        // WARNING: When changing how this class is serialized, follow the instructions
372        // at <https://www.mediawiki.org/wiki/Manual:Parser_cache/Serialization_compatibility>!
373        return [
374            'key' => $this->key,
375            'params' => $this->params,
376        ];
377    }
378
379    public static function newFromJsonArray( array $json ): MessageValue {
380        // WARNING: When changing how this class is serialized, follow the instructions
381        // at <https://www.mediawiki.org/wiki/Manual:Parser_cache/Serialization_compatibility>!
382        return new self( $json['key'], $json['params'] );
383    }
384}