MediaWiki  master
SpecialPageFactory.php
Go to the documentation of this file.
1 <?php
26 
27 use Hooks;
35 use Title;
36 use User;
37 
69  private static $coreList = [
70  // Maintenance Reports
71  'BrokenRedirects' => \BrokenRedirectsPage::class,
72  'Deadendpages' => \DeadendPagesPage::class,
73  'DoubleRedirects' => \DoubleRedirectsPage::class,
74  'Longpages' => \LongPagesPage::class,
75  'Ancientpages' => \AncientPagesPage::class,
76  'Lonelypages' => \LonelyPagesPage::class,
77  'Fewestrevisions' => \FewestrevisionsPage::class,
78  'Withoutinterwiki' => \WithoutInterwikiPage::class,
79  'Protectedpages' => \SpecialProtectedpages::class,
80  'Protectedtitles' => \SpecialProtectedtitles::class,
81  'Shortpages' => \ShortPagesPage::class,
82  'Uncategorizedcategories' => \UncategorizedCategoriesPage::class,
83  'Uncategorizedimages' => \UncategorizedImagesPage::class,
84  'Uncategorizedpages' => \UncategorizedPagesPage::class,
85  'Uncategorizedtemplates' => \UncategorizedTemplatesPage::class,
86  'Unusedcategories' => \UnusedCategoriesPage::class,
87  'Unusedimages' => \UnusedimagesPage::class,
88  'Unusedtemplates' => \UnusedtemplatesPage::class,
89  'Unwatchedpages' => \UnwatchedpagesPage::class,
90  'Wantedcategories' => \WantedCategoriesPage::class,
91  'Wantedfiles' => \WantedFilesPage::class,
92  'Wantedpages' => \WantedPagesPage::class,
93  'Wantedtemplates' => \WantedTemplatesPage::class,
94 
95  // List of pages
96  'Allpages' => \SpecialAllPages::class,
97  'Prefixindex' => \SpecialPrefixindex::class,
98  'Categories' => \SpecialCategories::class,
99  'Listredirects' => \ListredirectsPage::class,
100  'PagesWithProp' => \SpecialPagesWithProp::class,
101  'TrackingCategories' => \SpecialTrackingCategories::class,
102 
103  // Authentication
104  'Userlogin' => \SpecialUserLogin::class,
105  'Userlogout' => \SpecialUserLogout::class,
106  'CreateAccount' => \SpecialCreateAccount::class,
107  'LinkAccounts' => \SpecialLinkAccounts::class,
108  'UnlinkAccounts' => \SpecialUnlinkAccounts::class,
109  'ChangeCredentials' => \SpecialChangeCredentials::class,
110  'RemoveCredentials' => \SpecialRemoveCredentials::class,
111 
112  // Users and rights
113  'Activeusers' => \SpecialActiveUsers::class,
114  'Block' => \SpecialBlock::class,
115  'Unblock' => \SpecialUnblock::class,
116  'BlockList' => \SpecialBlockList::class,
117  'AutoblockList' => \SpecialAutoblockList::class,
118  'ChangePassword' => \SpecialChangePassword::class,
119  'BotPasswords' => \SpecialBotPasswords::class,
120  'PasswordReset' => \SpecialPasswordReset::class,
121  'DeletedContributions' => \DeletedContributionsPage::class,
122  'Preferences' => \SpecialPreferences::class,
123  'ResetTokens' => \SpecialResetTokens::class,
124  'Contributions' => \SpecialContributions::class,
125  'Listgrouprights' => \SpecialListGroupRights::class,
126  'Listgrants' => \SpecialListGrants::class,
127  'Listusers' => \SpecialListUsers::class,
128  'Listadmins' => \SpecialListAdmins::class,
129  'Listbots' => \SpecialListBots::class,
130  'Userrights' => \UserrightsPage::class,
131  'EditWatchlist' => \SpecialEditWatchlist::class,
132  'PasswordPolicies' => \SpecialPasswordPolicies::class,
133 
134  // Recent changes and logs
135  'Newimages' => \SpecialNewFiles::class,
136  'Log' => \SpecialLog::class,
137  'Watchlist' => \SpecialWatchlist::class,
138  'Newpages' => \SpecialNewpages::class,
139  'Recentchanges' => \SpecialRecentChanges::class,
140  'Recentchangeslinked' => \SpecialRecentChangesLinked::class,
141  'Tags' => \SpecialTags::class,
142 
143  // Media reports and uploads
144  'Listfiles' => \SpecialListFiles::class,
145  'Filepath' => \SpecialFilepath::class,
146  'MediaStatistics' => \MediaStatisticsPage::class,
147  'MIMEsearch' => \MIMEsearchPage::class,
148  'FileDuplicateSearch' => \FileDuplicateSearchPage::class,
149  'Upload' => \SpecialUpload::class,
150  'UploadStash' => \SpecialUploadStash::class,
151  'ListDuplicatedFiles' => \ListDuplicatedFilesPage::class,
152 
153  // Data and tools
154  'ApiSandbox' => \SpecialApiSandbox::class,
155  'Statistics' => \SpecialStatistics::class,
156  'Allmessages' => \SpecialAllMessages::class,
157  'Version' => \SpecialVersion::class,
158  'Lockdb' => \SpecialLockdb::class,
159  'Unlockdb' => \SpecialUnlockdb::class,
160 
161  // Redirecting special pages
162  'LinkSearch' => \LinkSearchPage::class,
163  'Randompage' => \RandomPage::class,
164  'RandomInCategory' => \SpecialRandomInCategory::class,
165  'Randomredirect' => \SpecialRandomredirect::class,
166  'Randomrootpage' => \SpecialRandomrootpage::class,
167  'GoToInterwiki' => \SpecialGoToInterwiki::class,
168 
169  // High use pages
170  'Mostlinkedcategories' => \MostlinkedCategoriesPage::class,
171  'Mostimages' => \MostimagesPage::class,
172  'Mostinterwikis' => \MostinterwikisPage::class,
173  'Mostlinked' => \MostlinkedPage::class,
174  'Mostlinkedtemplates' => \MostlinkedTemplatesPage::class,
175  'Mostcategories' => \MostcategoriesPage::class,
176  'Mostrevisions' => \MostrevisionsPage::class,
177 
178  // Page tools
179  'ComparePages' => \SpecialComparePages::class,
180  'Export' => \SpecialExport::class,
181  'Import' => \SpecialImport::class,
182  'Undelete' => \SpecialUndelete::class,
183  'Whatlinkshere' => \SpecialWhatLinksHere::class,
184  'MergeHistory' => \SpecialMergeHistory::class,
185  'ExpandTemplates' => \SpecialExpandTemplates::class,
186 
187  // Other
188  'Booksources' => \SpecialBookSources::class,
189 
190  // Unlisted / redirects
191  'ApiHelp' => \SpecialApiHelp::class,
192  'Blankpage' => \SpecialBlankpage::class,
193  'Diff' => \SpecialDiff::class,
194  'EditTags' => \SpecialEditTags::class,
195  'Emailuser' => \SpecialEmailUser::class,
196  'Movepage' => \MovePageForm::class,
197  'Mycontributions' => \SpecialMycontributions::class,
198  'MyLanguage' => \SpecialMyLanguage::class,
199  'Mypage' => \SpecialMypage::class,
200  'Mytalk' => \SpecialMytalk::class,
201  'Myuploads' => \SpecialMyuploads::class,
202  'AllMyUploads' => \SpecialAllMyUploads::class,
203  'PermanentLink' => \SpecialPermanentLink::class,
204  'Redirect' => \SpecialRedirect::class,
205  'Revisiondelete' => \SpecialRevisionDelete::class,
206  'RunJobs' => \SpecialRunJobs::class,
207  'Specialpages' => \SpecialSpecialpages::class,
208  'PageData' => \SpecialPageData::class,
209  ];
210 
212  private $list;
213 
215  private $aliases;
216 
218  private $options;
219 
221  private $contLang;
222 
229  public static $constructorOptions = [
230  'ContentHandlerUseDB',
231  'DisableInternalSearch',
232  'EmailAuthentication',
233  'EnableEmail',
234  'EnableJavaScriptTest',
235  'PageLanguageUseDB',
236  'SpecialPages',
237  ];
238 
244  $options->assertRequiredOptions( self::$constructorOptions );
245  $this->options = $options;
246  $this->contLang = $contLang;
247  }
248 
255  public function getNames() : array {
256  return array_keys( $this->getPageList() );
257  }
258 
264  private function getPageList() : array {
265  if ( !is_array( $this->list ) ) {
266  $this->list = self::$coreList;
267 
268  if ( !$this->options->get( 'DisableInternalSearch' ) ) {
269  $this->list['Search'] = \SpecialSearch::class;
270  }
271 
272  if ( $this->options->get( 'EmailAuthentication' ) ) {
273  $this->list['Confirmemail'] = \EmailConfirmation::class;
274  $this->list['Invalidateemail'] = \EmailInvalidation::class;
275  }
276 
277  if ( $this->options->get( 'EnableEmail' ) ) {
278  $this->list['ChangeEmail'] = \SpecialChangeEmail::class;
279  }
280 
281  if ( $this->options->get( 'EnableJavaScriptTest' ) ) {
282  $this->list['JavaScriptTest'] = \SpecialJavaScriptTest::class;
283  }
284 
285  if ( $this->options->get( 'PageLanguageUseDB' ) ) {
286  $this->list['PageLanguage'] = \SpecialPageLanguage::class;
287  }
288  if ( $this->options->get( 'ContentHandlerUseDB' ) ) {
289  $this->list['ChangeContentModel'] = \SpecialChangeContentModel::class;
290  }
291 
292  // Add extension special pages
293  $this->list = array_merge( $this->list, $this->options->get( 'SpecialPages' ) );
294 
295  // This hook can be used to disable unwanted core special pages
296  // or conditionally register special pages.
297  Hooks::run( 'SpecialPage_initList', [ &$this->list ] );
298 
299  }
300 
301  return $this->list;
302  }
303 
310  private function getAliasList() : array {
311  if ( is_null( $this->aliases ) ) {
312  $aliases = $this->contLang->getSpecialPageAliases();
313  $pageList = $this->getPageList();
314 
315  $this->aliases = [];
316  $keepAlias = [];
317 
318  // Force every canonical name to be an alias for itself.
319  foreach ( $pageList as $name => $stuff ) {
320  $caseFoldedAlias = $this->contLang->caseFold( $name );
321  $this->aliases[$caseFoldedAlias] = $name;
322  $keepAlias[$caseFoldedAlias] = 'canonical';
323  }
324 
325  // Check for $aliases being an array since Language::getSpecialPageAliases can return null
326  if ( is_array( $aliases ) ) {
327  foreach ( $aliases as $realName => $aliasList ) {
328  $aliasList = array_values( $aliasList );
329  foreach ( $aliasList as $i => $alias ) {
330  $caseFoldedAlias = $this->contLang->caseFold( $alias );
331 
332  if ( isset( $this->aliases[$caseFoldedAlias] ) &&
333  $realName === $this->aliases[$caseFoldedAlias]
334  ) {
335  // Ignore same-realName conflicts
336  continue;
337  }
338 
339  if ( !isset( $keepAlias[$caseFoldedAlias] ) ) {
340  $this->aliases[$caseFoldedAlias] = $realName;
341  if ( !$i ) {
342  $keepAlias[$caseFoldedAlias] = 'first';
343  }
344  } elseif ( !$i ) {
345  wfWarn( "First alias '$alias' for $realName conflicts with " .
346  "{$keepAlias[$caseFoldedAlias]} alias for " .
347  $this->aliases[$caseFoldedAlias]
348  );
349  }
350  }
351  }
352  }
353  }
354 
355  return $this->aliases;
356  }
357 
366  public function resolveAlias( $alias ) {
367  $bits = explode( '/', $alias, 2 );
368 
369  $caseFoldedAlias = $this->contLang->caseFold( $bits[0] );
370  $caseFoldedAlias = str_replace( ' ', '_', $caseFoldedAlias );
371  $aliases = $this->getAliasList();
372  if ( !isset( $aliases[$caseFoldedAlias] ) ) {
373  return [ null, null ];
374  }
375  $name = $aliases[$caseFoldedAlias];
376  $par = $bits[1] ?? null; // T4087
377 
378  return [ $name, $par ];
379  }
380 
387  public function exists( $name ) {
388  list( $title, /*...*/ ) = $this->resolveAlias( $name );
389 
390  $specialPageList = $this->getPageList();
391  return isset( $specialPageList[$title] );
392  }
393 
400  public function getPage( $name ) {
401  list( $realName, /*...*/ ) = $this->resolveAlias( $name );
402 
403  $specialPageList = $this->getPageList();
404 
405  if ( isset( $specialPageList[$realName] ) ) {
406  $rec = $specialPageList[$realName];
407 
408  if ( is_callable( $rec ) ) {
409  // Use callback to instantiate the special page
410  $page = $rec();
411  } elseif ( is_string( $rec ) ) {
412  $className = $rec;
413  $page = new $className;
414  } elseif ( $rec instanceof SpecialPage ) {
415  $page = $rec; // XXX: we should deep clone here
416  } else {
417  $page = null;
418  }
419 
420  if ( $page instanceof SpecialPage ) {
421  return $page;
422  }
423 
424  // It's not a classname, nor a callback, nor a legacy constructor array,
425  // nor a special page object. Give up.
426  wfLogWarning( "Cannot instantiate special page $realName: bad spec!" );
427  }
428 
429  return null;
430  }
431 
440  public function getUsablePages( User $user ) : array {
441  $pages = [];
442  foreach ( $this->getPageList() as $name => $rec ) {
443  $page = $this->getPage( $name );
444  if ( $page ) { // not null
445  $page->setContext( RequestContext::getMain() );
446  if ( $page->isListed()
447  && ( !$page->isRestricted() || $page->userCanExecute( $user ) )
448  ) {
449  $pages[$name] = $page;
450  }
451  }
452  }
453 
454  return $pages;
455  }
456 
462  public function getRegularPages() : array {
463  $pages = [];
464  foreach ( $this->getPageList() as $name => $rec ) {
465  $page = $this->getPage( $name );
466  if ( $page && $page->isListed() && !$page->isRestricted() ) {
467  $pages[$name] = $page;
468  }
469  }
470 
471  return $pages;
472  }
473 
481  public function getRestrictedPages( User $user ) : array {
482  $pages = [];
483  foreach ( $this->getPageList() as $name => $rec ) {
484  $page = $this->getPage( $name );
485  if ( $page
486  && $page->isListed()
487  && $page->isRestricted()
488  && $page->userCanExecute( $user )
489  ) {
490  $pages[$name] = $page;
491  }
492  }
493 
494  return $pages;
495  }
496 
512  public function executePath( Title &$title, IContextSource &$context, $including = false,
514  ) {
515  // @todo FIXME: Redirects broken due to this call
516  $bits = explode( '/', $title->getDBkey(), 2 );
517  $name = $bits[0];
518  $par = $bits[1] ?? null; // T4087
519 
520  $page = $this->getPage( $name );
521  if ( !$page ) {
522  $context->getOutput()->setArticleRelated( false );
523  $context->getOutput()->setRobotPolicy( 'noindex,nofollow' );
524 
525  global $wgSend404Code;
526  if ( $wgSend404Code ) {
527  $context->getOutput()->setStatusCode( 404 );
528  }
529 
530  $context->getOutput()->showErrorPage( 'nosuchspecialpage', 'nospecialpagetext' );
531 
532  return false;
533  }
534 
535  if ( !$including ) {
536  // Narrow DB query expectations for this HTTP request
537  $trxLimits = $context->getConfig()->get( 'TrxProfilerLimits' );
538  $trxProfiler = Profiler::instance()->getTransactionProfiler();
539  if ( $context->getRequest()->wasPosted() && !$page->doesWrites() ) {
540  $trxProfiler->setExpectations( $trxLimits['POST-nonwrite'], __METHOD__ );
541  $context->getRequest()->markAsSafeRequest();
542  }
543  }
544 
545  // Page exists, set the context
546  $page->setContext( $context );
547 
548  if ( !$including ) {
549  // Redirect to canonical alias for GET commands
550  // Not for POST, we'd lose the post data, so it's best to just distribute
551  // the request. Such POST requests are possible for old extensions that
552  // generate self-links without being aware that their default name has
553  // changed.
554  if ( $name != $page->getLocalName() && !$context->getRequest()->wasPosted() ) {
555  $query = $context->getRequest()->getQueryValues();
556  unset( $query['title'] );
557  $title = $page->getPageTitle( $par );
558  $url = $title->getFullURL( $query );
559  $context->getOutput()->redirect( $url );
560 
561  return $title;
562  }
563 
564  $context->setTitle( $page->getPageTitle( $par ) );
565  } elseif ( !$page->isIncludable() ) {
566  return false;
567  }
568 
569  $page->including( $including );
570  if ( $linkRenderer ) {
571  $page->setLinkRenderer( $linkRenderer );
572  }
573 
574  // Execute special page
575  $page->run( $par );
576 
577  return true;
578  }
579 
595  public function capturePath(
597  ) {
598  global $wgTitle, $wgOut, $wgRequest, $wgUser, $wgLang;
599  $main = RequestContext::getMain();
600 
601  // Save current globals and main context
602  $glob = [
603  'title' => $wgTitle,
604  'output' => $wgOut,
605  'request' => $wgRequest,
606  'user' => $wgUser,
607  'language' => $wgLang,
608  ];
609  $ctx = [
610  'title' => $main->getTitle(),
611  'output' => $main->getOutput(),
612  'request' => $main->getRequest(),
613  'user' => $main->getUser(),
614  'language' => $main->getLanguage(),
615  ];
616  if ( $main->canUseWikiPage() ) {
617  $ctx['wikipage'] = $main->getWikiPage();
618  }
619 
620  // Override
621  $wgTitle = $title;
622  $wgOut = $context->getOutput();
623  $wgRequest = $context->getRequest();
624  $wgUser = $context->getUser();
625  $wgLang = $context->getLanguage();
626  $main->setTitle( $title );
627  $main->setOutput( $context->getOutput() );
628  $main->setRequest( $context->getRequest() );
629  $main->setUser( $context->getUser() );
630  $main->setLanguage( $context->getLanguage() );
631 
632  // The useful part
633  $ret = $this->executePath( $title, $context, true, $linkRenderer );
634 
635  // Restore old globals and context
636  $wgTitle = $glob['title'];
637  $wgOut = $glob['output'];
638  $wgRequest = $glob['request'];
639  $wgUser = $glob['user'];
640  $wgLang = $glob['language'];
641  $main->setTitle( $ctx['title'] );
642  $main->setOutput( $ctx['output'] );
643  $main->setRequest( $ctx['request'] );
644  $main->setUser( $ctx['user'] );
645  $main->setLanguage( $ctx['language'] );
646  if ( isset( $ctx['wikipage'] ) ) {
647  $main->setWikiPage( $ctx['wikipage'] );
648  }
649 
650  return $ret;
651  }
652 
660  public function getLocalNameFor( $name, $subpage = false ) {
661  $aliases = $this->contLang->getSpecialPageAliases();
662  $aliasList = $this->getAliasList();
663 
664  // Find the first alias that maps back to $name
665  if ( isset( $aliases[$name] ) ) {
666  $found = false;
667  foreach ( $aliases[$name] as $alias ) {
668  $caseFoldedAlias = $this->contLang->caseFold( $alias );
669  $caseFoldedAlias = str_replace( ' ', '_', $caseFoldedAlias );
670  if ( isset( $aliasList[$caseFoldedAlias] ) &&
671  $aliasList[$caseFoldedAlias] === $name
672  ) {
673  $name = $alias;
674  $found = true;
675  break;
676  }
677  }
678  if ( !$found ) {
679  wfWarn( "Did not find a usable alias for special page '$name'. " .
680  "It seems all defined aliases conflict?" );
681  }
682  } else {
683  // Check if someone misspelled the correct casing
684  if ( is_array( $aliases ) ) {
685  foreach ( $aliases as $n => $values ) {
686  if ( strcasecmp( $name, $n ) === 0 ) {
687  wfWarn( "Found alias defined for $n when searching for " .
688  "special page aliases for $name. Case mismatch?" );
689  return $this->getLocalNameFor( $n, $subpage );
690  }
691  }
692  }
693 
694  wfWarn( "Did not find alias for special page '$name'. " .
695  "Perhaps no aliases are defined for it?" );
696  }
697 
698  if ( $subpage !== false && !is_null( $subpage ) ) {
699  // Make sure it's in dbkey form
700  $subpage = str_replace( ' ', '_', $subpage );
701  $name = "$name/$subpage";
702  }
703 
704  return $this->contLang->ucfirst( $name );
705  }
706 
713  public function getTitleForAlias( $alias ) {
714  list( $name, $subpage ) = $this->resolveAlias( $alias );
715  if ( $name != null ) {
716  return SpecialPage::getTitleFor( $name, $subpage );
717  }
718 
719  return null;
720  }
721 }
getRestrictedPages(User $user)
Return categorised listable special pages which are available for the current user, but not for everyone.
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
wfWarn( $msg, $callerOffset=1, $level=E_USER_NOTICE)
Send a warning either to the debug log or in a PHP error depending on $wgDevelopmentWarnings.
null for the local wiki Added should default to null in handler for backwards compatibility add a value to it if you want to add a cookie that have to vary cache options can modify $query
Definition: hooks.txt:1585
capturePath(Title $title, IContextSource $context, LinkRenderer $linkRenderer=null)
Just like executePath() but will override global variables and execute the page in "inclusion" mode...
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Definition: hooks.txt:1982
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses after processing after in associative array form before processing starts Return false to skip default processing and return $ret $linkRenderer
Definition: hooks.txt:1982
static instance()
Singleton.
Definition: Profiler.php:62
executePath(Title &$title, IContextSource &$context, $including=false, LinkRenderer $linkRenderer=null)
Execute a special page path.
wfLogWarning( $msg, $callerOffset=1, $level=E_USER_WARNING)
Send a warning as a PHP error and the debug log.
getUsablePages(User $user)
Return categorised listable special pages which are available for the current user, and everyone.
A class for passing options to services.
exists( $name)
Check if a given name exist as a special page or as a special page alias.
The User object encapsulates all of the user-specific settings (user_id, name, rights, email address, options, last login time).
Definition: User.php:51
getConfig()
Get the site configuration.
$wgLang
Definition: Setup.php:931
Class that generates HTML links for pages.
Factory for handling the special page list and generating SpecialPage objects.
static getMain()
Get the RequestContext object associated with the main request.
IContextSource $context
Definition: MediaWiki.php:38
getDBkey()
Get the main part with underscores.
Definition: Title.php:1002
getPageList()
Get the special page list as an array.
getLocalNameFor( $name, $subpage=false)
Get the local name for a specified canonical name.
getNames()
Returns a list of canonical special page names.
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that When $user is not null
Definition: hooks.txt:780
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:925
getFullURL( $query='', $query2=false, $proto=PROTO_RELATIVE)
Get a real URL referring to this title, with interwiki link and fragment.
Definition: Title.php:1924
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don&#39;t need a full Title object...
Definition: SpecialPage.php:83
getRegularPages()
Return categorised listable special pages for all users.
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
static array $list
Special page name => class name.
assertRequiredOptions(array $expectedKeys)
Assert that the list of options provided in this instance exactly match $expectedKeys, without regard for order.
__construct(ServiceOptions $options, Language $contLang)
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:35
static $coreList
List of special page names to the subclass of SpecialPage which handles them.
Using a hook running we can avoid having all this option specific stuff in our mainline code Using the function We ve cleaned up the code here by removing clumps of infrequently used code and moving them off somewhere else It s much easier for someone working with this code to see what s _really_ going and make changes or fix bugs In we can take all the code that deals with the little used title reversing options(say) and put it in one place. Instead of having little title-reversing if-blocks spread all over the codebase in showAnArticle
getTitleForAlias( $alias)
Get a title for a given alias.
you have access to all of the normal MediaWiki so you can get a DB use the etc For full docs on the Maintenance class
Definition: maintenance.txt:52
resolveAlias( $alias)
Given a special page name with a possible subpage, return an array where the first element is the spe...
getPage( $name)
Find the object with a given name and return it (or NULL)
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:271
if(! $wgDBerrorLogTZ) $wgRequest
Definition: Setup.php:783
$wgOut
Definition: Setup.php:936
if(! $wgRequest->checkUrlExtension()) if(isset( $_SERVER['PATH_INFO']) && $_SERVER['PATH_INFO'] !='') $wgTitle
Definition: api.php:57
getAliasList()
Initialise and return the list of special page aliases.
$wgSend404Code
Some web hosts attempt to rewrite all responses with a 404 (not found) status code, mangling or hiding MediaWiki&#39;s output.
static array $constructorOptions
TODO Make this a const when HHVM support is dropped (T192166)
return true to allow those checks to and false if checking is done & $user
Definition: hooks.txt:1473
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:200