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