MediaWiki REL1_27
DatabaseSQLTest.php
Go to the documentation of this file.
1<?php
2
8
12 private $database;
13
14 protected function setUp() {
15 parent::setUp();
16 $this->database = new DatabaseTestHelper( __CLASS__ );
17 }
18
19 protected function assertLastSql( $sqlText ) {
20 $this->assertEquals(
21 $this->database->getLastSqls(),
22 $sqlText
23 );
24 }
25
30 public function testSelect( $sql, $sqlText ) {
31 $this->database->select(
32 $sql['tables'],
33 $sql['fields'],
34 isset( $sql['conds'] ) ? $sql['conds'] : [],
35 __METHOD__,
36 isset( $sql['options'] ) ? $sql['options'] : [],
37 isset( $sql['join_conds'] ) ? $sql['join_conds'] : []
38 );
39 $this->assertLastSql( $sqlText );
40 }
41
42 public static function provideSelect() {
43 return [
44 [
45 [
46 'tables' => 'table',
47 'fields' => [ 'field', 'alias' => 'field2' ],
48 'conds' => [ 'alias' => 'text' ],
49 ],
50 "SELECT field,field2 AS alias " .
51 "FROM table " .
52 "WHERE alias = 'text'"
53 ],
54 [
55 [
56 'tables' => 'table',
57 'fields' => [ 'field', 'alias' => 'field2' ],
58 'conds' => [ 'alias' => 'text' ],
59 'options' => [ 'LIMIT' => 1, 'ORDER BY' => 'field' ],
60 ],
61 "SELECT field,field2 AS alias " .
62 "FROM table " .
63 "WHERE alias = 'text' " .
64 "ORDER BY field " .
65 "LIMIT 1"
66 ],
67 [
68 [
69 'tables' => [ 'table', 't2' => 'table2' ],
70 'fields' => [ 'tid', 'field', 'alias' => 'field2', 't2.id' ],
71 'conds' => [ 'alias' => 'text' ],
72 'options' => [ 'LIMIT' => 1, 'ORDER BY' => 'field' ],
73 'join_conds' => [ 't2' => [
74 'LEFT JOIN', 'tid = t2.id'
75 ] ],
76 ],
77 "SELECT tid,field,field2 AS alias,t2.id " .
78 "FROM table LEFT JOIN table2 t2 ON ((tid = t2.id)) " .
79 "WHERE alias = 'text' " .
80 "ORDER BY field " .
81 "LIMIT 1"
82 ],
83 [
84 [
85 'tables' => [ 'table', 't2' => 'table2' ],
86 'fields' => [ 'tid', 'field', 'alias' => 'field2', 't2.id' ],
87 'conds' => [ 'alias' => 'text' ],
88 'options' => [ 'LIMIT' => 1, 'GROUP BY' => 'field', 'HAVING' => 'COUNT(*) > 1' ],
89 'join_conds' => [ 't2' => [
90 'LEFT JOIN', 'tid = t2.id'
91 ] ],
92 ],
93 "SELECT tid,field,field2 AS alias,t2.id " .
94 "FROM table LEFT JOIN table2 t2 ON ((tid = t2.id)) " .
95 "WHERE alias = 'text' " .
96 "GROUP BY field HAVING COUNT(*) > 1 " .
97 "LIMIT 1"
98 ],
99 [
100 [
101 'tables' => [ 'table', 't2' => 'table2' ],
102 'fields' => [ 'tid', 'field', 'alias' => 'field2', 't2.id' ],
103 'conds' => [ 'alias' => 'text' ],
104 'options' => [
105 'LIMIT' => 1,
106 'GROUP BY' => [ 'field', 'field2' ],
107 'HAVING' => [ 'COUNT(*) > 1', 'field' => 1 ]
108 ],
109 'join_conds' => [ 't2' => [
110 'LEFT JOIN', 'tid = t2.id'
111 ] ],
112 ],
113 "SELECT tid,field,field2 AS alias,t2.id " .
114 "FROM table LEFT JOIN table2 t2 ON ((tid = t2.id)) " .
115 "WHERE alias = 'text' " .
116 "GROUP BY field,field2 HAVING (COUNT(*) > 1) AND field = '1' " .
117 "LIMIT 1"
118 ],
119 [
120 [
121 'tables' => [ 'table' ],
122 'fields' => [ 'alias' => 'field' ],
123 'conds' => [ 'alias' => [ 1, 2, 3, 4 ] ],
124 ],
125 "SELECT field AS alias " .
126 "FROM table " .
127 "WHERE alias IN ('1','2','3','4')"
128 ],
129 ];
130 }
131
136 public function testUpdate( $sql, $sqlText ) {
137 $this->database->update(
138 $sql['table'],
139 $sql['values'],
140 $sql['conds'],
141 __METHOD__,
142 isset( $sql['options'] ) ? $sql['options'] : []
143 );
144 $this->assertLastSql( $sqlText );
145 }
146
147 public static function provideUpdate() {
148 return [
149 [
150 [
151 'table' => 'table',
152 'values' => [ 'field' => 'text', 'field2' => 'text2' ],
153 'conds' => [ 'alias' => 'text' ],
154 ],
155 "UPDATE table " .
156 "SET field = 'text'" .
157 ",field2 = 'text2' " .
158 "WHERE alias = 'text'"
159 ],
160 [
161 [
162 'table' => 'table',
163 'values' => [ 'field = other', 'field2' => 'text2' ],
164 'conds' => [ 'id' => '1' ],
165 ],
166 "UPDATE table " .
167 "SET field = other" .
168 ",field2 = 'text2' " .
169 "WHERE id = '1'"
170 ],
171 [
172 [
173 'table' => 'table',
174 'values' => [ 'field = other', 'field2' => 'text2' ],
175 'conds' => '*',
176 ],
177 "UPDATE table " .
178 "SET field = other" .
179 ",field2 = 'text2'"
180 ],
181 ];
182 }
183
188 public function testDelete( $sql, $sqlText ) {
189 $this->database->delete(
190 $sql['table'],
191 $sql['conds'],
192 __METHOD__
193 );
194 $this->assertLastSql( $sqlText );
195 }
196
197 public static function provideDelete() {
198 return [
199 [
200 [
201 'table' => 'table',
202 'conds' => [ 'alias' => 'text' ],
203 ],
204 "DELETE FROM table " .
205 "WHERE alias = 'text'"
206 ],
207 [
208 [
209 'table' => 'table',
210 'conds' => '*',
211 ],
212 "DELETE FROM table"
213 ],
214 ];
215 }
216
221 public function testUpsert( $sql, $sqlText ) {
222 $this->database->upsert(
223 $sql['table'],
224 $sql['rows'],
225 $sql['uniqueIndexes'],
226 $sql['set'],
227 __METHOD__
228 );
229 $this->assertLastSql( $sqlText );
230 }
231
232 public static function provideUpsert() {
233 return [
234 [
235 [
236 'table' => 'upsert_table',
237 'rows' => [ 'field' => 'text', 'field2' => 'text2' ],
238 'uniqueIndexes' => [ 'field' ],
239 'set' => [ 'field' => 'set' ],
240 ],
241 "BEGIN; " .
242 "UPDATE upsert_table " .
243 "SET field = 'set' " .
244 "WHERE ((field = 'text')); " .
245 "INSERT IGNORE INTO upsert_table " .
246 "(field,field2) " .
247 "VALUES ('text','text2'); " .
248 "COMMIT"
249 ],
250 ];
251 }
252
257 public function testDeleteJoin( $sql, $sqlText ) {
258 $this->database->deleteJoin(
259 $sql['delTable'],
260 $sql['joinTable'],
261 $sql['delVar'],
262 $sql['joinVar'],
263 $sql['conds'],
264 __METHOD__
265 );
266 $this->assertLastSql( $sqlText );
267 }
268
269 public static function provideDeleteJoin() {
270 return [
271 [
272 [
273 'delTable' => 'table',
274 'joinTable' => 'table_join',
275 'delVar' => 'field',
276 'joinVar' => 'field_join',
277 'conds' => [ 'alias' => 'text' ],
278 ],
279 "DELETE FROM table " .
280 "WHERE field IN (" .
281 "SELECT field_join FROM table_join WHERE alias = 'text'" .
282 ")"
283 ],
284 [
285 [
286 'delTable' => 'table',
287 'joinTable' => 'table_join',
288 'delVar' => 'field',
289 'joinVar' => 'field_join',
290 'conds' => '*',
291 ],
292 "DELETE FROM table " .
293 "WHERE field IN (" .
294 "SELECT field_join FROM table_join " .
295 ")"
296 ],
297 ];
298 }
299
304 public function testInsert( $sql, $sqlText ) {
305 $this->database->insert(
306 $sql['table'],
307 $sql['rows'],
308 __METHOD__,
309 isset( $sql['options'] ) ? $sql['options'] : []
310 );
311 $this->assertLastSql( $sqlText );
312 }
313
314 public static function provideInsert() {
315 return [
316 [
317 [
318 'table' => 'table',
319 'rows' => [ 'field' => 'text', 'field2' => 2 ],
320 ],
321 "INSERT INTO table " .
322 "(field,field2) " .
323 "VALUES ('text','2')"
324 ],
325 [
326 [
327 'table' => 'table',
328 'rows' => [ 'field' => 'text', 'field2' => 2 ],
329 'options' => 'IGNORE',
330 ],
331 "INSERT IGNORE INTO table " .
332 "(field,field2) " .
333 "VALUES ('text','2')"
334 ],
335 [
336 [
337 'table' => 'table',
338 'rows' => [
339 [ 'field' => 'text', 'field2' => 2 ],
340 [ 'field' => 'multi', 'field2' => 3 ],
341 ],
342 'options' => 'IGNORE',
343 ],
344 "INSERT IGNORE INTO table " .
345 "(field,field2) " .
346 "VALUES " .
347 "('text','2')," .
348 "('multi','3')"
349 ],
350 ];
351 }
352
357 public function testInsertSelect( $sql, $sqlText ) {
358 $this->database->insertSelect(
359 $sql['destTable'],
360 $sql['srcTable'],
361 $sql['varMap'],
362 $sql['conds'],
363 __METHOD__,
364 isset( $sql['insertOptions'] ) ? $sql['insertOptions'] : [],
365 isset( $sql['selectOptions'] ) ? $sql['selectOptions'] : []
366 );
367 $this->assertLastSql( $sqlText );
368 }
369
370 public static function provideInsertSelect() {
371 return [
372 [
373 [
374 'destTable' => 'insert_table',
375 'srcTable' => 'select_table',
376 'varMap' => [ 'field_insert' => 'field_select', 'field' => 'field2' ],
377 'conds' => '*',
378 ],
379 "INSERT INTO insert_table " .
380 "(field_insert,field) " .
381 "SELECT field_select,field2 " .
382 "FROM select_table"
383 ],
384 [
385 [
386 'destTable' => 'insert_table',
387 'srcTable' => 'select_table',
388 'varMap' => [ 'field_insert' => 'field_select', 'field' => 'field2' ],
389 'conds' => [ 'field' => 2 ],
390 ],
391 "INSERT INTO insert_table " .
392 "(field_insert,field) " .
393 "SELECT field_select,field2 " .
394 "FROM select_table " .
395 "WHERE field = '2'"
396 ],
397 [
398 [
399 'destTable' => 'insert_table',
400 'srcTable' => 'select_table',
401 'varMap' => [ 'field_insert' => 'field_select', 'field' => 'field2' ],
402 'conds' => [ 'field' => 2 ],
403 'insertOptions' => 'IGNORE',
404 'selectOptions' => [ 'ORDER BY' => 'field' ],
405 ],
406 "INSERT IGNORE INTO insert_table " .
407 "(field_insert,field) " .
408 "SELECT field_select,field2 " .
409 "FROM select_table " .
410 "WHERE field = '2' " .
411 "ORDER BY field"
412 ],
413 ];
414 }
415
420 public function testReplace( $sql, $sqlText ) {
421 $this->database->replace(
422 $sql['table'],
423 $sql['uniqueIndexes'],
424 $sql['rows'],
425 __METHOD__
426 );
427 $this->assertLastSql( $sqlText );
428 }
429
430 public static function provideReplace() {
431 return [
432 [
433 [
434 'table' => 'replace_table',
435 'uniqueIndexes' => [ 'field' ],
436 'rows' => [ 'field' => 'text', 'field2' => 'text2' ],
437 ],
438 "DELETE FROM replace_table " .
439 "WHERE ( field='text' ); " .
440 "INSERT INTO replace_table " .
441 "(field,field2) " .
442 "VALUES ('text','text2')"
443 ],
444 [
445 [
446 'table' => 'module_deps',
447 'uniqueIndexes' => [ [ 'md_module', 'md_skin' ] ],
448 'rows' => [
449 'md_module' => 'module',
450 'md_skin' => 'skin',
451 'md_deps' => 'deps',
452 ],
453 ],
454 "DELETE FROM module_deps " .
455 "WHERE ( md_module='module' AND md_skin='skin' ); " .
456 "INSERT INTO module_deps " .
457 "(md_module,md_skin,md_deps) " .
458 "VALUES ('module','skin','deps')"
459 ],
460 [
461 [
462 'table' => 'module_deps',
463 'uniqueIndexes' => [ [ 'md_module', 'md_skin' ] ],
464 'rows' => [
465 [
466 'md_module' => 'module',
467 'md_skin' => 'skin',
468 'md_deps' => 'deps',
469 ], [
470 'md_module' => 'module2',
471 'md_skin' => 'skin2',
472 'md_deps' => 'deps2',
473 ],
474 ],
475 ],
476 "DELETE FROM module_deps " .
477 "WHERE ( md_module='module' AND md_skin='skin' ); " .
478 "INSERT INTO module_deps " .
479 "(md_module,md_skin,md_deps) " .
480 "VALUES ('module','skin','deps'); " .
481 "DELETE FROM module_deps " .
482 "WHERE ( md_module='module2' AND md_skin='skin2' ); " .
483 "INSERT INTO module_deps " .
484 "(md_module,md_skin,md_deps) " .
485 "VALUES ('module2','skin2','deps2')"
486 ],
487 [
488 [
489 'table' => 'module_deps',
490 'uniqueIndexes' => [ 'md_module', 'md_skin' ],
491 'rows' => [
492 [
493 'md_module' => 'module',
494 'md_skin' => 'skin',
495 'md_deps' => 'deps',
496 ], [
497 'md_module' => 'module2',
498 'md_skin' => 'skin2',
499 'md_deps' => 'deps2',
500 ],
501 ],
502 ],
503 "DELETE FROM module_deps " .
504 "WHERE ( md_module='module' ) OR ( md_skin='skin' ); " .
505 "INSERT INTO module_deps " .
506 "(md_module,md_skin,md_deps) " .
507 "VALUES ('module','skin','deps'); " .
508 "DELETE FROM module_deps " .
509 "WHERE ( md_module='module2' ) OR ( md_skin='skin2' ); " .
510 "INSERT INTO module_deps " .
511 "(md_module,md_skin,md_deps) " .
512 "VALUES ('module2','skin2','deps2')"
513 ],
514 [
515 [
516 'table' => 'module_deps',
517 'uniqueIndexes' => [],
518 'rows' => [
519 'md_module' => 'module',
520 'md_skin' => 'skin',
521 'md_deps' => 'deps',
522 ],
523 ],
524 "INSERT INTO module_deps " .
525 "(md_module,md_skin,md_deps) " .
526 "VALUES ('module','skin','deps')"
527 ],
528 ];
529 }
530
535 public function testNativeReplace( $sql, $sqlText ) {
536 $this->database->nativeReplace(
537 $sql['table'],
538 $sql['rows'],
539 __METHOD__
540 );
541 $this->assertLastSql( $sqlText );
542 }
543
544 public static function provideNativeReplace() {
545 return [
546 [
547 [
548 'table' => 'replace_table',
549 'rows' => [ 'field' => 'text', 'field2' => 'text2' ],
550 ],
551 "REPLACE INTO replace_table " .
552 "(field,field2) " .
553 "VALUES ('text','text2')"
554 ],
555 ];
556 }
557
562 public function testConditional( $sql, $sqlText ) {
563 $this->assertEquals( trim( $this->database->conditional(
564 $sql['conds'],
565 $sql['true'],
566 $sql['false']
567 ) ), $sqlText );
568 }
569
570 public static function provideConditional() {
571 return [
572 [
573 [
574 'conds' => [ 'field' => 'text' ],
575 'true' => 1,
576 'false' => 'NULL',
577 ],
578 "(CASE WHEN field = 'text' THEN 1 ELSE NULL END)"
579 ],
580 [
581 [
582 'conds' => [ 'field' => 'text', 'field2' => 'anothertext' ],
583 'true' => 1,
584 'false' => 'NULL',
585 ],
586 "(CASE WHEN field = 'text' AND field2 = 'anothertext' THEN 1 ELSE NULL END)"
587 ],
588 [
589 [
590 'conds' => 'field=1',
591 'true' => 1,
592 'false' => 'NULL',
593 ],
594 "(CASE WHEN field=1 THEN 1 ELSE NULL END)"
595 ],
596 ];
597 }
598
603 public function testBuildConcat( $stringList, $sqlText ) {
604 $this->assertEquals( trim( $this->database->buildConcat(
605 $stringList
606 ) ), $sqlText );
607 }
608
609 public static function provideBuildConcat() {
610 return [
611 [
612 [ 'field', 'field2' ],
613 "CONCAT(field,field2)"
614 ],
615 [
616 [ "'test'", 'field2' ],
617 "CONCAT('test',field2)"
618 ],
619 ];
620 }
621
626 public function testBuildLike( $array, $sqlText ) {
627 $this->assertEquals( trim( $this->database->buildLike(
628 $array
629 ) ), $sqlText );
630 }
631
632 public static function provideBuildLike() {
633 return [
634 [
635 'text',
636 "LIKE 'text'"
637 ],
638 [
639 [ 'text', new LikeMatch( '%' ) ],
640 "LIKE 'text%'"
641 ],
642 [
643 [ 'text', new LikeMatch( '%' ), 'text2' ],
644 "LIKE 'text%text2'"
645 ],
646 [
647 [ 'text', new LikeMatch( '_' ) ],
648 "LIKE 'text_'"
649 ],
650 ];
651 }
652
657 public function testUnionQueries( $sql, $sqlText ) {
658 $this->assertEquals( trim( $this->database->unionQueries(
659 $sql['sqls'],
660 $sql['all']
661 ) ), $sqlText );
662 }
663
664 public static function provideUnionQueries() {
665 return [
666 [
667 [
668 'sqls' => [ 'RAW SQL', 'RAW2SQL' ],
669 'all' => true,
670 ],
671 "(RAW SQL) UNION ALL (RAW2SQL)"
672 ],
673 [
674 [
675 'sqls' => [ 'RAW SQL', 'RAW2SQL' ],
676 'all' => false,
677 ],
678 "(RAW SQL) UNION (RAW2SQL)"
679 ],
680 [
681 [
682 'sqls' => [ 'RAW SQL', 'RAW2SQL', 'RAW3SQL' ],
683 'all' => false,
684 ],
685 "(RAW SQL) UNION (RAW2SQL) UNION (RAW3SQL)"
686 ],
687 ];
688 }
689
693 public function testTransactionCommit() {
694 $this->database->begin( __METHOD__ );
695 $this->database->commit( __METHOD__ );
696 $this->assertLastSql( 'BEGIN; COMMIT' );
697 }
698
702 public function testTransactionRollback() {
703 $this->database->begin( __METHOD__ );
704 $this->database->rollback( __METHOD__ );
705 $this->assertLastSql( 'BEGIN; ROLLBACK' );
706 }
707
711 public function testDropTable() {
712 $this->database->setExistingTables( [ 'table' ] );
713 $this->database->dropTable( 'table', __METHOD__ );
714 $this->assertLastSql( 'DROP TABLE table' );
715 }
716
720 public function testDropNonExistingTable() {
721 $this->assertFalse(
722 $this->database->dropTable( 'non_existing', __METHOD__ )
723 );
724 }
725
730 public function testMakeList( $list, $mode, $sqlText ) {
731 $this->assertEquals( trim( $this->database->makeList(
732 $list, $mode
733 ) ), $sqlText );
734 }
735
736 public static function provideMakeList() {
737 return [
738 [
739 [ 'value', 'value2' ],
741 "'value','value2'"
742 ],
743 [
744 [ 'field', 'field2' ],
746 "field,field2"
747 ],
748 [
749 [ 'field' => 'value', 'field2' => 'value2' ],
750 LIST_AND,
751 "field = 'value' AND field2 = 'value2'"
752 ],
753 [
754 [ 'field' => null, "field2 != 'value2'" ],
755 LIST_AND,
756 "field IS NULL AND (field2 != 'value2')"
757 ],
758 [
759 [ 'field' => [ 'value', null, 'value2' ], 'field2' => 'value2' ],
760 LIST_AND,
761 "(field IN ('value','value2') OR field IS NULL) AND field2 = 'value2'"
762 ],
763 [
764 [ 'field' => [ null ], 'field2' => null ],
765 LIST_AND,
766 "field IS NULL AND field2 IS NULL"
767 ],
768 [
769 [ 'field' => 'value', 'field2' => 'value2' ],
770 LIST_OR,
771 "field = 'value' OR field2 = 'value2'"
772 ],
773 [
774 [ 'field' => 'value', 'field2' => null ],
775 LIST_OR,
776 "field = 'value' OR field2 IS NULL"
777 ],
778 [
779 [ 'field' => [ 'value', 'value2' ], 'field2' => [ 'value' ] ],
780 LIST_OR,
781 "field IN ('value','value2') OR field2 = 'value'"
782 ],
783 [
784 [ 'field' => [ null, 'value', null, 'value2' ], "field2 != 'value2'" ],
785 LIST_OR,
786 "(field IN ('value','value2') OR field IS NULL) OR (field2 != 'value2')"
787 ],
788 [
789 [ 'field' => 'value', 'field2' => 'value2' ],
790 LIST_SET,
791 "field = 'value',field2 = 'value2'"
792 ],
793 [
794 [ 'field' => 'value', 'field2' => null ],
795 LIST_SET,
796 "field = 'value',field2 = NULL"
797 ],
798 [
799 [ 'field' => 'value', "field2 != 'value2'" ],
800 LIST_SET,
801 "field = 'value',field2 != 'value2'"
802 ],
803 ];
804 }
805}
Test the abstract database layer This is a non DBMS depending test.
static provideNativeReplace()
testSelect( $sql, $sqlText)
provideSelect DatabaseBase::select
testInsertSelect( $sql, $sqlText)
provideInsertSelect DatabaseBase::insertSelect
testBuildConcat( $stringList, $sqlText)
provideBuildConcat DatabaseBase::buildConcat
testDropTable()
DatabaseBase::dropTable.
testMakeList( $list, $mode, $sqlText)
provideMakeList DatabaseBase::makeList
static provideConditional()
testBuildLike( $array, $sqlText)
provideBuildLike DatabaseBase::buildLike
static provideUnionQueries()
testConditional( $sql, $sqlText)
provideConditional DatabaseBase::conditional
testTransactionRollback()
DatabaseBase::rollback.
static provideInsertSelect()
static provideBuildConcat()
testReplace( $sql, $sqlText)
provideReplace DatabaseBase::replace
testUnionQueries( $sql, $sqlText)
provideUnionQueries DatabaseBase::unionQueries
testUpsert( $sql, $sqlText)
provideUpsert DatabaseBase::upsert
testDropNonExistingTable()
DatabaseBase::dropTable.
testUpdate( $sql, $sqlText)
provideUpdate DatabaseBase::update
testInsert( $sql, $sqlText)
provideInsert DatabaseBase::insert
testDelete( $sql, $sqlText)
provideDelete DatabaseBase::delete
testNativeReplace( $sql, $sqlText)
provideNativeReplace DatabaseBase::nativeReplace
assertLastSql( $sqlText)
testTransactionCommit()
DatabaseBase::commit.
DatabaseTestHelper $database
testDeleteJoin( $sql, $sqlText)
provideDeleteJoin DatabaseBase::deleteJoin
Helper for testing the methods from the DatabaseBase class.
Used by DatabaseBase::buildLike() to represent characters that have special meaning in SQL LIKE claus...
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at etc Handles the details of getting and saving to the user table of the database
Definition design.txt:13
const LIST_NAMES
Definition Defines.php:196
const LIST_COMMA
Definition Defines.php:193
const LIST_SET
Definition Defines.php:195
const LIST_OR
Definition Defines.php:197
const LIST_AND
Definition Defines.php:194
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition injection.txt:37