Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
73.17% covered (warning)
73.17%
30 / 41
62.50% covered (warning)
62.50%
5 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
ListParam
73.17% covered (warning)
73.17%
30 / 41
62.50% covered (warning)
62.50%
5 / 8
29.52
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
4
 getListType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 dump
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 isSameAs
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
 toJsonArray
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 jsonClassHintFor
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 newFromJsonArray
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
4.59
 __wakeup
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace Wikimedia\Message;
4
5use InvalidArgumentException;
6use Wikimedia\JsonCodec\Hint;
7
8/**
9 * Value object representing a message parameter that consists of a list of values.
10 *
11 * Message parameter classes are pure value objects and are newable and (de)serializable.
12 *
13 * @newable
14 */
15class ListParam extends MessageParam {
16
17    // We can't use PHP type hint here without breaking deserialization of
18    // old ListParams saved with PHP serialize().
19    /** @var ListType */
20    private $listType;
21
22    /**
23     * @stable to call.
24     *
25     * @param string|ListType $listType One of the ListType constants.
26     * @param (MessageParam|MessageSpecifier|string|int|float)[] $elements Values in the list.
27     *  Values that are not instances of MessageParam are wrapped using ParamType::TEXT.
28     */
29    public function __construct( string|ListType $listType, array $elements ) {
30        if ( is_string( $listType ) ) {
31            wfDeprecated( __METHOD__ . ' with string listType', '1.45' );
32            $listType = ListType::from( $listType );
33        }
34        $this->type = ParamType::LIST;
35        $this->listType = $listType;
36        $this->value = [];
37        foreach ( $elements as $element ) {
38            if ( $element instanceof MessageParam ) {
39                $this->value[] = $element;
40            } else {
41                $this->value[] = new ScalarParam( ParamType::TEXT, $element );
42            }
43        }
44    }
45
46    /**
47     * Get the type of the list
48     *
49     * @return ListType One of the ListType constants
50     */
51    public function getListType(): ListType {
52        return $this->listType;
53    }
54
55    public function dump(): string {
56        $contents = '';
57        foreach ( $this->value as $element ) {
58            $contents .= $element->dump();
59        }
60        return "<{$this->type->value} listType=\"{$this->listType->value}\">$contents</{$this->type->value}>";
61    }
62
63    public function isSameAs( MessageParam $mp ): bool {
64        return $mp instanceof ListParam &&
65            $this->listType === $mp->listType &&
66            count( $this->value ) === count( $mp->value ) &&
67            array_all(
68                $this->value,
69                static fn ( $v, $k ) => $v->isSameAs( $mp->value[$k] )
70            );
71    }
72
73    public function toJsonArray(): array {
74        // WARNING: When changing how this class is serialized, follow the instructions
75        // at <https://www.mediawiki.org/wiki/Manual:Parser_cache/Serialization_compatibility>!
76        return [
77            $this->type->value => array_map(
78                /**
79                 * Serialize trivial parameters as scalar values to minimize the footprint. Full
80                 * round-trip compatibility is guaranteed via the constructor.
81                 */
82                static fn ( $p ) => $p->getType() === ParamType::TEXT ? $p->getValue() : $p,
83                $this->value
84            ),
85            'type' => $this->listType->value,
86        ];
87    }
88
89    /** @inheritDoc */
90    public static function jsonClassHintFor( string $keyName ) {
91        // Reduce serialization overhead by eliminating the type information
92        // when the list consists of MessageParam instances
93        if ( $keyName === ParamType::LIST->value ) {
94            return Hint::build(
95                MessageParam::class, Hint::INHERITED,
96                Hint::LIST, Hint::USE_SQUARE
97            );
98        }
99        return null;
100    }
101
102    public static function newFromJsonArray( array $json ): ListParam {
103        // WARNING: When changing how this class is serialized, follow the instructions
104        // at <https://www.mediawiki.org/wiki/Manual:Parser_cache/Serialization_compatibility>!
105        if ( count( $json ) !== 2 || !isset( $json[ParamType::LIST->value] ) || !isset( $json['type'] ) ) {
106            throw new InvalidArgumentException( 'Invalid format' );
107        }
108        return new self( ListType::from( $json['type'] ), $json[ParamType::LIST->value] );
109    }
110
111    public function __wakeup(): void {
112        parent::__wakeup();
113        // Backward-compatibility for PHP serialization:
114        // Fixup $type after deserialization
115        if ( is_string( $this->listType ) ) {
116            $this->listType = ListType::from( $this->listType );
117        }
118    }
119}