Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 212 |
n/a |
0 / 0 |
CRAP | n/a |
0 / 0 |
1 | <?php |
2 | /** |
3 | * ServiceWiring.php |
4 | * |
5 | * This file returns the array loaded by the CodexServices class |
6 | * for use through `Wikimedia\CodexServices::getInstance()`. Each service is associated with a key (service name), |
7 | * and its value is a closure that returns an instance of the service. This setup allows for |
8 | * dependency injection, ensuring services are instantiated only when needed. |
9 | * |
10 | * Reminder: |
11 | * - ServiceWiring is NOT a cache for arbitrary singletons. |
12 | * |
13 | * Services include various UI component builders, renderers, and utilities such as the |
14 | * Mustache template engine and Localization for localization. These services are integral to |
15 | * the Codex design system for generating reusable, standardized components. |
16 | * |
17 | * @category Infrastructure |
18 | * @package Codex\Infrastructure |
19 | * @since 0.1.0 |
20 | * @author Doğu Abaris <abaris@null.net> |
21 | * @license https://www.gnu.org/copyleft/gpl.html GPL-2.0-or-later |
22 | * @link https://doc.wikimedia.org/codex/main/ Codex Documentation |
23 | */ |
24 | |
25 | use Krinkle\Intuition\Intuition; |
26 | use MediaWiki\Context\RequestContext; |
27 | use Wikimedia\Codex\Adapter\WebRequestAdapter; |
28 | use Wikimedia\Codex\Builder\AccordionBuilder; |
29 | use Wikimedia\Codex\Builder\ButtonBuilder; |
30 | use Wikimedia\Codex\Builder\CardBuilder; |
31 | use Wikimedia\Codex\Builder\CheckboxBuilder; |
32 | use Wikimedia\Codex\Builder\FieldBuilder; |
33 | use Wikimedia\Codex\Builder\HtmlSnippetBuilder; |
34 | use Wikimedia\Codex\Builder\InfoChipBuilder; |
35 | use Wikimedia\Codex\Builder\LabelBuilder; |
36 | use Wikimedia\Codex\Builder\MessageBuilder; |
37 | use Wikimedia\Codex\Builder\OptionBuilder; |
38 | use Wikimedia\Codex\Builder\PagerBuilder; |
39 | use Wikimedia\Codex\Builder\ProgressBarBuilder; |
40 | use Wikimedia\Codex\Builder\RadioBuilder; |
41 | use Wikimedia\Codex\Builder\SelectBuilder; |
42 | use Wikimedia\Codex\Builder\TabBuilder; |
43 | use Wikimedia\Codex\Builder\TableBuilder; |
44 | use Wikimedia\Codex\Builder\TabsBuilder; |
45 | use Wikimedia\Codex\Builder\TextAreaBuilder; |
46 | use Wikimedia\Codex\Builder\TextInputBuilder; |
47 | use Wikimedia\Codex\Builder\ThumbnailBuilder; |
48 | use Wikimedia\Codex\Builder\ToggleSwitchBuilder; |
49 | use Wikimedia\Codex\Contract\ILocalizer; |
50 | use Wikimedia\Codex\Localization\IntuitionLocalization; |
51 | use Wikimedia\Codex\Localization\MediaWikiLocalization; |
52 | use Wikimedia\Codex\Renderer\AccordionRenderer; |
53 | use Wikimedia\Codex\Renderer\ButtonRenderer; |
54 | use Wikimedia\Codex\Renderer\CardRenderer; |
55 | use Wikimedia\Codex\Renderer\CheckboxRenderer; |
56 | use Wikimedia\Codex\Renderer\FieldRenderer; |
57 | use Wikimedia\Codex\Renderer\InfoChipRenderer; |
58 | use Wikimedia\Codex\Renderer\LabelRenderer; |
59 | use Wikimedia\Codex\Renderer\MessageRenderer; |
60 | use Wikimedia\Codex\Renderer\PagerRenderer; |
61 | use Wikimedia\Codex\Renderer\ProgressBarRenderer; |
62 | use Wikimedia\Codex\Renderer\RadioRenderer; |
63 | use Wikimedia\Codex\Renderer\SelectRenderer; |
64 | use Wikimedia\Codex\Renderer\TableRenderer; |
65 | use Wikimedia\Codex\Renderer\TabsRenderer; |
66 | use Wikimedia\Codex\Renderer\TemplateRenderer; |
67 | use Wikimedia\Codex\Renderer\TextAreaRenderer; |
68 | use Wikimedia\Codex\Renderer\TextInputRenderer; |
69 | use Wikimedia\Codex\Renderer\ThumbnailRenderer; |
70 | use Wikimedia\Codex\Renderer\ToggleSwitchRenderer; |
71 | use Wikimedia\Codex\Utility\Sanitizer; |
72 | use Wikimedia\Codex\Utility\SimpleWebRequest; |
73 | use Wikimedia\Codex\Utility\WebRequestCallbacks; |
74 | |
75 | /** @phpcs-require-sorted-array */ |
76 | return [ |
77 | |
78 | 'AccordionBuilder' => static function ( $container ) { |
79 | return new AccordionBuilder( $container->getService( 'AccordionRenderer' ) ); |
80 | }, |
81 | |
82 | 'AccordionRenderer' => static function ( $container ) { |
83 | return new AccordionRenderer( |
84 | $container->getService( 'Sanitizer' ), $container->getService( 'TemplateRenderer' ), |
85 | ); |
86 | }, |
87 | |
88 | 'ButtonBuilder' => static function ( $container ) { |
89 | return new ButtonBuilder( $container->getService( 'ButtonRenderer' ) ); |
90 | }, |
91 | |
92 | 'ButtonRenderer' => static function ( $container ) { |
93 | return new ButtonRenderer( |
94 | $container->getService( 'Sanitizer' ), $container->getService( 'TemplateRenderer' ), |
95 | ); |
96 | }, |
97 | |
98 | 'CardBuilder' => static function ( $container ) { |
99 | return new CardBuilder( $container->getService( 'CardRenderer' ) ); |
100 | }, |
101 | |
102 | 'CardRenderer' => static function ( $container ) { |
103 | return new CardRenderer( |
104 | $container->getService( 'Sanitizer' ), $container->getService( 'TemplateRenderer' ), |
105 | ); |
106 | }, |
107 | |
108 | 'CheckboxBuilder' => static function ( $container ) { |
109 | return new CheckboxBuilder( $container->getService( 'CheckboxRenderer' ) ); |
110 | }, |
111 | |
112 | 'CheckboxRenderer' => static function ( $container ) { |
113 | return new CheckboxRenderer( |
114 | $container->getService( 'Sanitizer' ), $container->getService( 'TemplateRenderer' ) |
115 | ); |
116 | }, |
117 | |
118 | 'FieldBuilder' => static function ( $container ) { |
119 | return new FieldBuilder( $container->getService( 'FieldRenderer' ) ); |
120 | }, |
121 | |
122 | 'FieldRenderer' => static function ( $container ) { |
123 | return new FieldRenderer( |
124 | $container->getService( 'Sanitizer' ), $container->getService( 'TemplateRenderer' ), |
125 | ); |
126 | }, |
127 | |
128 | 'HTMLPurifier' => static function ( $container ) { |
129 | return new HTMLPurifier( $container->getService( 'HTMLPurifierConfig' ) ); |
130 | }, |
131 | |
132 | 'HTMLPurifierConfig' => static function () { |
133 | return HTMLPurifier_Config::createDefault(); |
134 | }, |
135 | |
136 | 'HtmlSnippetBuilder' => static function ( $container ) { |
137 | return new HtmlSnippetBuilder( $container->getService( 'Sanitizer' ) ); |
138 | }, |
139 | |
140 | 'InfoChipBuilder' => static function ( $container ) { |
141 | return new InfoChipBuilder( $container->getService( 'InfoChipRenderer' ) ); |
142 | }, |
143 | |
144 | 'InfoChipRenderer' => static function ( $container ) { |
145 | return new InfoChipRenderer( |
146 | $container->getService( 'Sanitizer' ), $container->getService( 'TemplateRenderer' ), |
147 | ); |
148 | }, |
149 | |
150 | 'LabelBuilder' => static function ( $container ) { |
151 | return new LabelBuilder( $container->getService( 'LabelRenderer' ) ); |
152 | }, |
153 | |
154 | 'LabelRenderer' => static function ( $container ) { |
155 | return new LabelRenderer( |
156 | $container->getService( 'Sanitizer' ), $container->getService( 'TemplateRenderer' ) |
157 | ); |
158 | }, |
159 | |
160 | 'Localization' => static function (): ILocalizer { |
161 | if ( defined( 'MW_INSTALL_PATH' ) ) { |
162 | $messageLocalizer = RequestContext::getMain(); |
163 | return new MediaWikiLocalization( $messageLocalizer ); |
164 | } else { |
165 | $intuition = new Intuition( 'codex' ); |
166 | $intuition->registerDomain( 'codex', __DIR__ . '/../../i18n' ); |
167 | return new IntuitionLocalization( $intuition ); |
168 | } |
169 | }, |
170 | |
171 | 'MessageBuilder' => static function ( $container ) { |
172 | return new MessageBuilder( $container->getService( 'MessageRenderer' ) ); |
173 | }, |
174 | |
175 | 'MessageRenderer' => static function ( $container ) { |
176 | return new MessageRenderer( |
177 | $container->getService( 'Sanitizer' ), $container->getService( 'TemplateRenderer' ), |
178 | ); |
179 | }, |
180 | |
181 | 'OptionBuilder' => static function () { |
182 | return new OptionBuilder(); |
183 | }, |
184 | |
185 | 'PagerBuilder' => static function ( $container ) { |
186 | return new PagerBuilder( $container->getService( 'PagerRenderer' ) ); |
187 | }, |
188 | |
189 | 'PagerRenderer' => static function ( $container ) { |
190 | return new PagerRenderer( |
191 | $container->getService( 'Sanitizer' ), |
192 | $container->getService( 'TemplateRenderer' ), |
193 | $container->getService( 'Localization' ) |
194 | ); |
195 | }, |
196 | |
197 | 'ProgressBarBuilder' => static function ( $container ) { |
198 | return new ProgressBarBuilder( $container->getService( 'ProgressBarRenderer' ) ); |
199 | }, |
200 | |
201 | 'ProgressBarRenderer' => static function ( $container ) { |
202 | return new ProgressBarRenderer( |
203 | $container->getService( 'Sanitizer' ), $container->getService( 'TemplateRenderer' ), |
204 | ); |
205 | }, |
206 | |
207 | 'RadioBuilder' => static function ( $container ) { |
208 | return new RadioBuilder( $container->getService( 'RadioRenderer' ) ); |
209 | }, |
210 | |
211 | 'RadioRenderer' => static function ( $container ) { |
212 | return new RadioRenderer( |
213 | $container->getService( 'Sanitizer' ), $container->getService( 'TemplateRenderer' ) |
214 | ); |
215 | }, |
216 | |
217 | 'Sanitizer' => static function ( $container ) { |
218 | return new Sanitizer( $container->getService( 'HTMLPurifier' ) ); |
219 | }, |
220 | |
221 | 'SelectBuilder' => static function ( $container ) { |
222 | return new SelectBuilder( $container->getService( 'SelectRenderer' ) ); |
223 | }, |
224 | |
225 | 'SelectRenderer' => static function ( $container ) { |
226 | return new SelectRenderer( |
227 | $container->getService( 'Sanitizer' ), $container->getService( 'TemplateRenderer' ), |
228 | ); |
229 | }, |
230 | |
231 | 'SimpleWebRequest' => static function () { |
232 | //phpcs:ignore |
233 | return new SimpleWebRequest( $_GET ); |
234 | }, |
235 | |
236 | 'TabBuilder' => static function () { |
237 | return new TabBuilder(); |
238 | }, |
239 | |
240 | 'TableBuilder' => static function ( $container ) { |
241 | return new TableBuilder( $container->getService( 'TableRenderer' ) ); |
242 | }, |
243 | |
244 | 'TableRenderer' => static function ( $container ) { |
245 | return new TableRenderer( $container->getService( 'Sanitizer' ), $container->getService( 'TemplateRenderer' ) ); |
246 | }, |
247 | |
248 | 'TabsBuilder' => static function ( $container ) { |
249 | return new TabsBuilder( $container->getService( 'TabsRenderer' ) ); |
250 | }, |
251 | |
252 | 'TabsRenderer' => static function ( $container ) { |
253 | return new TabsRenderer( $container->getService( 'Sanitizer' ), $container->getService( 'TemplateRenderer' ) ); |
254 | }, |
255 | |
256 | 'TemplateRenderer' => static function ( $container ) { |
257 | $templatePath = __DIR__ . '/../../resources/templates'; |
258 | |
259 | $localization = $container->getService( 'Localization' ); |
260 | |
261 | $mustacheEngine = new Mustache_Engine( [ |
262 | 'loader' => new Mustache_Loader_FilesystemLoader( $templatePath ), |
263 | // Disable escaping in Mustache. We use custom PHP escaping instead. |
264 | 'escape' => static fn ( $x ) => $x, |
265 | 'helpers' => [ |
266 | // TODO: Consider moving the following helper functions to a separate helper class. |
267 | // i18n helper - for localization |
268 | 'i18n' => static function ( $text, $render ) use ( $localization ) { |
269 | $renderedText = trim( $render( $text ) ); |
270 | // Split by '|' to separate the key and parameters. |
271 | // XXX This assumes that the expanded content of parameters does not contain pipes. |
272 | $parts = explode( '|', $renderedText ); |
273 | // The first part is the message key, the rest are parameters |
274 | $key = trim( array_shift( $parts ) ); |
275 | $params = array_map( 'trim', $parts ); |
276 | |
277 | return htmlspecialchars( |
278 | $localization->msg( $key, [ 'variables' => $params ] ), |
279 | ENT_QUOTES, |
280 | 'UTF-8' |
281 | ); |
282 | }, |
283 | 'renderClasses' => static function ( $attributes, $render ) { |
284 | $renderedAttributes = $render( $attributes ); |
285 | |
286 | // Use a regular expression to match the 'class' attribute and capture its value |
287 | if ( preg_match( '/class="([^"]*)"/', $renderedAttributes, $matches ) ) { |
288 | // If a 'class' attribute is found, prepend a space and return the class string |
289 | return ' ' . $matches[1]; |
290 | } |
291 | |
292 | // If no 'class' attribute is found, return an empty string |
293 | return ''; |
294 | }, |
295 | 'renderAttributes' => static function ( $attributes, $render ) { |
296 | $renderedAttributes = $render( $attributes ); |
297 | |
298 | // Remove the 'class' attribute from the rendered attributes using a regular expression |
299 | // This ensures that only non-class attributes are returned |
300 | $attribs = trim( preg_replace( '/\s*class="[^"]*"/', '', $renderedAttributes ) ); |
301 | |
302 | // If there are remaining attributes after removing 'class', prepend a space and return them |
303 | // Otherwise, return an empty string |
304 | return $attribs !== '' ? ' ' . $attribs : ''; |
305 | }, |
306 | ], |
307 | ] ); |
308 | |
309 | return new TemplateRenderer( $mustacheEngine ); |
310 | }, |
311 | |
312 | 'TextAreaBuilder' => static function ( $container ) { |
313 | return new TextAreaBuilder( $container->getService( 'TextAreaRenderer' ) ); |
314 | }, |
315 | |
316 | 'TextAreaRenderer' => static function ( $container ) { |
317 | return new TextAreaRenderer( |
318 | $container->getService( 'Sanitizer' ), $container->getService( 'TemplateRenderer' ) |
319 | ); |
320 | }, |
321 | |
322 | 'TextInputBuilder' => static function ( $container ) { |
323 | return new TextInputBuilder( $container->getService( 'TextInputRenderer' ) ); |
324 | }, |
325 | |
326 | 'TextInputRenderer' => static function ( $container ) { |
327 | return new TextInputRenderer( |
328 | $container->getService( 'Sanitizer' ), $container->getService( 'TemplateRenderer' ), |
329 | ); |
330 | }, |
331 | |
332 | 'ThumbnailBuilder' => static function ( $container ) { |
333 | return new ThumbnailBuilder( $container->getService( 'ThumbnailRenderer' ) ); |
334 | }, |
335 | |
336 | 'ThumbnailRenderer' => static function ( $container ) { |
337 | return new ThumbnailRenderer( |
338 | $container->getService( 'Sanitizer' ), $container->getService( 'TemplateRenderer' ), |
339 | ); |
340 | }, |
341 | |
342 | 'ToggleSwitchBuilder' => static function ( $container ) { |
343 | return new ToggleSwitchBuilder( $container->getService( 'ToggleSwitchRenderer' ) ); |
344 | }, |
345 | |
346 | 'ToggleSwitchRenderer' => static function ( $container ) { |
347 | return new ToggleSwitchRenderer( |
348 | $container->getService( 'Sanitizer' ), $container->getService( 'TemplateRenderer' ), |
349 | ); |
350 | }, |
351 | |
352 | 'WebRequestAdapter' => static function ( $container ) { |
353 | return new WebRequestAdapter( $container->getService( 'SimpleWebRequest' ) ); |
354 | }, |
355 | |
356 | 'WebRequestCallbacks' => static function ( $container ) { |
357 | return new WebRequestCallbacks( $container->getService( 'WebRequestAdapter' ) ); |
358 | }, |
359 | ]; |