MediaWiki  master
SpecialPageFactory.php
Go to the documentation of this file.
1 <?php
25 namespace MediaWiki\SpecialPage;
26 
27 use IContextSource;
28 use Language;
33 use Profiler;
34 use RequestContext;
35 use SpecialPage;
36 use Title;
37 use User;
38 use Wikimedia\ObjectFactory;
39 
65  private const CORE_LIST = [
66  // Maintenance Reports
67  'BrokenRedirects' => [
68  'class' => \SpecialBrokenRedirects::class,
69  'services' => [
70  'PermissionManager',
71  'ContentHandlerFactory',
72  'DBLoadBalancer',
73  'LinkBatchFactory',
74  ]
75  ],
76  'Deadendpages' => [
77  'class' => \SpecialDeadendPages::class,
78  'services' => [
79  'NamespaceInfo',
80  'DBLoadBalancer',
81  'LinkBatchFactory',
82  'LanguageConverterFactory',
83  ]
84  ],
85  'DoubleRedirects' => [
86  'class' => \SpecialDoubleRedirects::class,
87  'services' => [
88  'PermissionManager',
89  'ContentHandlerFactory',
90  'LinkBatchFactory',
91  'DBLoadBalancer',
92  ]
93  ],
94  'Longpages' => [
95  'class' => \SpecialLongPages::class,
96  'services' => [
97  // Same as for Shortpages
98  'NamespaceInfo',
99  'DBLoadBalancer',
100  'LinkBatchFactory',
101  ]
102  ],
103  'Ancientpages' => [
104  'class' => \SpecialAncientPages::class,
105  'services' => [
106  'NamespaceInfo',
107  'DBLoadBalancer',
108  'LinkBatchFactory',
109  'LanguageConverterFactory',
110  ]
111  ],
112  'Lonelypages' => [
113  'class' => \SpecialLonelyPages::class,
114  'services' => [
115  'NamespaceInfo',
116  'DBLoadBalancer',
117  'LinkBatchFactory',
118  'LanguageConverterFactory',
119  ]
120  ],
121  'Fewestrevisions' => [
122  'class' => \SpecialFewestRevisions::class,
123  'services' => [
124  // Same as for Mostrevisions
125  'NamespaceInfo',
126  'DBLoadBalancer',
127  'LinkBatchFactory',
128  'LanguageConverterFactory',
129  ]
130  ],
131  'Withoutinterwiki' => [
132  'class' => \SpecialWithoutInterwiki::class,
133  'services' => [
134  'NamespaceInfo',
135  'DBLoadBalancer',
136  'LinkBatchFactory',
137  'LanguageConverterFactory',
138  ]
139  ],
140  'Protectedpages' => [
141  'class' => \SpecialProtectedpages::class,
142  'services' => [
143  'LinkBatchFactory',
144  'PermissionManager',
145  'DBLoadBalancer',
146  'CommentStore',
147  'ActorMigration',
148  'UserCache',
149  ]
150  ],
151  'Protectedtitles' => [
152  'class' => \SpecialProtectedtitles::class,
153  'services' => [
154  'LinkBatchFactory',
155  'DBLoadBalancer',
156  ]
157  ],
158  'Shortpages' => [
159  'class' => \SpecialShortPages::class,
160  'services' => [
161  // Same as for Longpages
162  'NamespaceInfo',
163  'DBLoadBalancer',
164  'LinkBatchFactory',
165  ]
166  ],
167  'Uncategorizedcategories' => [
168  'class' => \SpecialUncategorizedCategories::class,
169  'services' => [
170  // Same as for SpecialUncategorizedPages and SpecialUncategorizedTemplates
171  'NamespaceInfo',
172  'DBLoadBalancer',
173  'LinkBatchFactory',
174  'LanguageConverterFactory',
175  ]
176  ],
177  'Uncategorizedimages' => [
178  'class' => \SpecialUncategorizedImages::class,
179  'services' => [
180  'DBLoadBalancer',
181  ]
182  ],
183  'Uncategorizedpages' => [
184  'class' => \SpecialUncategorizedPages::class,
185  'services' => [
186  // Same as for SpecialUncategorizedCategories and SpecialUncategorizedTemplates
187  'NamespaceInfo',
188  'DBLoadBalancer',
189  'LinkBatchFactory',
190  'LanguageConverterFactory',
191  ]
192  ],
193  'Uncategorizedtemplates' => [
194  'class' => \SpecialUncategorizedTemplates::class,
195  'services' => [
196  // Same as for SpecialUncategorizedCategories and SpecialUncategorizedPages
197  'NamespaceInfo',
198  'DBLoadBalancer',
199  'LinkBatchFactory',
200  'LanguageConverterFactory',
201  ]
202  ],
203  'Unusedcategories' => [
204  'class' => \SpecialUnusedCategories::class,
205  'services' => [
206  'DBLoadBalancer',
207  'LinkBatchFactory',
208  ]
209  ],
210  'Unusedimages' => [
211  'class' => \SpecialUnusedImages::class,
212  'services' => [
213  'DBLoadBalancer',
214  ]
215  ],
216  'Unusedtemplates' => [
217  'class' => \SpecialUnusedTemplates::class,
218  'services' => [
219  'DBLoadBalancer',
220  ]
221  ],
222  'Unwatchedpages' => [
223  'class' => \SpecialUnwatchedPages::class,
224  'services' => [
225  'LinkBatchFactory',
226  'DBLoadBalancer',
227  'LanguageConverterFactory',
228  ]
229  ],
230  'Wantedcategories' => [
231  'class' => \SpecialWantedCategories::class,
232  'services' => [
233  'DBLoadBalancer',
234  'LinkBatchFactory',
235  'LanguageConverterFactory',
236  ]
237  ],
238  'Wantedfiles' => [
239  'class' => \WantedFilesPage::class,
240  'services' => [
241  'RepoGroup',
242  'DBLoadBalancer',
243  'LinkBatchFactory',
244  ]
245  ],
246  'Wantedpages' => [
247  'class' => \WantedPagesPage::class,
248  'services' => [
249  'DBLoadBalancer',
250  'LinkBatchFactory',
251  ]
252  ],
253  'Wantedtemplates' => [
254  'class' => \SpecialWantedTemplates::class,
255  'services' => [
256  'DBLoadBalancer',
257  'LinkBatchFactory',
258  ]
259  ],
260 
261  // List of pages
262  'Allpages' => [
263  'class' => \SpecialAllPages::class,
264  'services' => [
265  'DBLoadBalancer',
266  'SearchEngineFactory',
267  ]
268  ],
269  'Prefixindex' => [
270  'class' => \SpecialPrefixindex::class,
271  'services' => [
272  'DBLoadBalancer',
273  'LinkCache',
274  ]
275  ],
276  'Categories' => [
277  'class' => \SpecialCategories::class,
278  'services' => [
279  'LinkBatchFactory',
280  'DBLoadBalancer',
281  ]
282  ],
283  'Listredirects' => [
284  'class' => \SpecialListRedirects::class,
285  'services' => [
286  'LinkBatchFactory',
287  'DBLoadBalancer',
288  'WikiPageFactory',
289  ]
290  ],
291  'PagesWithProp' => [
292  'class' => \SpecialPagesWithProp::class,
293  'services' => [
294  'DBLoadBalancer',
295  ]
296  ],
297  'TrackingCategories' => [
298  'class' => \SpecialTrackingCategories::class,
299  'services' => [
300  'LinkBatchFactory',
301  ]
302  ],
303 
304  // Authentication
305  'Userlogin' => [
306  'class' => \SpecialUserLogin::class,
307  'services' => [
308  'AuthManager',
309  ]
310  ],
311  'Userlogout' => [
312  'class' => \SpecialUserLogout::class,
313  ],
314  'CreateAccount' => [
315  'class' => \SpecialCreateAccount::class,
316  'services' => [
317  'PermissionManager',
318  'AuthManager',
319  ]
320  ],
321  'LinkAccounts' => [
322  'class' => \SpecialLinkAccounts::class,
323  'services' => [
324  'AuthManager',
325  ]
326  ],
327  'UnlinkAccounts' => [
328  'class' => \SpecialUnlinkAccounts::class,
329  'services' => [
330  'AuthManager',
331  ]
332  ],
333  'ChangeCredentials' => [
334  'class' => \SpecialChangeCredentials::class,
335  'services' => [
336  'AuthManager',
337  ]
338  ],
339  'RemoveCredentials' => [
340  'class' => \SpecialRemoveCredentials::class,
341  'services' => [
342  'AuthManager',
343  ]
344  ],
345 
346  // Users and rights
347  'Activeusers' => [
348  'class' => \SpecialActiveUsers::class,
349  'services' => [
350  'LinkBatchFactory',
351  'PermissionManager',
352  'DBLoadBalancer',
353  'UserGroupManager',
354  ]
355  ],
356  'Block' => [
357  'class' => \SpecialBlock::class,
358  'services' => [
359  'PermissionManager',
360  'BlockUtils',
361  'BlockPermissionCheckerFactory',
362  'BlockUserFactory',
363  'UserNameUtils',
364  'UserNamePrefixSearch',
365  ]
366  ],
367  'Unblock' => [
368  'class' => \SpecialUnblock::class,
369  'services' => [
370  'UnblockUserFactory',
371  'BlockUtils',
372  'UserNameUtils',
373  'UserNamePrefixSearch',
374  ]
375  ],
376  'BlockList' => [
377  'class' => \SpecialBlockList::class,
378  'services' => [
379  'PermissionManager',
380  'LinkBatchFactory',
381  'BlockRestrictionStore',
382  'DBLoadBalancer',
383  'ActorMigration',
384  'CommentStore',
385  ],
386  ],
387  'AutoblockList' => [
388  'class' => \SpecialAutoblockList::class,
389  'services' => [
390  'PermissionManager',
391  'LinkBatchFactory',
392  'BlockRestrictionStore',
393  'DBLoadBalancer',
394  'ActorMigration',
395  'CommentStore',
396  ],
397  ],
398  'ChangePassword' => [
399  'class' => \SpecialChangePassword::class,
400  ],
401  'BotPasswords' => [
402  'class' => \SpecialBotPasswords::class,
403  'services' => [
404  'PasswordFactory',
405  'AuthManager',
406  ]
407  ],
408  'PasswordReset' => [
409  'class' => \SpecialPasswordReset::class,
410  'services' => [
411  'PasswordReset'
412  ]
413  ],
414  'DeletedContributions' => [
415  'class' => \SpecialDeletedContributions::class,
416  'services' => [
417  'PermissionManager',
418  'DBLoadBalancer',
419  'CommentStore',
420  'ActorMigration',
421  'RevisionFactory',
422  'NamespaceInfo',
423  'UserNameUtils',
424  'UserNamePrefixSearch',
425  ]
426  ],
427  'Preferences' => [
428  'class' => \SpecialPreferences::class,
429  'services' => [
430  'PreferencesFactory',
431  'PermissionManager',
432  'UserOptionsManager',
433  ]
434  ],
435  'ResetTokens' => [
436  'class' => \SpecialResetTokens::class,
437  ],
438  'Contributions' => [
439  'class' => \SpecialContributions::class,
440  'services' => [
441  'LinkBatchFactory',
442  'PermissionManager',
443  'DBLoadBalancer',
444  'ActorMigration',
445  'RevisionStore',
446  'NamespaceInfo',
447  'UserNameUtils',
448  'UserNamePrefixSearch',
449  'UserOptionsLookup',
450  ]
451  ],
452  'Listgrouprights' => [
453  'class' => \SpecialListGroupRights::class,
454  'services' => [
455  'NamespaceInfo',
456  'UserGroupManager',
457  'LanguageConverterFactory',
458  ]
459  ],
460  'Listgrants' => [
461  'class' => \SpecialListGrants::class,
462  ],
463  'Listusers' => [
464  'class' => \SpecialListUsers::class,
465  'services' => [
466  'LinkBatchFactory',
467  'PermissionManager',
468  'DBLoadBalancer',
469  'UserGroupManager',
470  ]
471  ],
472  'Listadmins' => [
473  'class' => \SpecialListAdmins::class,
474  ],
475  'Listbots' => [
476  'class' => \SpecialListBots::class,
477  ],
478  'Userrights' => [
479  'class' => \UserrightsPage::class,
480  'services' => [
481  'PermissionManager',
482  'UserGroupManagerFactory',
483  'UserNameUtils',
484  'UserNamePrefixSearch',
485  ]
486  ],
487  'EditWatchlist' => [
488  'class' => \SpecialEditWatchlist::class,
489  'services' => [
490  'WatchedItemStore',
491  'TitleParser',
492  'GenderCache',
493  'LinkBatchFactory',
494  'NamespaceInfo',
495  'WikiPageFactory',
496  ]
497  ],
498  'PasswordPolicies' => [
499  'class' => \SpecialPasswordPolicies::class,
500  'services' => [
501  'NamespaceInfo'
502  ]
503  ],
504 
505  // Recent changes and logs
506  'Newimages' => [
507  'class' => \SpecialNewFiles::class,
508  'services' => [
509  'MimeAnalyzer',
510  'PermissionManager',
511  'ActorMigration',
512  'DBLoadBalancer',
513  'UserCache',
514  ]
515  ],
516  'Log' => [
517  'class' => \SpecialLog::class,
518  'services' => [
519  'PermissionManager',
520  'LinkBatchFactory',
521  'DBLoadBalancer',
522  'ActorMigration',
523  ]
524  ],
525  'Watchlist' => [
526  'class' => \SpecialWatchlist::class,
527  'services' => [
528  'WatchedItemStore',
529  'WatchlistNotificationManager',
530  'PermissionManager',
531  'DBLoadBalancer',
532  'UserOptionsLookup',
533  ]
534  ],
535  'Newpages' => [
536  'class' => \SpecialNewpages::class,
537  'services' => [
538  'LinkBatchFactory',
539  'CommentStore',
540  'ContentHandlerFactory',
541  'PermissionManager',
542  'DBLoadBalancer',
543  'RevisionLookup',
544  'NamespaceInfo',
545  'ActorMigration',
546  'UserOptionsLookup',
547  ]
548  ],
549  'Recentchanges' => [
550  'class' => \SpecialRecentChanges::class,
551  'services' => [
552  'PermissionManager',
553  'WatchedItemStore',
554  'MessageCache',
555  'DBLoadBalancer',
556  'UserOptionsLookup',
557  ]
558  ],
559  'Recentchangeslinked' => [
560  'class' => \SpecialRecentChangesLinked::class,
561  'services' => [
562  'PermissionManager',
563  'WatchedItemStore',
564  'MessageCache',
565  'DBLoadBalancer',
566  'UserOptionsLookup',
567  'SearchEngineFactory',
568  ]
569  ],
570  'Tags' => [
571  'class' => \SpecialTags::class,
572  'services' => [
573  'PermissionManager',
574  ]
575  ],
576 
577  // Media reports and uploads
578  'Listfiles' => [
579  'class' => \SpecialListFiles::class,
580  'services' => [
581  'RepoGroup',
582  'PermissionManager',
583  'DBLoadBalancer',
584  'CommentStore',
585  'ActorMigration',
586  'UserNameUtils',
587  'UserNamePrefixSearch',
588  'UserCache',
589  ]
590  ],
591  'Filepath' => [
592  'class' => \SpecialFilepath::class,
593  ],
594  'MediaStatistics' => [
595  'class' => \SpecialMediaStatistics::class,
596  'services' => [
597  'MimeAnalyzer',
598  'DBLoadBalancer',
599  'LinkBatchFactory',
600  ]
601  ],
602  'MIMEsearch' => [
603  'class' => \SpecialMIMESearch::class,
604  'services' => [
605  'DBLoadBalancer',
606  'LinkBatchFactory',
607  'LanguageConverterFactory',
608  ]
609  ],
610  'FileDuplicateSearch' => [
611  'class' => \SpecialFileDuplicateSearch::class,
612  'services' => [
613  'LinkBatchFactory',
614  'RepoGroup',
615  'SearchEngineFactory',
616  'DBLoadBalancer',
617  'LanguageConverterFactory',
618  ]
619  ],
620  'Upload' => [
621  'class' => \SpecialUpload::class,
622  'services' => [
623  'RepoGroup',
624  'PermissionManager',
625  'UserOptionsLookup',
626  'NamespaceInfo',
627  ]
628  ],
629  'UploadStash' => [
630  'class' => \SpecialUploadStash::class,
631  'services' => [
632  'RepoGroup',
633  'HttpRequestFactory',
634  ]
635  ],
636  'ListDuplicatedFiles' => [
637  'class' => \SpecialListDuplicatedFiles::class,
638  'services' => [
639  'DBLoadBalancer',
640  'LinkBatchFactory',
641  ]
642  ],
643 
644  // Data and tools
645  'ApiSandbox' => [
646  'class' => \SpecialApiSandbox::class,
647  'services' => [
648  'PermissionManager',
649  ],
650  ],
651  'Statistics' => [
652  'class' => \SpecialStatistics::class,
653  'services' => [
654  'NamespaceInfo',
655  ]
656  ],
657  'Allmessages' => [
658  'class' => \SpecialAllMessages::class,
659  'services' => [
660  'LocalisationCache',
661  'DBLoadBalancer',
662  ]
663  ],
664  'Version' => [
665  'class' => \SpecialVersion::class,
666  'services' => [
667  'Parser',
668  ]
669  ],
670  'Lockdb' => [
671  'class' => \SpecialLockdb::class,
672  ],
673  'Unlockdb' => [
674  'class' => \SpecialUnlockdb::class,
675  ],
676 
677  // Redirecting special pages
678  'LinkSearch' => [
679  'class' => \SpecialLinkSearch::class,
680  'services' => [
681  'DBLoadBalancer',
682  'LinkBatchFactory',
683  ]
684  ],
685  'Randompage' => [
686  'class' => \RandomPage::class,
687  'services' => [
688  'DBLoadBalancer',
689  'NamespaceInfo',
690  ]
691  ],
692  'RandomInCategory' => [
693  'class' => \SpecialRandomInCategory::class,
694  'services' => [
695  'DBLoadBalancer',
696  ]
697  ],
698  'Randomredirect' => [
699  'class' => \SpecialRandomredirect::class,
700  'services' => [
701  'DBLoadBalancer',
702  'NamespaceInfo',
703  ]
704  ],
705  'Randomrootpage' => [
706  'class' => \SpecialRandomrootpage::class,
707  'services' => [
708  'DBLoadBalancer',
709  'NamespaceInfo',
710  ]
711  ],
712  'GoToInterwiki' => [
713  'class' => \SpecialGoToInterwiki::class,
714  ],
715 
716  // High use pages
717  'Mostlinkedcategories' => [
718  'class' => \SpecialMostLinkedCategories::class,
719  'services' => [
720  'DBLoadBalancer',
721  'LinkBatchFactory',
722  'LanguageConverterFactory',
723  ]
724  ],
725  'Mostimages' => [
726  'class' => \MostimagesPage::class,
727  'services' => [
728  'DBLoadBalancer',
729  'LanguageConverterFactory',
730  ]
731  ],
732  'Mostinterwikis' => [
733  'class' => \SpecialMostInterwikis::class,
734  'services' => [
735  'NamespaceInfo',
736  'DBLoadBalancer',
737  'LinkBatchFactory',
738  ]
739  ],
740  'Mostlinked' => [
741  'class' => \SpecialMostLinked::class,
742  'services' => [
743  'DBLoadBalancer',
744  'LinkBatchFactory',
745  ]
746  ],
747  'Mostlinkedtemplates' => [
748  'class' => \SpecialMostLinkedTemplates::class,
749  'services' => [
750  'DBLoadBalancer',
751  'LinkBatchFactory',
752  ]
753  ],
754  'Mostcategories' => [
755  'class' => \SpecialMostCategories::class,
756  'services' => [
757  'NamespaceInfo',
758  'DBLoadBalancer',
759  'LinkBatchFactory',
760  ]
761  ],
762  'Mostrevisions' => [
763  'class' => \SpecialMostRevisions::class,
764  'services' => [
765  // Same as for Fewestrevisions
766  'NamespaceInfo',
767  'DBLoadBalancer',
768  'LinkBatchFactory',
769  'LanguageConverterFactory',
770  ]
771  ],
772 
773  // Page tools
774  'ComparePages' => [
775  'class' => \SpecialComparePages::class,
776  'services' => [
777  'RevisionLookup',
778  'ContentHandlerFactory',
779  ]
780  ],
781  'Export' => [
782  'class' => \SpecialExport::class,
783  'services' => [
784  'PermissionManager',
785  'DBLoadBalancer',
786  ]
787  ],
788  'Import' => [
789  'class' => \SpecialImport::class,
790  'services' => [
791  'PermissionManager',
792  ]
793  ],
794  'Undelete' => [
795  'class' => \SpecialUndelete::class,
796  'services' => [
797  'PermissionManager',
798  'RevisionStore',
799  'RevisionRenderer',
800  'ContentHandlerFactory',
801  'ChangeTagDefStore',
802  'LinkBatchFactory',
803  'RepoGroup',
804  'DBLoadBalancer',
805  'UserOptionsLookup',
806  'WikiPageFactory',
807  'SearchEngineFactory',
808  ],
809  ],
810  'Whatlinkshere' => [
811  'class' => \SpecialWhatLinksHere::class,
812  'services' => [
813  'DBLoadBalancer',
814  'LinkBatchFactory',
815  'PermissionManager',
816  'ContentHandlerFactory',
817  'SearchEngineFactory',
818  'NamespaceInfo',
819  ]
820  ],
821  'MergeHistory' => [
822  'class' => \SpecialMergeHistory::class,
823  'services' => [
824  'MergeHistoryFactory',
825  'LinkBatchFactory',
826  'DBLoadBalancer',
827  'RevisionStore',
828  ]
829  ],
830  'ExpandTemplates' => [
831  'class' => \SpecialExpandTemplates::class,
832  'services' => [
833  'PermissionManager',
834  'Parser',
835  'UserOptionsLookup',
836  ],
837  ],
838  'ChangeContentModel' => [
839  'class' => \SpecialChangeContentModel::class,
840  'services' => [
841  'ContentHandlerFactory',
842  'ContentModelChangeFactory',
843  'SpamChecker',
844  'RevisionLookup',
845  'WikiPageFactory',
846  'SearchEngineFactory',
847  ],
848  ],
849 
850  // Other
851  'Booksources' => [
852  'class' => \SpecialBookSources::class,
853  'services' => [
854  'RevisionLookup',
855  ]
856  ],
857 
858  // Unlisted / redirects
859  'ApiHelp' => [
860  'class' => \SpecialApiHelp::class,
861  ],
862  'Blankpage' => [
863  'class' => \SpecialBlankpage::class,
864  ],
865  'Diff' => [
866  'class' => \SpecialDiff::class,
867  ],
868  'EditPage' => [
869  'class' => \SpecialEditPage::class,
870  ],
871  'EditTags' => [
872  'class' => \SpecialEditTags::class,
873  'services' => [
874  'PermissionManager',
875  ],
876  ],
877  'Emailuser' => [
878  'class' => \SpecialEmailUser::class,
879  'services' => [
880  'UserNameUtils',
881  'UserNamePrefixSearch',
882  'UserOptionsLookup',
883  ]
884  ],
885  'Movepage' => [
886  'class' => \MovePageForm::class,
887  'services' => [
888  'MovePageFactory',
889  'PermissionManager',
890  'UserOptionsLookup',
891  'DBLoadBalancer',
892  'ContentHandlerFactory',
893  'NamespaceInfo',
894  'LinkBatchFactory',
895  'RepoGroup',
896  'WikiPageFactory',
897  'SearchEngineFactory',
898  ]
899  ],
900  'Mycontributions' => [
901  'class' => \SpecialMycontributions::class,
902  ],
903  'MyLanguage' => [
904  'class' => \SpecialMyLanguage::class,
905  'services' => [
906  'LanguageNameUtils',
907  'WikiPageFactory',
908  ]
909  ],
910  'Mypage' => [
911  'class' => \SpecialMypage::class,
912  ],
913  'Mytalk' => [
914  'class' => \SpecialMytalk::class,
915  ],
916  'PageHistory' => [
917  'class' => \SpecialPageHistory::class,
918  ],
919  'PageInfo' => [
920  'class' => \SpecialPageInfo::class,
921  ],
922  'Purge' => [
923  'class' => \SpecialPurge::class,
924  ],
925  'Myuploads' => [
926  'class' => \SpecialMyuploads::class,
927  ],
928  'AllMyUploads' => [
929  'class' => \SpecialAllMyUploads::class,
930  ],
931  'NewSection' => [
932  'class' => \SpecialNewSection::class,
933  ],
934  'PermanentLink' => [
935  'class' => \SpecialPermanentLink::class,
936  ],
937  'Redirect' => [
938  'class' => \SpecialRedirect::class,
939  'services' => [
940  'PermissionManager',
941  'RepoGroup'
942  ]
943  ],
944  'Revisiondelete' => [
945  'class' => \SpecialRevisionDelete::class,
946  'services' => [
947  'PermissionManager',
948  'RepoGroup',
949  ],
950  ],
951  'RunJobs' => [
952  'class' => \SpecialRunJobs::class,
953  'services' => [
954  'JobRunner',
955  'ReadOnlyMode',
956  ]
957  ],
958  'Specialpages' => [
959  'class' => \SpecialSpecialpages::class,
960  ],
961  'PageData' => [
962  'class' => \SpecialPageData::class,
963  ],
964  ];
965 
967  private $list;
968 
970  private $aliases;
971 
973  private $options;
974 
976  private $contLang;
977 
979  private $objectFactory;
980 
982  private $hookContainer;
983 
985  private $hookRunner;
986 
990  public const CONSTRUCTOR_OPTIONS = [
991  'DisableInternalSearch',
992  'EmailAuthentication',
993  'EnableEmail',
994  'EnableJavaScriptTest',
995  'EnableSpecialMute',
996  'PageLanguageUseDB',
997  'SpecialPages',
998  ];
999 
1006  public function __construct(
1009  ObjectFactory $objectFactory,
1011  ) {
1012  $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
1013  $this->options = $options;
1014  $this->contLang = $contLang;
1015  $this->objectFactory = $objectFactory;
1016  $this->hookContainer = $hookContainer;
1017  $this->hookRunner = new HookRunner( $hookContainer );
1018  }
1019 
1026  public function getNames() : array {
1027  return array_keys( $this->getPageList() );
1028  }
1029 
1035  private function getPageList() : array {
1036  if ( !is_array( $this->list ) ) {
1037  $this->list = self::CORE_LIST;
1038 
1039  if ( !$this->options->get( 'DisableInternalSearch' ) ) {
1040  $this->list['Search'] = [
1041  'class' => \SpecialSearch::class,
1042  'services' => [
1043  'SearchEngineConfig',
1044  'SearchEngineFactory',
1045  'PermissionManager',
1046  'NamespaceInfo',
1047  'ContentHandlerFactory',
1048  'InterwikiLookup',
1049  'ReadOnlyMode',
1050  'UserOptionsManager',
1051  'LanguageConverterFactory'
1052  ]
1053  ];
1054  }
1055 
1056  if ( $this->options->get( 'EmailAuthentication' ) ) {
1057  $this->list['Confirmemail'] = [
1058  'class' => \SpecialConfirmEmail::class,
1059  'services' => [
1060  'PermissionManager',
1061  'UserFactory',
1062  ]
1063  ];
1064  $this->list['Invalidateemail'] = [
1065  'class' => \SpecialEmailInvalidate::class,
1066  'services' => [
1067  'UserFactory',
1068  ]
1069  ];
1070  }
1071 
1072  if ( $this->options->get( 'EnableEmail' ) ) {
1073  $this->list['ChangeEmail'] = [
1074  'class' => \SpecialChangeEmail::class,
1075  'services' => [
1076  'PermissionManager',
1077  'AuthManager',
1078  ],
1079  ];
1080  }
1081 
1082  if ( $this->options->get( 'EnableJavaScriptTest' ) ) {
1083  $this->list['JavaScriptTest'] = [
1084  'class' => \SpecialJavaScriptTest::class
1085  ];
1086  }
1087 
1088  if ( $this->options->get( 'EnableSpecialMute' ) ) {
1089  $this->list['Mute'] = [
1090  'class' => \SpecialMute::class,
1091  'services' => [
1092  'UserOptionsManager',
1093  ]
1094  ];
1095  }
1096 
1097  if ( $this->options->get( 'PageLanguageUseDB' ) ) {
1098  $this->list['PageLanguage'] = [
1099  'class' => \SpecialPageLanguage::class,
1100  'services' => [
1101  'PermissionManager',
1102  'ContentHandlerFactory',
1103  'LanguageNameUtils',
1104  'DBLoadBalancer',
1105  'SearchEngineFactory',
1106  ]
1107  ];
1108  }
1109 
1110  // Add extension special pages
1111  $this->list = array_merge( $this->list, $this->options->get( 'SpecialPages' ) );
1112 
1113  // This hook can be used to disable unwanted core special pages
1114  // or conditionally register special pages.
1115  $this->hookRunner->onSpecialPage_initList( $this->list );
1116  }
1117 
1118  return $this->list;
1119  }
1120 
1127  private function getAliasList() : array {
1128  if ( $this->aliases === null ) {
1129  $aliases = $this->contLang->getSpecialPageAliases();
1130  $pageList = $this->getPageList();
1131 
1132  $this->aliases = [];
1133  $keepAlias = [];
1134 
1135  // Force every canonical name to be an alias for itself.
1136  foreach ( $pageList as $name => $stuff ) {
1137  $caseFoldedAlias = $this->contLang->caseFold( $name );
1138  $this->aliases[$caseFoldedAlias] = $name;
1139  $keepAlias[$caseFoldedAlias] = 'canonical';
1140  }
1141 
1142  // Check for $aliases being an array since Language::getSpecialPageAliases can return null
1143  if ( is_array( $aliases ) ) {
1144  foreach ( $aliases as $realName => $aliasList ) {
1145  $aliasList = array_values( $aliasList );
1146  foreach ( $aliasList as $i => $alias ) {
1147  $caseFoldedAlias = $this->contLang->caseFold( $alias );
1148 
1149  if ( isset( $this->aliases[$caseFoldedAlias] ) &&
1150  $realName === $this->aliases[$caseFoldedAlias]
1151  ) {
1152  // Ignore same-realName conflicts
1153  continue;
1154  }
1155 
1156  if ( !isset( $keepAlias[$caseFoldedAlias] ) ) {
1157  $this->aliases[$caseFoldedAlias] = $realName;
1158  if ( !$i ) {
1159  $keepAlias[$caseFoldedAlias] = 'first';
1160  }
1161  } elseif ( !$i ) {
1162  wfWarn( "First alias '$alias' for $realName conflicts with " .
1163  "{$keepAlias[$caseFoldedAlias]} alias for " .
1164  $this->aliases[$caseFoldedAlias]
1165  );
1166  }
1167  }
1168  }
1169  }
1170  }
1171 
1172  return $this->aliases;
1173  }
1174 
1183  public function resolveAlias( $alias ) {
1184  $bits = explode( '/', $alias, 2 );
1185 
1186  $caseFoldedAlias = $this->contLang->caseFold( $bits[0] );
1187  $caseFoldedAlias = str_replace( ' ', '_', $caseFoldedAlias );
1188  $aliases = $this->getAliasList();
1189  if ( !isset( $aliases[$caseFoldedAlias] ) ) {
1190  return [ null, null ];
1191  }
1192  $name = $aliases[$caseFoldedAlias];
1193  $par = $bits[1] ?? null; // T4087
1194 
1195  return [ $name, $par ];
1196  }
1197 
1204  public function exists( $name ) {
1205  list( $title, /*...*/ ) = $this->resolveAlias( $name );
1206 
1207  $specialPageList = $this->getPageList();
1208  return isset( $specialPageList[$title] );
1209  }
1210 
1217  public function getPage( $name ) {
1218  list( $realName, /*...*/ ) = $this->resolveAlias( $name );
1219 
1220  $specialPageList = $this->getPageList();
1221 
1222  if ( isset( $specialPageList[$realName] ) ) {
1223  $rec = $specialPageList[$realName];
1224 
1225  if ( $rec instanceof SpecialPage ) {
1227  "A SpecialPage instance for $realName was found in " .
1228  '$wgSpecialPages or came from a SpecialPage_initList hook handler, ' .
1229  'this was deprecated in MediaWiki 1.34',
1230  '1.34'
1231  );
1232 
1233  $page = $rec; // XXX: we should deep clone here
1234  } elseif ( is_array( $rec ) || is_string( $rec ) || is_callable( $rec ) ) {
1235  $page = $this->objectFactory->createObject(
1236  $rec,
1237  [
1238  'allowClassName' => true,
1239  'allowCallable' => true
1240  ]
1241  );
1242  } else {
1243  $page = null;
1244  }
1245 
1246  if ( $page instanceof SpecialPage ) {
1247  $page->setHookContainer( $this->hookContainer );
1248  $page->setContentLanguage( $this->contLang );
1249  $page->setSpecialPageFactory( $this );
1250  return $page;
1251  }
1252 
1253  // It's not a classname, nor a callback, nor a legacy constructor array,
1254  // nor a special page object. Give up.
1255  wfLogWarning( "Cannot instantiate special page $realName: bad spec!" );
1256  }
1257 
1258  return null;
1259  }
1260 
1269  public function getUsablePages( User $user ) : array {
1270  $pages = [];
1271  foreach ( $this->getPageList() as $name => $rec ) {
1272  $page = $this->getPage( $name );
1273  if ( $page ) { // not null
1274  $page->setContext( RequestContext::getMain() );
1275  if ( $page->isListed()
1276  && ( !$page->isRestricted() || $page->userCanExecute( $user ) )
1277  ) {
1278  $pages[$name] = $page;
1279  }
1280  }
1281  }
1282 
1283  return $pages;
1284  }
1285 
1291  public function getRegularPages() : array {
1292  $pages = [];
1293  foreach ( $this->getPageList() as $name => $rec ) {
1294  $page = $this->getPage( $name );
1295  if ( $page && $page->isListed() && !$page->isRestricted() ) {
1296  $pages[$name] = $page;
1297  }
1298  }
1299 
1300  return $pages;
1301  }
1302 
1310  public function getRestrictedPages( User $user ) : array {
1311  $pages = [];
1312  foreach ( $this->getPageList() as $name => $rec ) {
1313  $page = $this->getPage( $name );
1314  if ( $page
1315  && $page->isListed()
1316  && $page->isRestricted()
1317  && $page->userCanExecute( $user )
1318  ) {
1319  $pages[$name] = $page;
1320  }
1321  }
1322 
1323  return $pages;
1324  }
1325 
1341  public function executePath( Title &$title, IContextSource &$context, $including = false,
1342  LinkRenderer $linkRenderer = null
1343  ) {
1344  // @todo FIXME: Redirects broken due to this call
1345  $bits = explode( '/', $title->getDBkey(), 2 );
1346  $name = $bits[0];
1347  $par = $bits[1] ?? null; // T4087
1348 
1349  $page = $this->getPage( $name );
1350  if ( !$page ) {
1351  $context->getOutput()->setArticleRelated( false );
1352  $context->getOutput()->setRobotPolicy( 'noindex,nofollow' );
1353 
1354  global $wgSend404Code;
1355  if ( $wgSend404Code ) {
1356  $context->getOutput()->setStatusCode( 404 );
1357  }
1358 
1359  $context->getOutput()->showErrorPage( 'nosuchspecialpage', 'nospecialpagetext' );
1360 
1361  return false;
1362  }
1363 
1364  if ( !$including ) {
1365  // Narrow DB query expectations for this HTTP request
1366  $trxLimits = $context->getConfig()->get( 'TrxProfilerLimits' );
1367  $trxProfiler = Profiler::instance()->getTransactionProfiler();
1368  if ( $context->getRequest()->wasPosted() && !$page->doesWrites() ) {
1369  $trxProfiler->setExpectations( $trxLimits['POST-nonwrite'], __METHOD__ );
1370  $context->getRequest()->markAsSafeRequest();
1371  }
1372  }
1373 
1374  // Page exists, set the context
1375  $page->setContext( $context );
1376 
1377  if ( !$including ) {
1378  // Redirect to canonical alias for GET commands
1379  // Not for POST, we'd lose the post data, so it's best to just distribute
1380  // the request. Such POST requests are possible for old extensions that
1381  // generate self-links without being aware that their default name has
1382  // changed.
1383  if ( $name != $page->getLocalName() && !$context->getRequest()->wasPosted() ) {
1384  $query = $context->getRequest()->getQueryValues();
1385  unset( $query['title'] );
1386  $title = $page->getPageTitle( $par );
1387  $url = $title->getFullURL( $query );
1388  $context->getOutput()->redirect( $url );
1389 
1390  return $title;
1391  }
1392 
1393  // @phan-suppress-next-line PhanUndeclaredMethod
1394  $context->setTitle( $page->getPageTitle( $par ) );
1395  } elseif ( !$page->isIncludable() ) {
1396  return false;
1397  }
1398 
1399  $page->including( $including );
1400  if ( $linkRenderer ) {
1401  $page->setLinkRenderer( $linkRenderer );
1402  }
1403 
1404  // Execute special page
1405  $page->run( $par );
1406 
1407  return true;
1408  }
1409 
1425  public function capturePath(
1426  Title $title, IContextSource $context, LinkRenderer $linkRenderer = null
1427  ) {
1428  global $wgTitle, $wgOut, $wgRequest, $wgUser, $wgLang;
1429  $main = RequestContext::getMain();
1430 
1431  // Save current globals and main context
1432  $glob = [
1433  'title' => $wgTitle,
1434  'output' => $wgOut,
1435  'request' => $wgRequest,
1436  'user' => $wgUser,
1437  'language' => $wgLang,
1438  ];
1439  $ctx = [
1440  'title' => $main->getTitle(),
1441  'output' => $main->getOutput(),
1442  'request' => $main->getRequest(),
1443  'user' => $main->getUser(),
1444  'language' => $main->getLanguage(),
1445  ];
1446  if ( $main->canUseWikiPage() ) {
1447  $ctx['wikipage'] = $main->getWikiPage();
1448  }
1449 
1450  // Override
1451  $wgTitle = $title;
1452  $wgOut = $context->getOutput();
1454  $wgUser = $context->getUser();
1456  $main->setTitle( $title );
1457  $main->setOutput( $context->getOutput() );
1458  $main->setRequest( $context->getRequest() );
1459  $main->setUser( $context->getUser() );
1460  $main->setLanguage( $context->getLanguage() );
1461 
1462  // The useful part
1463  $ret = $this->executePath( $title, $context, true, $linkRenderer );
1464 
1465  // Restore old globals and context
1466  $wgTitle = $glob['title'];
1467  $wgOut = $glob['output'];
1468  $wgRequest = $glob['request'];
1469  $wgUser = $glob['user'];
1470  $wgLang = $glob['language'];
1471  $main->setTitle( $ctx['title'] );
1472  $main->setOutput( $ctx['output'] );
1473  $main->setRequest( $ctx['request'] );
1474  $main->setUser( $ctx['user'] );
1475  $main->setLanguage( $ctx['language'] );
1476  if ( isset( $ctx['wikipage'] ) ) {
1477  $main->setWikiPage( $ctx['wikipage'] );
1478  }
1479 
1480  return $ret;
1481  }
1482 
1490  public function getLocalNameFor( $name, $subpage = false ) {
1491  $aliases = $this->contLang->getSpecialPageAliases();
1492  $aliasList = $this->getAliasList();
1493 
1494  // Find the first alias that maps back to $name
1495  if ( isset( $aliases[$name] ) ) {
1496  $found = false;
1497  foreach ( $aliases[$name] as $alias ) {
1498  $caseFoldedAlias = $this->contLang->caseFold( $alias );
1499  $caseFoldedAlias = str_replace( ' ', '_', $caseFoldedAlias );
1500  if ( isset( $aliasList[$caseFoldedAlias] ) &&
1501  $aliasList[$caseFoldedAlias] === $name
1502  ) {
1503  $name = $alias;
1504  $found = true;
1505  break;
1506  }
1507  }
1508  if ( !$found ) {
1509  wfWarn( "Did not find a usable alias for special page '$name'. " .
1510  "It seems all defined aliases conflict?" );
1511  }
1512  } else {
1513  // Check if someone misspelled the correct casing
1514  if ( is_array( $aliases ) ) {
1515  foreach ( $aliases as $n => $values ) {
1516  if ( strcasecmp( $name, $n ) === 0 ) {
1517  wfWarn( "Found alias defined for $n when searching for " .
1518  "special page aliases for $name. Case mismatch?" );
1519  return $this->getLocalNameFor( $n, $subpage );
1520  }
1521  }
1522  }
1523 
1524  wfWarn( "Did not find alias for special page '$name'. " .
1525  "Perhaps no aliases are defined for it?" );
1526  }
1527 
1528  if ( $subpage !== false && $subpage !== null ) {
1529  // Make sure it's in dbkey form
1530  $subpage = str_replace( ' ', '_', $subpage );
1531  $name = "$name/$subpage";
1532  }
1533 
1534  return $this->contLang->ucfirst( $name );
1535  }
1536 
1543  public function getTitleForAlias( $alias ) {
1544  list( $name, $subpage ) = $this->resolveAlias( $alias );
1545  if ( $name != null ) {
1546  return SpecialPage::getTitleFor( $name, $subpage );
1547  }
1548 
1549  return null;
1550  }
1551 }
1552 
1554 class_alias( SpecialPageFactory::class, 'MediaWiki\\Special\\SpecialPageFactory' );
$wgSend404Code
$wgSend404Code
Some web hosts attempt to rewrite all responses with a 404 (not found) status code,...
Definition: DefaultSettings.php:3662
MediaWiki\SpecialPage\SpecialPageFactory\executePath
executePath(Title &$title, IContextSource &$context, $including=false, LinkRenderer $linkRenderer=null)
Execute a special page path.
Definition: SpecialPageFactory.php:1341
MediaWiki\SpecialPage\SpecialPageFactory\__construct
__construct(ServiceOptions $options, Language $contLang, ObjectFactory $objectFactory, HookContainer $hookContainer)
Definition: SpecialPageFactory.php:1006
MediaWiki\SpecialPage\SpecialPageFactory\getUsablePages
getUsablePages(User $user)
Return categorised listable special pages which are available for the current user,...
Definition: SpecialPageFactory.php:1269
MediaWiki\SpecialPage\SpecialPageFactory\$options
ServiceOptions $options
Definition: SpecialPageFactory.php:973
Profiler\instance
static instance()
Singleton.
Definition: Profiler.php:69
MediaWiki\SpecialPage\SpecialPageFactory\CORE_LIST
const CORE_LIST
List of special page names to the subclass of SpecialPage which handles them.
Definition: SpecialPageFactory.php:65
MediaWiki\Linker\LinkRenderer
Class that generates HTML links for pages.
Definition: LinkRenderer.php:41
MediaWiki\SpecialPage\SpecialPageFactory
Factory for handling the special page list and generating SpecialPage objects.
Definition: SpecialPageFactory.php:61
MediaWiki\SpecialPage\SpecialPageFactory\resolveAlias
resolveAlias( $alias)
Given a special page name with a possible subpage, return an array where the first element is the spe...
Definition: SpecialPageFactory.php:1183
MediaWiki\SpecialPage\SpecialPageFactory\getRestrictedPages
getRestrictedPages(User $user)
Return categorised listable special pages which are available for the current user,...
Definition: SpecialPageFactory.php:1310
MediaWiki\SpecialPage\SpecialPageFactory\$hookRunner
HookRunner $hookRunner
Definition: SpecialPageFactory.php:985
SpecialPage\getTitleFor
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
Definition: SpecialPage.php:106
wfLogWarning
wfLogWarning( $msg, $callerOffset=1, $level=E_USER_WARNING)
Send a warning as a PHP error and the debug log.
Definition: GlobalFunctions.php:1093
MediaWiki\SpecialPage\SpecialPageFactory\getLocalNameFor
getLocalNameFor( $name, $subpage=false)
Get the local name for a specified canonical name.
Definition: SpecialPageFactory.php:1490
MediaWiki\SpecialPage\SpecialPageFactory\$list
array $list
Special page name => class name.
Definition: SpecialPageFactory.php:967
$wgLang
$wgLang
Definition: Setup.php:776
MediaWiki\SpecialPage\SpecialPageFactory\$contLang
Language $contLang
Definition: SpecialPageFactory.php:976
wfDeprecatedMsg
wfDeprecatedMsg( $msg, $version=false, $component=false, $callerOffset=2)
Log a deprecation warning with arbitrary message text.
Definition: GlobalFunctions.php:1065
MediaWiki\Config\ServiceOptions
A class for passing options to services.
Definition: ServiceOptions.php:27
Profiler
Profiler base class that defines the interface and some shared functionality.
Definition: Profiler.php:36
$title
$title
Definition: testCompression.php:38
RequestContext
Group all the pieces relevant to the context of a request into one instance @newable.
Definition: RequestContext.php:40
$wgTitle
$wgTitle
Definition: Setup.php:794
MediaWiki\SpecialPage\SpecialPageFactory\getNames
getNames()
Returns a list of canonical special page names.
Definition: SpecialPageFactory.php:1026
MediaWiki\SpecialPage\SpecialPageFactory\exists
exists( $name)
Check if a given name exist as a special page or as a special page alias.
Definition: SpecialPageFactory.php:1204
SpecialPage
Parent class for all special pages.
Definition: SpecialPage.php:42
MediaWiki\SpecialPage\SpecialPageFactory\getRegularPages
getRegularPages()
Return categorised listable special pages for all users.
Definition: SpecialPageFactory.php:1291
MediaWiki\SpecialPage\SpecialPageFactory\$objectFactory
ObjectFactory $objectFactory
Definition: SpecialPageFactory.php:979
IContextSource\getUser
getUser()
MediaWiki\SpecialPage\SpecialPageFactory\getPage
getPage( $name)
Find the object with a given name and return it (or NULL)
Definition: SpecialPageFactory.php:1217
RequestContext\getMain
static getMain()
Get the RequestContext object associated with the main request.
Definition: RequestContext.php:476
IContextSource
Interface for objects which can provide a MediaWiki context on request.
Definition: IContextSource.php:57
Title
Represents a title within MediaWiki.
Definition: Title.php:46
MediaWiki\SpecialPage\SpecialPageFactory\capturePath
capturePath(Title $title, IContextSource $context, LinkRenderer $linkRenderer=null)
Just like executePath() but will override global variables and execute the page in "inclusion" mode.
Definition: SpecialPageFactory.php:1425
IContextSource\getConfig
getConfig()
Get the site configuration.
MediaWiki\SpecialPage\SpecialPageFactory\$hookContainer
HookContainer $hookContainer
Definition: SpecialPageFactory.php:982
IContextSource\getRequest
getRequest()
MediaWiki\HookContainer\HookContainer
HookContainer class.
Definition: HookContainer.php:45
wfWarn
wfWarn( $msg, $callerOffset=1, $level=E_USER_NOTICE)
Send a warning either to the debug log or in a PHP error depending on $wgDevelopmentWarnings.
Definition: GlobalFunctions.php:1080
MediaWiki\HookContainer\HookRunner
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
Definition: HookRunner.php:571
MediaWiki\SpecialPage\SpecialPageFactory\getTitleForAlias
getTitleForAlias( $alias)
Get a title for a given alias.
Definition: SpecialPageFactory.php:1543
$wgRequest
if(! $wgDBerrorLogTZ) $wgRequest
Definition: Setup.php:644
MediaWiki\SpecialPage\SpecialPageFactory\CONSTRUCTOR_OPTIONS
const CONSTRUCTOR_OPTIONS
Definition: SpecialPageFactory.php:990
MediaWiki\$context
IContextSource $context
Definition: MediaWiki.php:40
$wgOut
$wgOut
Definition: Setup.php:781
MediaWiki\SpecialPage\SpecialPageFactory\$aliases
array $aliases
Definition: SpecialPageFactory.php:970
MediaWiki\SpecialPage\SpecialPageFactory\getAliasList
getAliasList()
Initialise and return the list of special page aliases.
Definition: SpecialPageFactory.php:1127
MediaWiki\SpecialPage\SpecialPageFactory\getPageList
getPageList()
Get the special page list as an array.
Definition: SpecialPageFactory.php:1035
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:63
MediaWiki\SpecialPage
IContextSource\getOutput
getOutput()
Language
Internationalisation code See https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation for more...
Definition: Language.php:42
IContextSource\getLanguage
getLanguage()
MediaWiki\Config\ServiceOptions\assertRequiredOptions
assertRequiredOptions(array $expectedKeys)
Assert that the list of options provided in this instance exactly match $expectedKeys,...
Definition: ServiceOptions.php:66