Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 82 |
|
0.00% |
0 / 19 |
CRAP | |
0.00% |
0 / 1 |
Entity | |
0.00% |
0 / 82 |
|
0.00% |
0 / 19 |
1482 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
getType | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getMessageNames | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getId | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getElection | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
6 | |||
getChildren | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getDescendants | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
loadMessages | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
12 | |||
loadProperties | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
getRawMessage | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getMessage | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
20 | |||
parseMessage | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
12 | |||
parseMessageInline | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getLangList | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
getProperty | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getAllProperties | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getConfXml | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getConfXmlEntityStuff | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
42 | |||
getPropertyDumpExclusion | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\SecurePoll\Entities; |
4 | |
5 | use MediaWiki\Extension\SecurePoll\Context; |
6 | use MediaWiki\MediaWikiServices; |
7 | use MediaWiki\Parser\Parser; |
8 | use MediaWiki\SpecialPage\SpecialPage; |
9 | use MediaWiki\Xml\Xml; |
10 | |
11 | /** |
12 | * There are three types of entity: elections, questions and options. The |
13 | * entity abstraction provides generic i18n support, allowing localised message |
14 | * text to be attached to the entity, without introducing a dependency on the |
15 | * editability of the MediaWiki namespace. Users are only allowed to edit messages |
16 | * for the elections that they administer. |
17 | * |
18 | * Entities also provide a persistent key/value pair interface for non-localised |
19 | * properties, and a descendant tree which is used to accelerate message loading. |
20 | */ |
21 | class Entity { |
22 | /** @var int|false */ |
23 | public $id; |
24 | /** @var int|null */ |
25 | public $electionId; |
26 | /** @var Context */ |
27 | public $context; |
28 | /** @var array */ |
29 | public $messagesLoaded = []; |
30 | /** @var array|null */ |
31 | public $properties; |
32 | /** @var string */ |
33 | public $type; |
34 | |
35 | /** |
36 | * Create an entity of the given type. This is typically called from the |
37 | * child constructor. |
38 | * @param Context $context |
39 | * @param string $type |
40 | * @param array $info Associative array of entity info |
41 | */ |
42 | public function __construct( $context, $type, $info ) { |
43 | $this->context = $context; |
44 | $this->type = $type; |
45 | $this->id = $info['id'] ?? false; |
46 | $this->electionId = $info['election'] ?? null; |
47 | } |
48 | |
49 | /** |
50 | * Get the type of the entity. |
51 | * @return string |
52 | */ |
53 | public function getType() { |
54 | return $this->type; |
55 | } |
56 | |
57 | /** |
58 | * Get a list of localisable message names. This is used to provide the |
59 | * translate subpage with a list of messages to localise. |
60 | * @return array |
61 | */ |
62 | public function getMessageNames() { |
63 | # STUB |
64 | return []; |
65 | } |
66 | |
67 | /** |
68 | * Get the entity ID. |
69 | * @return int |
70 | */ |
71 | public function getId() { |
72 | return $this->id; |
73 | } |
74 | |
75 | /** |
76 | * Get the parent election |
77 | * @return Election|null |
78 | */ |
79 | public function getElection() { |
80 | return $this->electionId !== null ? $this->context->getElection( $this->electionId ) : null; |
81 | } |
82 | |
83 | /** |
84 | * Get the child entity objects. When the messages of an object are loaded, |
85 | * the messages of the children are loaded automatically, to reduce the |
86 | * query count. |
87 | * |
88 | * @return array |
89 | */ |
90 | public function getChildren() { |
91 | return []; |
92 | } |
93 | |
94 | /** |
95 | * Get all children, grandchildren, etc. in a single flat array of entity |
96 | * objects. |
97 | * @return array |
98 | */ |
99 | public function getDescendants() { |
100 | $descendants = []; |
101 | $children = $this->getChildren(); |
102 | foreach ( $children as $child ) { |
103 | $descendants[] = $child; |
104 | $descendants = array_merge( $descendants, $child->getDescendants() ); |
105 | } |
106 | |
107 | return $descendants; |
108 | } |
109 | |
110 | /** |
111 | * Load messages for a given language. It's not generally necessary to call |
112 | * this since getMessage() does it automatically. |
113 | * @param string|false $lang |
114 | */ |
115 | public function loadMessages( $lang = false ) { |
116 | if ( $lang === false ) { |
117 | $lang = reset( $this->context->languages ); |
118 | } |
119 | $ids = [ $this->getId() ]; |
120 | foreach ( $this->getDescendants() as $child ) { |
121 | $ids[] = $child->getId(); |
122 | } |
123 | $this->context->getMessages( $lang, $ids ); |
124 | $this->messagesLoaded[$lang] = true; |
125 | } |
126 | |
127 | /** |
128 | * Load the properties for the entity. It is not generally necessary to |
129 | * call this function from another class since getProperty() does it |
130 | * automatically. |
131 | */ |
132 | public function loadProperties() { |
133 | $properties = $this->context->getStore()->getProperties( [ $this->getId() ] ); |
134 | if ( count( $properties ) ) { |
135 | $this->properties = reset( $properties ); |
136 | } else { |
137 | $this->properties = []; |
138 | } |
139 | } |
140 | |
141 | /** |
142 | * Get a message, or false if the message does not exist. Does not use |
143 | * the fallback sequence. |
144 | * |
145 | * @param string $name |
146 | * @param string $language |
147 | * @return string|false |
148 | */ |
149 | public function getRawMessage( $name, $language ) { |
150 | if ( empty( $this->messagesLoaded[$language] ) ) { |
151 | $this->loadMessages( $language ); |
152 | } |
153 | |
154 | return $this->context->getMessage( $language, $this->getId(), $name ); |
155 | } |
156 | |
157 | /** |
158 | * Get a message, and go through the fallback sequence if it is not found. |
159 | * If the message is not found even after looking at all possible languages, |
160 | * a placeholder string is returned. |
161 | * |
162 | * @param string $name |
163 | * @return string |
164 | */ |
165 | public function getMessage( $name ) { |
166 | foreach ( $this->context->languages as $language ) { |
167 | if ( empty( $this->messagesLoaded[$language] ) ) { |
168 | $this->loadMessages( $language ); |
169 | } |
170 | $message = $this->getRawMessage( $name, $language ); |
171 | if ( $message !== false ) { |
172 | return $message; |
173 | } |
174 | } |
175 | |
176 | return "[$name]"; |
177 | } |
178 | |
179 | /** |
180 | * Get a message, and interpret it as wikitext, converting it to HTML. |
181 | * @param string $name |
182 | * @param bool $block |
183 | * @return string |
184 | */ |
185 | public function parseMessage( $name, $block = true ) { |
186 | // phpcs:ignore MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgTitle |
187 | global $wgTitle; |
188 | $parserOptions = $this->context->getParserOptions(); |
189 | if ( $wgTitle ) { |
190 | $title = $wgTitle; |
191 | } else { |
192 | $title = SpecialPage::getTitleFor( 'SecurePoll' ); |
193 | } |
194 | $wikiText = $this->getMessage( $name ); |
195 | $out = MediaWikiServices::getInstance()->getParser()->parse( |
196 | $wikiText, |
197 | $title, |
198 | $parserOptions |
199 | ); |
200 | |
201 | $html = $out->runOutputPipeline( $parserOptions, [ 'unwrap' => true ] )->getContentHolderText(); |
202 | if ( !$block ) { |
203 | $html = Parser::stripOuterParagraph( $html ); |
204 | } |
205 | return $html; |
206 | } |
207 | |
208 | /** |
209 | * Get a message and convert it from wikitext to HTML, without <p> tags. |
210 | * @param string $name |
211 | * @return string |
212 | */ |
213 | public function parseMessageInline( $name ) { |
214 | return $this->parseMessage( $name, false ); |
215 | } |
216 | |
217 | /** |
218 | * Get a list of languages for which we have translations, for this entity |
219 | * and its descendants. |
220 | * @return string[] |
221 | */ |
222 | public function getLangList() { |
223 | $ids = [ $this->getId() ]; |
224 | foreach ( $this->getDescendants() as $child ) { |
225 | $ids[] = $child->getId(); |
226 | } |
227 | |
228 | return $this->context->getStore()->getLangList( $ids ); |
229 | } |
230 | |
231 | /** |
232 | * Get a property value. If it does not exist, the $default parameter |
233 | * is passed back. |
234 | * @param string $name |
235 | * @param mixed $default |
236 | * @return bool|mixed |
237 | */ |
238 | public function getProperty( $name, $default = false ) { |
239 | if ( $this->properties === null ) { |
240 | $this->loadProperties(); |
241 | } |
242 | |
243 | return $this->properties[$name] ?? $default; |
244 | } |
245 | |
246 | /** |
247 | * Get all defined properties as an associative array |
248 | * @return array |
249 | */ |
250 | public function getAllProperties() { |
251 | if ( $this->properties === null ) { |
252 | $this->loadProperties(); |
253 | } |
254 | |
255 | return $this->properties; |
256 | } |
257 | |
258 | /** |
259 | * Get configuration XML. Overridden by most subclasses. |
260 | * @param array $params |
261 | * @return string |
262 | */ |
263 | public function getConfXml( $params = [] ) { |
264 | return "<{$this->type}>\n" . $this->getConfXmlEntityStuff( $params ) . "</{$this->type}>\n"; |
265 | } |
266 | |
267 | /** |
268 | * Get an XML snippet giving the messages and properties |
269 | * @param array $params |
270 | * @return string |
271 | */ |
272 | public function getConfXmlEntityStuff( $params = [] ) { |
273 | $s = Xml::element( 'id', [], (string)$this->getId() ) . "\n"; |
274 | $excludedNames = $this->getPropertyDumpExclusion( $params ); |
275 | foreach ( $this->getAllProperties() as $name => $value ) { |
276 | if ( !in_array( $name, $excludedNames ) ) { |
277 | $s .= Xml::element( 'property', [ 'name' => $name ], $value ) . "\n"; |
278 | } |
279 | } |
280 | $langs = $params['langs'] ?? $this->context->languages; |
281 | foreach ( $this->getMessageNames() as $name ) { |
282 | foreach ( $langs as $lang ) { |
283 | $value = $this->getRawMessage( $name, $lang ); |
284 | if ( $value !== false ) { |
285 | $s .= Xml::element( |
286 | 'message', |
287 | [ |
288 | 'name' => $name, |
289 | 'lang' => $lang |
290 | ], |
291 | $value |
292 | ) . "\n"; |
293 | } |
294 | } |
295 | } |
296 | |
297 | return $s; |
298 | } |
299 | |
300 | /** |
301 | * Get property names which aren't included in an XML dump. |
302 | * Overloaded by Election. |
303 | * @param array $params |
304 | * @return array |
305 | */ |
306 | public function getPropertyDumpExclusion( $params = [] ) { |
307 | return []; |
308 | } |
309 | |
310 | } |