Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
83.87% covered (warning)
83.87%
52 / 62
92.31% covered (success)
92.31%
12 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
ZMultiLingualString
83.87% covered (warning)
83.87%
52 / 62
92.31% covered (success)
92.31%
12 / 13
24.03
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
3
 getDefinition
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
1
 isValid
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 getSerialized
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 getZValue
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getValueAsList
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 getStringForLanguageCode
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 isLanguageProvidedValue
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 getStringForLanguage
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 buildStringForLanguage
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setMonoLingualString
23.08% covered (danger)
23.08%
3 / 13
0.00% covered (danger)
0.00%
0 / 1
3.82
 setStringForLanguage
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 removeValue
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * WikiLambda ZMultiLingualString
4 *
5 * @file
6 * @ingroup Extensions
7 * @copyright 2020– Abstract Wikipedia team; see AUTHORS.txt
8 * @license MIT
9 */
10
11namespace MediaWiki\Extension\WikiLambda\ZObjects;
12
13use MediaWiki\Extension\WikiLambda\Registry\ZLangRegistry;
14use MediaWiki\Extension\WikiLambda\Registry\ZTypeRegistry;
15use MediaWiki\Extension\WikiLambda\ZErrorException;
16use MediaWiki\Extension\WikiLambda\ZObjectUtils;
17use MediaWiki\Language\Language;
18use MediaWiki\Logger\LoggerFactory;
19use RuntimeException;
20
21class ZMultiLingualString extends ZObject {
22
23    /**
24     * Create a ZMultiLingualString instance given an array or a ZTypedList of
25     * ZMonoLingualString instances. Internally this class bypasses ZTypedList
26     * and stores an array with the language Zid as key.
27     *
28     * @param ZTypedList|array $strings
29     */
30    public function __construct( $strings = [] ) {
31        foreach ( ZObjectUtils::getIterativeList( $strings ) as $index => $monoLingualString ) {
32            if ( $monoLingualString instanceof ZMonoLingualString ) {
33                $this->setMonoLingualString( $monoLingualString );
34            }
35        }
36    }
37
38    /**
39     * @inheritDoc
40     */
41    public static function getDefinition(): array {
42        return [
43            'type' => [
44                'type' => ZTypeRegistry::Z_REFERENCE,
45                'value' => ZTypeRegistry::Z_MULTILINGUALSTRING,
46            ],
47            'keys' => [
48                ZTypeRegistry::Z_MULTILINGUALSTRING_VALUE => [
49                    'type' => ZTypeRegistry::HACK_ARRAY_Z_MONOLINGUALSTRING,
50                    'required' => true,
51                ],
52            ],
53        ];
54    }
55
56    /**
57     * @inheritDoc
58     */
59    public function isValid(): bool {
60        // @phan-suppress-next-line PhanTypeSuspiciousNonTraversableForeach; it's a ZMonoLingualString[]
61        foreach ( $this->data[ ZTypeRegistry::Z_MULTILINGUALSTRING_VALUE ] ?? [] as $lang => $monolingualString ) {
62            if ( !$monolingualString->isValid() ) {
63                return false;
64            }
65        }
66        return true;
67    }
68
69    /**
70     * @inheritDoc
71     */
72    public function getSerialized( $form = self::FORM_CANONICAL ) {
73        $listType = new ZReference( ZTypeRegistry::Z_MONOLINGUALSTRING );
74        $typedList = new ZTypedList( ZTypedList::buildType( $listType ), array_values( $this->getZValue() ) );
75        return (object)[
76            ZTypeRegistry::Z_OBJECT_TYPE => $this->getZTypeObject()->getSerialized( $form ),
77            ZTypeRegistry::Z_MULTILINGUALSTRING_VALUE => $typedList->getSerialized( $form )
78        ];
79    }
80
81    /**
82     * Get the list of ZMonoLingualStrings that represent the value of this ZMultiLingualString
83     *
84     * @return array
85     */
86    public function getZValue() {
87        return $this->data[ ZTypeRegistry::Z_MULTILINGUALSTRING_VALUE ] ?? [];
88    }
89
90    /**
91     * Get the values of this ZMultiLingualString in the shape of an array
92     * with language as key and string as value
93     *
94     * @return array
95     */
96    public function getValueAsList() {
97        $multi = [];
98        foreach ( $this->getZValue() as $mono ) {
99            $multi[ $mono->getLanguage() ] = $mono->getString();
100        }
101        return $multi;
102    }
103
104    /**
105     * Fetch the ZMultiLingualString's stored value for a given MediaWiki language code (e.g.
106     * 'en' or 'zh-hant'). Note that this is a raw fetch and does not walk the language fallback
107     * chain; users are expected to use getStringForLanguage() which does.
108     *
109     * @param string $languageCode The MediaWiki language code in which the string is wanted.
110     * @return string The string, or the empty string if .
111     */
112    public function getStringForLanguageCode( string $languageCode ): string {
113        try {
114            $languageZid = ZLangRegistry::singleton()->getLanguageZidFromCode( $languageCode );
115        } catch ( ZErrorException $e ) {
116            return '';
117        }
118        return array_key_exists( $languageZid, $this->getZValue() )
119            ? $this->getZValue()[ $languageZid ]->getString()
120            : '';
121    }
122
123    /**
124     * Check if the ZMultiLingualString has a stored value for a given MediaWiki language code (e.g.
125     * 'en' or 'zh-hant'). Note that this is a raw check and does not walk the language fallback
126     * chain.
127     *
128     * @param string $languageCode The MediaWiki language code in which the string is wanted.
129     * @return bool If there is a string stored.
130     */
131    public function isLanguageProvidedValue( string $languageCode ): bool {
132        try {
133            $languageZid = ZLangRegistry::singleton()->getLanguageZidFromCode( $languageCode );
134        } catch ( ZErrorException $e ) {
135            return false;
136        }
137        return array_key_exists( $languageZid, $this->data[ ZTypeRegistry::Z_MULTILINGUALSTRING_VALUE ] ?? [] );
138    }
139
140    /**
141     * Fetch the ZMultiLingualString's stored value for a given MediaWiki language class. This will
142     * walk the language fallback chain, and provide a fallback message if there is no label defined
143     * in the given language or any of its fallback languages.
144     *
145     * @param Language $language The MediaWiki language class in which the string is wanted.
146     * @return string|null The string, the value of the wikilambda-multilingualstring-nofallback message, or null.
147     */
148    public function getStringForLanguage( Language $language ): ?string {
149        return $this->buildStringForLanguage( $language )->placeholderNoFallback()->getString();
150    }
151
152    /**
153     * Instantiate a chained builder with which you can ask for a fallback in English,
154     * or define a placeholder. At the end, either call `getString()` or `getStringAndLanguageCode()`.
155     *
156     * @param Language $language
157     * @return StringForLanguageBuilder
158     */
159    public function buildStringForLanguage( Language $language ): StringForLanguageBuilder {
160        return new StringForLanguageBuilder( $language, $this );
161    }
162
163    /**
164     * @param ZMonoLingualString $value The new value to set.
165     */
166    public function setMonoLingualString( ZMonoLingualString $value ): void {
167        $language = $value->getLanguage() ?? '';
168        if ( !is_string( $language ) ) {
169            $logger = LoggerFactory::getInstance( 'WikiLambda' );
170            $logger->warning(
171                'Label to be added to a ZMultiLingualString but not a string: {language}',
172                [
173                    'language' => $language,
174                    'value' => $value,
175                    'e' => new RuntimeException()
176                ]
177            );
178            return;
179        }
180        $this->data[ ZTypeRegistry::Z_MULTILINGUALSTRING_VALUE ][ $language ] = $value;
181    }
182
183    /**
184     * @param Language $language The MediaWiki language class in which the string is to be set.
185     * @param string $value The new string to set.
186     */
187    public function setStringForLanguage( Language $language, string $value ): void {
188        $languageCode = $language->getCode();
189        $languageZid = ZLangRegistry::singleton()->getLanguageZidFromCode( $languageCode );
190        $monolingualString = new ZMonoLingualString( new ZReference( $languageZid ), new ZString( $value ) );
191        $this->data[ ZTypeRegistry::Z_MULTILINGUALSTRING_VALUE ][ $languageZid ] = $monolingualString;
192    }
193
194    /**
195     * @param Language $language The MediaWiki language class in which the string is to be unset.
196     */
197    public function removeValue( Language $language ): void {
198        $languageCode = $language->getCode();
199        $languageZid = ZLangRegistry::singleton()->getLanguageZidFromCode( $languageCode );
200        unset( $this->data[ ZTypeRegistry::Z_MULTILINGUALSTRING_VALUE ][ $languageZid ] );
201    }
202}