From: Aryeh Gregor Date: Tue, 7 Aug 2018 10:58:31 +0000 (+0300) Subject: Make SpecialPageFactory a service X-Git-Tag: 1.34.0-rc.0~4396^2 X-Git-Url: http://git.cyclocoop.org/?a=commitdiff_plain;h=d4045035b07f27f20dc441960803a0df4ea60baa;p=lhc%2Fweb%2Fwiklou.git Make SpecialPageFactory a service Calling SpecialPageFactory methods statically is now soft-deprecated. SpecialPageFactory::resetList() is a no-op, and I changed tests in core to use overrideMwServices() instead. Methods that fell back to $wgUser now require a User object being passed. Depends-On: Ie1f80315871085b9fd4763a265b588849d94414d Change-Id: Id8a92d57743f790b7d8c377c033cef38d1bb24de --- diff --git a/RELEASE-NOTES-1.32 b/RELEASE-NOTES-1.32 index 990cc1f95c..44f4558cd9 100644 --- a/RELEASE-NOTES-1.32 +++ b/RELEASE-NOTES-1.32 @@ -246,6 +246,8 @@ because of Phabricator reports. resetServiceForTesting( 'MagicWordFactory' ) on a MediaWikiServices. * mw.util.init() has been removed. This function is not needed anymore and was a no-op function since 1.30. +* SpecialPageFactory::resetList() is a no-op. Call overrideMwServices() + instead. === Deprecations in 1.32 === * Use of a StartProfiler.php file is deprecated in favour of placing @@ -351,6 +353,9 @@ because of Phabricator reports. * wfGetMainCache() is deprecated, use ObjectCache::getLocalClusterInstance() instead. * wfGetCache() is deprecated, use ObjectCache::getInstance() instead. +* All SpecialPageFactory static methods are deprecated. Instead, call the + methods on a SpecialPageFactory instance, which may be obtained from + MediaWikiServices. === Other changes in 1.32 === * (T198811) The following tables have had their UNIQUE indexes turned into diff --git a/autoload.php b/autoload.php index 1c1eeeff22..999d82dba9 100644 --- a/autoload.php +++ b/autoload.php @@ -930,6 +930,7 @@ $wgAutoloadLocalClasses = [ 'MediaWiki\\Search\\ParserOutputSearchDataExtractor' => __DIR__ . '/includes/search/ParserOutputSearchDataExtractor.php', 'MediaWiki\\ShellDisabledError' => __DIR__ . '/includes/exception/ShellDisabledError.php', 'MediaWiki\\Site\\MediaWikiPageNameNormalizer' => __DIR__ . '/includes/site/MediaWikiPageNameNormalizer.php', + 'MediaWiki\\Special\\SpecialPageFactory' => __DIR__ . '/includes/specialpage/SpecialPageFactory.php', 'MediaWiki\\User\\UserIdentity' => __DIR__ . '/includes/user/UserIdentity.php', 'MediaWiki\\User\\UserIdentityValue' => __DIR__ . '/includes/user/UserIdentityValue.php', 'MediaWiki\\Widget\\ComplexNamespaceInputWidget' => __DIR__ . '/includes/widget/ComplexNamespaceInputWidget.php', @@ -1392,7 +1393,7 @@ $wgAutoloadLocalClasses = [ 'SpecialPage' => __DIR__ . '/includes/specialpage/SpecialPage.php', 'SpecialPageAction' => __DIR__ . '/includes/actions/SpecialPageAction.php', 'SpecialPageData' => __DIR__ . '/includes/specials/SpecialPageData.php', - 'SpecialPageFactory' => __DIR__ . '/includes/specialpage/SpecialPageFactory.php', + 'SpecialPageFactory' => __DIR__ . '/includes/specialpage/SpecialPageFactory_deprecated.php', 'SpecialPageLanguage' => __DIR__ . '/includes/specials/SpecialPageLanguage.php', 'SpecialPagesWithProp' => __DIR__ . '/includes/specials/SpecialPagesWithProp.php', 'SpecialPasswordPolicies' => __DIR__ . '/includes/specials/SpecialPasswordPolicies.php', diff --git a/includes/MediaWikiServices.php b/includes/MediaWikiServices.php index 326c12ce0a..f9d9aab32e 100644 --- a/includes/MediaWikiServices.php +++ b/includes/MediaWikiServices.php @@ -15,6 +15,7 @@ use IBufferingStatsdDataFactory; use MediaWiki\Http\HttpRequestFactory; use MediaWiki\Preferences\PreferencesFactory; use MediaWiki\Shell\CommandFactory; +use MediaWiki\Special\SpecialPageFactory; use MediaWiki\Storage\BlobStore; use MediaWiki\Storage\BlobStoreFactory; use MediaWiki\Storage\NameTableStore; @@ -828,6 +829,14 @@ class MediaWikiServices extends ServiceContainer { return $this->getService( 'SlotRoleStore' ); } + /** + * @since 1.32 + * @return SpecialPageFactory + */ + public function getSpecialPageFactory() : SpecialPageFactory { + return $this->getService( 'SpecialPageFactory' ); + } + /** * @since 1.27 * @return IBufferingStatsdDataFactory diff --git a/includes/ServiceWiring.php b/includes/ServiceWiring.php index e5ebe2dc98..c6bbb602a7 100644 --- a/includes/ServiceWiring.php +++ b/includes/ServiceWiring.php @@ -48,6 +48,7 @@ use MediaWiki\MediaWikiServices; use MediaWiki\Preferences\PreferencesFactory; use MediaWiki\Preferences\DefaultPreferencesFactory; use MediaWiki\Shell\CommandFactory; +use MediaWiki\Special\SpecialPageFactory; use MediaWiki\Storage\BlobStore; use MediaWiki\Storage\BlobStoreFactory; use MediaWiki\Storage\NameTableStore; @@ -545,6 +546,13 @@ return [ ); }, + 'SpecialPageFactory' => function ( MediaWikiServices $services ) : SpecialPageFactory { + return new SpecialPageFactory( + $services->getMainConfig(), + $services->getContentLanguage() + ); + }, + 'StatsdDataFactory' => function ( MediaWikiServices $services ) : IBufferingStatsdDataFactory { return new BufferingStatsdDataFactory( rtrim( $services->getMainConfig()->get( 'StatsdMetricPrefix' ), '.' ) diff --git a/includes/specialpage/SpecialPageFactory.php b/includes/specialpage/SpecialPageFactory.php index 964581143d..c6ffbe4d70 100644 --- a/includes/specialpage/SpecialPageFactory.php +++ b/includes/specialpage/SpecialPageFactory.php @@ -21,8 +21,19 @@ * @ingroup SpecialPage * @defgroup SpecialPage SpecialPage */ + +namespace MediaWiki\Special; + +use Config; +use Hooks; +use IContextSource; +use Language; use MediaWiki\Linker\LinkRenderer; -use MediaWiki\MediaWikiServices; +use Profiler; +use RequestContext; +use SpecialPage; +use Title; +use User; use Wikimedia\ObjectFactory; /** @@ -43,165 +54,180 @@ use Wikimedia\ObjectFactory; * SpecialPageFactory::$list. To remove a core static special page at runtime, use * a SpecialPage_initList hook. * + * @note There are two classes called SpecialPageFactory. You should use this first one, in + * namespace MediaWiki\Special, which is a service. \SpecialPageFactory is a deprecated collection + * of static methods that forwards to the global service. + * * @ingroup SpecialPage * @since 1.17 */ class SpecialPageFactory { /** * List of special page names to the subclass of SpecialPage which handles them. + * @todo Make this a const when we drop HHVM support (T192166). It can still be private in PHP + * 7.1. */ private static $coreList = [ // Maintenance Reports - 'BrokenRedirects' => BrokenRedirectsPage::class, - 'Deadendpages' => DeadendPagesPage::class, - 'DoubleRedirects' => DoubleRedirectsPage::class, - 'Longpages' => LongPagesPage::class, - 'Ancientpages' => AncientPagesPage::class, - 'Lonelypages' => LonelyPagesPage::class, - 'Fewestrevisions' => FewestrevisionsPage::class, - 'Withoutinterwiki' => WithoutInterwikiPage::class, - 'Protectedpages' => SpecialProtectedpages::class, - 'Protectedtitles' => SpecialProtectedtitles::class, - 'Shortpages' => ShortPagesPage::class, - 'Uncategorizedcategories' => UncategorizedCategoriesPage::class, - 'Uncategorizedimages' => UncategorizedImagesPage::class, - 'Uncategorizedpages' => UncategorizedPagesPage::class, - 'Uncategorizedtemplates' => UncategorizedTemplatesPage::class, - 'Unusedcategories' => UnusedCategoriesPage::class, - 'Unusedimages' => UnusedimagesPage::class, - 'Unusedtemplates' => UnusedtemplatesPage::class, - 'Unwatchedpages' => UnwatchedpagesPage::class, - 'Wantedcategories' => WantedCategoriesPage::class, - 'Wantedfiles' => WantedFilesPage::class, - 'Wantedpages' => WantedPagesPage::class, - 'Wantedtemplates' => WantedTemplatesPage::class, + 'BrokenRedirects' => \BrokenRedirectsPage::class, + 'Deadendpages' => \DeadendPagesPage::class, + 'DoubleRedirects' => \DoubleRedirectsPage::class, + 'Longpages' => \LongPagesPage::class, + 'Ancientpages' => \AncientPagesPage::class, + 'Lonelypages' => \LonelyPagesPage::class, + 'Fewestrevisions' => \FewestrevisionsPage::class, + 'Withoutinterwiki' => \WithoutInterwikiPage::class, + 'Protectedpages' => \SpecialProtectedpages::class, + 'Protectedtitles' => \SpecialProtectedtitles::class, + 'Shortpages' => \ShortPagesPage::class, + 'Uncategorizedcategories' => \UncategorizedCategoriesPage::class, + 'Uncategorizedimages' => \UncategorizedImagesPage::class, + 'Uncategorizedpages' => \UncategorizedPagesPage::class, + 'Uncategorizedtemplates' => \UncategorizedTemplatesPage::class, + 'Unusedcategories' => \UnusedCategoriesPage::class, + 'Unusedimages' => \UnusedimagesPage::class, + 'Unusedtemplates' => \UnusedtemplatesPage::class, + 'Unwatchedpages' => \UnwatchedpagesPage::class, + 'Wantedcategories' => \WantedCategoriesPage::class, + 'Wantedfiles' => \WantedFilesPage::class, + 'Wantedpages' => \WantedPagesPage::class, + 'Wantedtemplates' => \WantedTemplatesPage::class, // List of pages - 'Allpages' => SpecialAllPages::class, - 'Prefixindex' => SpecialPrefixindex::class, - 'Categories' => SpecialCategories::class, - 'Listredirects' => ListredirectsPage::class, - 'PagesWithProp' => SpecialPagesWithProp::class, - 'TrackingCategories' => SpecialTrackingCategories::class, + 'Allpages' => \SpecialAllPages::class, + 'Prefixindex' => \SpecialPrefixindex::class, + 'Categories' => \SpecialCategories::class, + 'Listredirects' => \ListredirectsPage::class, + 'PagesWithProp' => \SpecialPagesWithProp::class, + 'TrackingCategories' => \SpecialTrackingCategories::class, // Authentication - 'Userlogin' => SpecialUserLogin::class, - 'Userlogout' => SpecialUserLogout::class, - 'CreateAccount' => SpecialCreateAccount::class, - 'LinkAccounts' => SpecialLinkAccounts::class, - 'UnlinkAccounts' => SpecialUnlinkAccounts::class, - 'ChangeCredentials' => SpecialChangeCredentials::class, - 'RemoveCredentials' => SpecialRemoveCredentials::class, + 'Userlogin' => \SpecialUserLogin::class, + 'Userlogout' => \SpecialUserLogout::class, + 'CreateAccount' => \SpecialCreateAccount::class, + 'LinkAccounts' => \SpecialLinkAccounts::class, + 'UnlinkAccounts' => \SpecialUnlinkAccounts::class, + 'ChangeCredentials' => \SpecialChangeCredentials::class, + 'RemoveCredentials' => \SpecialRemoveCredentials::class, // Users and rights - 'Activeusers' => SpecialActiveUsers::class, - 'Block' => SpecialBlock::class, - 'Unblock' => SpecialUnblock::class, - 'BlockList' => SpecialBlockList::class, - 'AutoblockList' => SpecialAutoblockList::class, - 'ChangePassword' => SpecialChangePassword::class, - 'BotPasswords' => SpecialBotPasswords::class, - 'PasswordReset' => SpecialPasswordReset::class, - 'DeletedContributions' => DeletedContributionsPage::class, - 'Preferences' => SpecialPreferences::class, - 'ResetTokens' => SpecialResetTokens::class, - 'Contributions' => SpecialContributions::class, - 'Listgrouprights' => SpecialListGroupRights::class, - 'Listgrants' => SpecialListGrants::class, - 'Listusers' => SpecialListUsers::class, - 'Listadmins' => SpecialListAdmins::class, - 'Listbots' => SpecialListBots::class, - 'Userrights' => UserrightsPage::class, - 'EditWatchlist' => SpecialEditWatchlist::class, - 'PasswordPolicies' => SpecialPasswordPolicies::class, + 'Activeusers' => \SpecialActiveUsers::class, + 'Block' => \SpecialBlock::class, + 'Unblock' => \SpecialUnblock::class, + 'BlockList' => \SpecialBlockList::class, + 'AutoblockList' => \SpecialAutoblockList::class, + 'ChangePassword' => \SpecialChangePassword::class, + 'BotPasswords' => \SpecialBotPasswords::class, + 'PasswordReset' => \SpecialPasswordReset::class, + 'DeletedContributions' => \DeletedContributionsPage::class, + 'Preferences' => \SpecialPreferences::class, + 'ResetTokens' => \SpecialResetTokens::class, + 'Contributions' => \SpecialContributions::class, + 'Listgrouprights' => \SpecialListGroupRights::class, + 'Listgrants' => \SpecialListGrants::class, + 'Listusers' => \SpecialListUsers::class, + 'Listadmins' => \SpecialListAdmins::class, + 'Listbots' => \SpecialListBots::class, + 'Userrights' => \UserrightsPage::class, + 'EditWatchlist' => \SpecialEditWatchlist::class, + 'PasswordPolicies' => \SpecialPasswordPolicies::class, // Recent changes and logs - 'Newimages' => SpecialNewFiles::class, - 'Log' => SpecialLog::class, - 'Watchlist' => SpecialWatchlist::class, - 'Newpages' => SpecialNewpages::class, - 'Recentchanges' => SpecialRecentChanges::class, - 'Recentchangeslinked' => SpecialRecentChangesLinked::class, - 'Tags' => SpecialTags::class, + 'Newimages' => \SpecialNewFiles::class, + 'Log' => \SpecialLog::class, + 'Watchlist' => \SpecialWatchlist::class, + 'Newpages' => \SpecialNewpages::class, + 'Recentchanges' => \SpecialRecentChanges::class, + 'Recentchangeslinked' => \SpecialRecentChangesLinked::class, + 'Tags' => \SpecialTags::class, // Media reports and uploads - 'Listfiles' => SpecialListFiles::class, - 'Filepath' => SpecialFilepath::class, - 'MediaStatistics' => MediaStatisticsPage::class, - 'MIMEsearch' => MIMEsearchPage::class, - 'FileDuplicateSearch' => FileDuplicateSearchPage::class, - 'Upload' => SpecialUpload::class, - 'UploadStash' => SpecialUploadStash::class, - 'ListDuplicatedFiles' => ListDuplicatedFilesPage::class, + 'Listfiles' => \SpecialListFiles::class, + 'Filepath' => \SpecialFilepath::class, + 'MediaStatistics' => \MediaStatisticsPage::class, + 'MIMEsearch' => \MIMEsearchPage::class, + 'FileDuplicateSearch' => \FileDuplicateSearchPage::class, + 'Upload' => \SpecialUpload::class, + 'UploadStash' => \SpecialUploadStash::class, + 'ListDuplicatedFiles' => \ListDuplicatedFilesPage::class, // Data and tools - 'ApiSandbox' => SpecialApiSandbox::class, - 'Statistics' => SpecialStatistics::class, - 'Allmessages' => SpecialAllMessages::class, - 'Version' => SpecialVersion::class, - 'Lockdb' => SpecialLockdb::class, - 'Unlockdb' => SpecialUnlockdb::class, + 'ApiSandbox' => \SpecialApiSandbox::class, + 'Statistics' => \SpecialStatistics::class, + 'Allmessages' => \SpecialAllMessages::class, + 'Version' => \SpecialVersion::class, + 'Lockdb' => \SpecialLockdb::class, + 'Unlockdb' => \SpecialUnlockdb::class, // Redirecting special pages - 'LinkSearch' => LinkSearchPage::class, - 'Randompage' => RandomPage::class, - 'RandomInCategory' => SpecialRandomInCategory::class, - 'Randomredirect' => SpecialRandomredirect::class, - 'Randomrootpage' => SpecialRandomrootpage::class, - 'GoToInterwiki' => SpecialGoToInterwiki::class, + 'LinkSearch' => \LinkSearchPage::class, + 'Randompage' => \RandomPage::class, + 'RandomInCategory' => \SpecialRandomInCategory::class, + 'Randomredirect' => \SpecialRandomredirect::class, + 'Randomrootpage' => \SpecialRandomrootpage::class, + 'GoToInterwiki' => \SpecialGoToInterwiki::class, // High use pages - 'Mostlinkedcategories' => MostlinkedCategoriesPage::class, - 'Mostimages' => MostimagesPage::class, - 'Mostinterwikis' => MostinterwikisPage::class, - 'Mostlinked' => MostlinkedPage::class, - 'Mostlinkedtemplates' => MostlinkedTemplatesPage::class, - 'Mostcategories' => MostcategoriesPage::class, - 'Mostrevisions' => MostrevisionsPage::class, + 'Mostlinkedcategories' => \MostlinkedCategoriesPage::class, + 'Mostimages' => \MostimagesPage::class, + 'Mostinterwikis' => \MostinterwikisPage::class, + 'Mostlinked' => \MostlinkedPage::class, + 'Mostlinkedtemplates' => \MostlinkedTemplatesPage::class, + 'Mostcategories' => \MostcategoriesPage::class, + 'Mostrevisions' => \MostrevisionsPage::class, // Page tools - 'ComparePages' => SpecialComparePages::class, - 'Export' => SpecialExport::class, - 'Import' => SpecialImport::class, - 'Undelete' => SpecialUndelete::class, - 'Whatlinkshere' => SpecialWhatLinksHere::class, - 'MergeHistory' => SpecialMergeHistory::class, - 'ExpandTemplates' => SpecialExpandTemplates::class, + 'ComparePages' => \SpecialComparePages::class, + 'Export' => \SpecialExport::class, + 'Import' => \SpecialImport::class, + 'Undelete' => \SpecialUndelete::class, + 'Whatlinkshere' => \SpecialWhatLinksHere::class, + 'MergeHistory' => \SpecialMergeHistory::class, + 'ExpandTemplates' => \SpecialExpandTemplates::class, // Other - 'Booksources' => SpecialBookSources::class, + 'Booksources' => \SpecialBookSources::class, // Unlisted / redirects - 'ApiHelp' => SpecialApiHelp::class, - 'Blankpage' => SpecialBlankpage::class, - 'Diff' => SpecialDiff::class, - 'EditTags' => SpecialEditTags::class, - 'Emailuser' => SpecialEmailUser::class, - 'Movepage' => MovePageForm::class, - 'Mycontributions' => SpecialMycontributions::class, - 'MyLanguage' => SpecialMyLanguage::class, - 'Mypage' => SpecialMypage::class, - 'Mytalk' => SpecialMytalk::class, - 'Myuploads' => SpecialMyuploads::class, - 'AllMyUploads' => SpecialAllMyUploads::class, - 'PermanentLink' => SpecialPermanentLink::class, - 'Redirect' => SpecialRedirect::class, - 'Revisiondelete' => SpecialRevisionDelete::class, - 'RunJobs' => SpecialRunJobs::class, - 'Specialpages' => SpecialSpecialpages::class, - 'PageData' => SpecialPageData::class, + 'ApiHelp' => \SpecialApiHelp::class, + 'Blankpage' => \SpecialBlankpage::class, + 'Diff' => \SpecialDiff::class, + 'EditTags' => \SpecialEditTags::class, + 'Emailuser' => \SpecialEmailUser::class, + 'Movepage' => \MovePageForm::class, + 'Mycontributions' => \SpecialMycontributions::class, + 'MyLanguage' => \SpecialMyLanguage::class, + 'Mypage' => \SpecialMypage::class, + 'Mytalk' => \SpecialMytalk::class, + 'Myuploads' => \SpecialMyuploads::class, + 'AllMyUploads' => \SpecialAllMyUploads::class, + 'PermanentLink' => \SpecialPermanentLink::class, + 'Redirect' => \SpecialRedirect::class, + 'Revisiondelete' => \SpecialRevisionDelete::class, + 'RunJobs' => \SpecialRunJobs::class, + 'Specialpages' => \SpecialSpecialpages::class, + 'PageData' => \SpecialPageData::class, ]; - private static $list; - private static $aliases; + /** @var array Special page name => class name */ + private $list; + + /** @var array */ + private $aliases; + + /** @var Config */ + private $config; + + /** @var Language */ + private $contLang; /** - * Reset the internal list of special pages. Useful when changing $wgSpecialPages after - * the internal list has already been initialized, e.g. during testing. + * @param Config $config + * @param Language $contLang */ - public static function resetList() { - self::$list = null; - self::$aliases = null; + public function __construct( Config $config, Language $contLang ) { + $this->config = $config; + $this->contLang = $contLang; } /** @@ -210,8 +236,8 @@ class SpecialPageFactory { * * @return string[] */ - public static function getNames() { - return array_keys( self::getPageList() ); + public function getNames() : array { + return array_keys( $this->getPageList() ); } /** @@ -219,49 +245,44 @@ class SpecialPageFactory { * * @return array */ - private static function getPageList() { - global $wgSpecialPages; - global $wgDisableInternalSearch, $wgEmailAuthentication; - global $wgEnableEmail, $wgEnableJavaScriptTest; - global $wgPageLanguageUseDB, $wgContentHandlerUseDB; - - if ( !is_array( self::$list ) ) { - self::$list = self::$coreList; + private function getPageList() : array { + if ( !is_array( $this->list ) ) { + $this->list = self::$coreList; - if ( !$wgDisableInternalSearch ) { - self::$list['Search'] = SpecialSearch::class; + if ( !$this->config->get( 'DisableInternalSearch' ) ) { + $this->list['Search'] = \SpecialSearch::class; } - if ( $wgEmailAuthentication ) { - self::$list['Confirmemail'] = EmailConfirmation::class; - self::$list['Invalidateemail'] = EmailInvalidation::class; + if ( $this->config->get( 'EmailAuthentication' ) ) { + $this->list['Confirmemail'] = \EmailConfirmation::class; + $this->list['Invalidateemail'] = \EmailInvalidation::class; } - if ( $wgEnableEmail ) { - self::$list['ChangeEmail'] = SpecialChangeEmail::class; + if ( $this->config->get( 'EnableEmail' ) ) { + $this->list['ChangeEmail'] = \SpecialChangeEmail::class; } - if ( $wgEnableJavaScriptTest ) { - self::$list['JavaScriptTest'] = SpecialJavaScriptTest::class; + if ( $this->config->get( 'EnableJavaScriptTest' ) ) { + $this->list['JavaScriptTest'] = \SpecialJavaScriptTest::class; } - if ( $wgPageLanguageUseDB ) { - self::$list['PageLanguage'] = SpecialPageLanguage::class; + if ( $this->config->get( 'PageLanguageUseDB' ) ) { + $this->list['PageLanguage'] = \SpecialPageLanguage::class; } - if ( $wgContentHandlerUseDB ) { - self::$list['ChangeContentModel'] = SpecialChangeContentModel::class; + if ( $this->config->get( 'ContentHandlerUseDB' ) ) { + $this->list['ChangeContentModel'] = \SpecialChangeContentModel::class; } // Add extension special pages - self::$list = array_merge( self::$list, $wgSpecialPages ); + $this->list = array_merge( $this->list, $this->config->get( 'SpecialPages' ) ); // This hook can be used to disable unwanted core special pages // or conditionally register special pages. - Hooks::run( 'SpecialPage_initList', [ &self::$list ] ); + Hooks::run( 'SpecialPage_initList', [ &$this->list ] ); } - return self::$list; + return $this->list; } /** @@ -270,19 +291,18 @@ class SpecialPageFactory { * All registered special pages are guaranteed to map to themselves. * @return array */ - private static function getAliasList() { - $contLang = MediaWikiServices::getInstance()->getContentLanguage(); - if ( is_null( self::$aliases ) ) { - $aliases = $contLang->getSpecialPageAliases(); - $pageList = self::getPageList(); + private function getAliasList() : array { + if ( is_null( $this->aliases ) ) { + $aliases = $this->contLang->getSpecialPageAliases(); + $pageList = $this->getPageList(); - self::$aliases = []; + $this->aliases = []; $keepAlias = []; // Force every canonical name to be an alias for itself. foreach ( $pageList as $name => $stuff ) { - $caseFoldedAlias = $contLang->caseFold( $name ); - self::$aliases[$caseFoldedAlias] = $name; + $caseFoldedAlias = $this->contLang->caseFold( $name ); + $this->aliases[$caseFoldedAlias] = $name; $keepAlias[$caseFoldedAlias] = 'canonical'; } @@ -291,24 +311,24 @@ class SpecialPageFactory { foreach ( $aliases as $realName => $aliasList ) { $aliasList = array_values( $aliasList ); foreach ( $aliasList as $i => $alias ) { - $caseFoldedAlias = $contLang->caseFold( $alias ); + $caseFoldedAlias = $this->contLang->caseFold( $alias ); - if ( isset( self::$aliases[$caseFoldedAlias] ) && - $realName === self::$aliases[$caseFoldedAlias] + if ( isset( $this->aliases[$caseFoldedAlias] ) && + $realName === $this->aliases[$caseFoldedAlias] ) { // Ignore same-realName conflicts continue; } if ( !isset( $keepAlias[$caseFoldedAlias] ) ) { - self::$aliases[$caseFoldedAlias] = $realName; + $this->aliases[$caseFoldedAlias] = $realName; if ( !$i ) { $keepAlias[$caseFoldedAlias] = 'first'; } } elseif ( !$i ) { wfWarn( "First alias '$alias' for $realName conflicts with " . "{$keepAlias[$caseFoldedAlias]} alias for " . - self::$aliases[$caseFoldedAlias] + $this->aliases[$caseFoldedAlias] ); } } @@ -316,7 +336,7 @@ class SpecialPageFactory { } } - return self::$aliases; + return $this->aliases; } /** @@ -327,13 +347,12 @@ class SpecialPageFactory { * @param string $alias * @return array Array( String, String|null ), or array( null, null ) if the page is invalid */ - public static function resolveAlias( $alias ) { + public function resolveAlias( $alias ) { $bits = explode( '/', $alias, 2 ); - $caseFoldedAlias = MediaWikiServices::getInstance()->getContentLanguage()-> - caseFold( $bits[0] ); + $caseFoldedAlias = $this->contLang->caseFold( $bits[0] ); $caseFoldedAlias = str_replace( ' ', '_', $caseFoldedAlias ); - $aliases = self::getAliasList(); + $aliases = $this->getAliasList(); if ( isset( $aliases[$caseFoldedAlias] ) ) { $name = $aliases[$caseFoldedAlias]; } else { @@ -355,10 +374,10 @@ class SpecialPageFactory { * @param string $name Name of a special page * @return bool True if a special page exists with this name */ - public static function exists( $name ) { - list( $title, /*...*/ ) = self::resolveAlias( $name ); + public function exists( $name ) { + list( $title, /*...*/ ) = $this->resolveAlias( $name ); - $specialPageList = self::getPageList(); + $specialPageList = $this->getPageList(); return isset( $specialPageList[$title] ); } @@ -368,17 +387,17 @@ class SpecialPageFactory { * @param string $name Special page name, may be localised and/or an alias * @return SpecialPage|null SpecialPage object or null if the page doesn't exist */ - public static function getPage( $name ) { - list( $realName, /*...*/ ) = self::resolveAlias( $name ); + public function getPage( $name ) { + list( $realName, /*...*/ ) = $this->resolveAlias( $name ); - $specialPageList = self::getPageList(); + $specialPageList = $this->getPageList(); if ( isset( $specialPageList[$realName] ) ) { $rec = $specialPageList[$realName]; if ( is_callable( $rec ) ) { // Use callback to instantiate the special page - $page = call_user_func( $rec ); + $page = $rec(); } elseif ( is_string( $rec ) ) { $className = $rec; $page = new $className; @@ -416,18 +435,14 @@ class SpecialPageFactory { * Return categorised listable special pages which are available * for the current user, and everyone. * - * @param User|null $user User object to check permissions, $wgUser will be used - * if not provided + * @param User $user User object to check permissions + * provided * @return array ( string => Specialpage ) */ - public static function getUsablePages( User $user = null ) { + public function getUsablePages( User $user ) : array { $pages = []; - if ( $user === null ) { - global $wgUser; - $user = $wgUser; - } - foreach ( self::getPageList() as $name => $rec ) { - $page = self::getPage( $name ); + foreach ( $this->getPageList() as $name => $rec ) { + $page = $this->getPage( $name ); if ( $page ) { // not null $page->setContext( RequestContext::getMain() ); if ( $page->isListed() @@ -446,10 +461,10 @@ class SpecialPageFactory { * * @return array ( string => Specialpage ) */ - public static function getRegularPages() { + public function getRegularPages() : array { $pages = []; - foreach ( self::getPageList() as $name => $rec ) { - $page = self::getPage( $name ); + foreach ( $this->getPageList() as $name => $rec ) { + $page = $this->getPage( $name ); if ( $page && $page->isListed() && !$page->isRestricted() ) { $pages[$name] = $page; } @@ -462,17 +477,13 @@ class SpecialPageFactory { * Return categorised listable special pages which are available * for the current user, but not for everyone * - * @param User|null $user User object to use or null for $wgUser + * @param User $user User object to use * @return array ( string => Specialpage ) */ - public static function getRestrictedPages( User $user = null ) { + public function getRestrictedPages( User $user ) : array { $pages = []; - if ( $user === null ) { - global $wgUser; - $user = $wgUser; - } - foreach ( self::getPageList() as $name => $rec ) { - $page = self::getPage( $name ); + foreach ( $this->getPageList() as $name => $rec ) { + $page = $this->getPage( $name ); if ( $page && $page->isListed() && $page->isRestricted() @@ -500,7 +511,7 @@ class SpecialPageFactory { * * @return bool|Title */ - public static function executePath( Title &$title, IContextSource &$context, $including = false, + public function executePath( Title &$title, IContextSource &$context, $including = false, LinkRenderer $linkRenderer = null ) { // @todo FIXME: Redirects broken due to this call @@ -512,7 +523,7 @@ class SpecialPageFactory { $par = $bits[1]; } - $page = self::getPage( $name ); + $page = $this->getPage( $name ); if ( !$page ) { $context->getOutput()->setArticleRelated( false ); $context->getOutput()->setRobotPolicy( 'noindex,nofollow' ); @@ -587,7 +598,7 @@ class SpecialPageFactory { * @param LinkRenderer|null $linkRenderer (since 1.28) * @return string HTML fragment */ - public static function capturePath( + public function capturePath( Title $title, IContextSource $context, LinkRenderer $linkRenderer = null ) { global $wgTitle, $wgOut, $wgRequest, $wgUser, $wgLang; @@ -622,7 +633,7 @@ class SpecialPageFactory { $main->setLanguage( $context->getLanguage() ); // The useful part - $ret = self::executePath( $title, $context, true, $linkRenderer ); + $ret = $this->executePath( $title, $context, true, $linkRenderer ); // Restore old globals and context $wgTitle = $glob['title']; @@ -646,16 +657,15 @@ class SpecialPageFactory { * @param string|bool $subpage * @return string */ - public static function getLocalNameFor( $name, $subpage = false ) { - $contLang = MediaWikiServices::getInstance()->getContentLanguage(); - $aliases = $contLang->getSpecialPageAliases(); - $aliasList = self::getAliasList(); + public function getLocalNameFor( $name, $subpage = false ) { + $aliases = $this->contLang->getSpecialPageAliases(); + $aliasList = $this->getAliasList(); // Find the first alias that maps back to $name if ( isset( $aliases[$name] ) ) { $found = false; foreach ( $aliases[$name] as $alias ) { - $caseFoldedAlias = $contLang->caseFold( $alias ); + $caseFoldedAlias = $this->contLang->caseFold( $alias ); $caseFoldedAlias = str_replace( ' ', '_', $caseFoldedAlias ); if ( isset( $aliasList[$caseFoldedAlias] ) && $aliasList[$caseFoldedAlias] === $name @@ -676,7 +686,7 @@ class SpecialPageFactory { if ( strcasecmp( $name, $n ) === 0 ) { wfWarn( "Found alias defined for $n when searching for " . "special page aliases for $name. Case mismatch?" ); - return self::getLocalNameFor( $n, $subpage ); + return $this->getLocalNameFor( $n, $subpage ); } } } @@ -691,7 +701,7 @@ class SpecialPageFactory { $name = "$name/$subpage"; } - return $contLang->ucfirst( $name ); + return $this->contLang->ucfirst( $name ); } /** @@ -700,8 +710,8 @@ class SpecialPageFactory { * @param string $alias * @return Title|null Title or null if there is no such alias */ - public static function getTitleForAlias( $alias ) { - list( $name, $subpage ) = self::resolveAlias( $alias ); + public function getTitleForAlias( $alias ) { + list( $name, $subpage ) = $this->resolveAlias( $alias ); if ( $name != null ) { return SpecialPage::getTitleFor( $name, $subpage ); } else { diff --git a/includes/specialpage/SpecialPageFactory_deprecated.php b/includes/specialpage/SpecialPageFactory_deprecated.php new file mode 100644 index 0000000000..bc0c250b97 --- /dev/null +++ b/includes/specialpage/SpecialPageFactory_deprecated.php @@ -0,0 +1,96 @@ +getSpecialPageFactory()->getNames(); + } + + public static function resolveAlias( $alias ) : array { + return MediaWikiServices::getInstance()->getSpecialPageFactory()->resolveAlias( $alias ); + } + + public static function exists( $name ) { + return MediaWikiServices::getInstance()->getSpecialPageFactory()->exists( $name ); + } + + public static function getPage( $name ) { + return MediaWikiServices::getInstance()->getSpecialPageFactory()->getPage( $name ); + } + + public static function getUsablePages( User $user = null ) : array { + global $wgUser; + $user = $user ?? $wgUser; + return MediaWikiServices::getInstance()->getSpecialPageFactory()->getUsablePages( $user ); + } + + public static function getRegularPages() : array { + return MediaWikiServices::getInstance()->getSpecialPageFactory()->getRegularPages(); + } + + public static function getRestrictedPages( User $user = null ) : array { + global $wgUser; + $user = $user ?? $wgUser; + return MediaWikiServices::getInstance()->getSpecialPageFactory()->getRestrictedPages( $user ); + } + + public static function executePath( Title &$title, IContextSource &$context, $including = false, + LinkRenderer $linkRenderer = null + ) { + return MediaWikiServices::getInstance()->getSpecialPageFactory() + ->executePath( $title, $context, $including, $linkRenderer ); + } + + public static function capturePath( + Title $title, IContextSource $context, LinkRenderer $linkRenderer = null + ) { + return MediaWikiServices::getInstance()->getSpecialPageFactory() + ->capturePath( $title, $context, $linkRenderer ); + } + + public static function getLocalNameFor( $name, $subpage = false ) { + return MediaWikiServices::getInstance()->getSpecialPageFactory() + ->getLocalNameFor( $name, $subpage ); + } + + public static function getTitleForAlias( $alias ) { + return MediaWikiServices::getInstance()->getSpecialPageFactory() + ->getTitleForAlias( $alias ); + } + + /** + * No-op since 1.32, call overrideMwServices() instead + */ + public static function resetList() { + } +} diff --git a/tests/phpunit/MediaWikiTestCase.php b/tests/phpunit/MediaWikiTestCase.php index a8cc25242a..89bcf600c8 100644 --- a/tests/phpunit/MediaWikiTestCase.php +++ b/tests/phpunit/MediaWikiTestCase.php @@ -947,7 +947,9 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase { * @return MediaWikiServices * @throws MWException */ - protected function overrideMwServices( Config $configOverrides = null, array $services = [] ) { + protected static function overrideMwServices( + Config $configOverrides = null, array $services = [] + ) { if ( !$configOverrides ) { $configOverrides = new HashConfig(); } diff --git a/tests/phpunit/includes/PrefixSearchTest.php b/tests/phpunit/includes/PrefixSearchTest.php index 560692417f..0e357678e8 100644 --- a/tests/phpunit/includes/PrefixSearchTest.php +++ b/tests/phpunit/includes/PrefixSearchTest.php @@ -61,7 +61,7 @@ class PrefixSearchTest extends MediaWikiLangTestCase { $this->originalHandlers = TestingAccessWrapper::newFromClass( Hooks::class )->handlers; TestingAccessWrapper::newFromClass( Hooks::class )->handlers = []; - SpecialPageFactory::resetList(); + $this->overrideMwServices(); } public function tearDown() { @@ -69,7 +69,7 @@ class PrefixSearchTest extends MediaWikiLangTestCase { TestingAccessWrapper::newFromClass( Hooks::class )->handlers = $this->originalHandlers; - SpecialPageFactory::resetList(); + $this->overrideMwServices(); } protected function searchProvision( array $results = null ) { diff --git a/tests/phpunit/includes/search/SearchEnginePrefixTest.php b/tests/phpunit/includes/search/SearchEnginePrefixTest.php index 83df61a4bc..41c12188a8 100644 --- a/tests/phpunit/includes/search/SearchEnginePrefixTest.php +++ b/tests/phpunit/includes/search/SearchEnginePrefixTest.php @@ -69,7 +69,7 @@ class SearchEnginePrefixTest extends MediaWikiLangTestCase { $this->originalHandlers = TestingAccessWrapper::newFromClass( Hooks::class )->handlers; TestingAccessWrapper::newFromClass( Hooks::class )->handlers = []; - SpecialPageFactory::resetList(); + $this->overrideMwServices(); } public function tearDown() { @@ -77,7 +77,7 @@ class SearchEnginePrefixTest extends MediaWikiLangTestCase { TestingAccessWrapper::newFromClass( Hooks::class )->handlers = $this->originalHandlers; - SpecialPageFactory::resetList(); + $this->overrideMwServices(); } protected function searchProvision( array $results = null ) { diff --git a/tests/phpunit/includes/specialpage/SpecialPageFactoryTest.php b/tests/phpunit/includes/specialpage/SpecialPageFactoryTest.php index 1da6fb36a7..04a89d2f15 100644 --- a/tests/phpunit/includes/specialpage/SpecialPageFactoryTest.php +++ b/tests/phpunit/includes/specialpage/SpecialPageFactoryTest.php @@ -21,22 +21,10 @@ use Wikimedia\ScopedCallback; * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * - * @covers SpecialPageFactory + * @covers \MediaWiki\Special\SpecialPageFactory * @group SpecialPage */ class SpecialPageFactoryTest extends MediaWikiTestCase { - - protected function tearDown() { - parent::tearDown(); - - SpecialPageFactory::resetList(); - } - - public function testResetList() { - SpecialPageFactory::resetList(); - $this->assertContains( 'Specialpages', SpecialPageFactory::getNames() ); - } - public function testHookNotCalledTwice() { $count = 0; $this->mergeMwGlobalArrayValue( 'wgHooks', [ @@ -45,9 +33,10 @@ class SpecialPageFactoryTest extends MediaWikiTestCase { $count++; } ] ] ); - SpecialPageFactory::resetList(); - SpecialPageFactory::getNames(); - SpecialPageFactory::getNames(); + $this->overrideMwServices(); + $spf = MediaWikiServices::getInstance()->getSpecialPageFactory(); + $spf->getNames(); + $spf->getNames(); $this->assertEquals( 1, $count ); } @@ -82,7 +71,7 @@ class SpecialPageFactoryTest extends MediaWikiTestCase { */ public function testGetPage( $spec, $shouldReuseInstance ) { $this->mergeMwGlobalArrayValue( 'wgSpecialPages', [ 'testdummy' => $spec ] ); - SpecialPageFactory::resetList(); + $this->overrideMwServices(); $page = SpecialPageFactory::getPage( 'testdummy' ); $this->assertInstanceOf( SpecialPage::class, $page ); @@ -96,7 +85,7 @@ class SpecialPageFactoryTest extends MediaWikiTestCase { */ public function testGetNames() { $this->mergeMwGlobalArrayValue( 'wgSpecialPages', [ 'testdummy' => SpecialAllPages::class ] ); - SpecialPageFactory::resetList(); + $this->overrideMwServices(); $names = SpecialPageFactory::getNames(); $this->assertInternalType( 'array', $names ); @@ -108,7 +97,7 @@ class SpecialPageFactoryTest extends MediaWikiTestCase { */ public function testResolveAlias() { $this->setContentLang( 'de' ); - SpecialPageFactory::resetList(); + $this->overrideMwServices(); list( $name, $param ) = SpecialPageFactory::resolveAlias( 'Spezialseiten/Foo' ); $this->assertEquals( 'Specialpages', $name ); @@ -120,7 +109,7 @@ class SpecialPageFactoryTest extends MediaWikiTestCase { */ public function testGetLocalNameFor() { $this->setContentLang( 'de' ); - SpecialPageFactory::resetList(); + $this->overrideMwServices(); $name = SpecialPageFactory::getLocalNameFor( 'Specialpages', 'Foo' ); $this->assertEquals( 'Spezialseiten/Foo', $name ); @@ -131,7 +120,7 @@ class SpecialPageFactoryTest extends MediaWikiTestCase { */ public function testGetTitleForAlias() { $this->setContentLang( 'de' ); - SpecialPageFactory::resetList(); + $this->overrideMwServices(); $title = SpecialPageFactory::getTitleForAlias( 'Specialpages/Foo' ); $this->assertEquals( 'Spezialseiten/Foo', $title->getText() ); @@ -146,11 +135,11 @@ class SpecialPageFactoryTest extends MediaWikiTestCase { ) { $lang = clone MediaWikiServices::getInstance()->getContentLanguage(); $lang->mExtendedSpecialPageAliases = $aliasesList; - $this->setContentLang( $lang ); $this->setMwGlobals( 'wgSpecialPages', array_combine( array_keys( $aliasesList ), array_keys( $aliasesList ) ) ); - SpecialPageFactory::resetList(); + $this->overrideMwServices(); + $this->setContentLang( $lang ); // Catch the warnings we expect to be raised $warnings = []; @@ -278,7 +267,7 @@ class SpecialPageFactoryTest extends MediaWikiTestCase { } ], ] ); - SpecialPageFactory::resetList(); + $this->overrideMwServices(); SpecialPageFactory::getLocalNameFor( 'Specialpages' ); $this->assertTrue( $called, 'Recursive call succeeded' ); } diff --git a/tests/phpunit/structure/SpecialPageFatalTest.php b/tests/phpunit/structure/SpecialPageFatalTest.php index abf1cddbbb..47dbd2e02e 100644 --- a/tests/phpunit/structure/SpecialPageFatalTest.php +++ b/tests/phpunit/structure/SpecialPageFatalTest.php @@ -14,11 +14,11 @@ class SpecialPageFatalTest extends MediaWikiTestCase { public static function setUpBeforeClass() { parent::setUpBeforeClass(); - SpecialPageFactory::resetList(); + self::overrideMwServices(); } public static function tearDownAfterClass() { - SpecialPageFactory::resetList(); + self::overrideMwServices(); parent::tearDownAfterClass(); }