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