Hooks::run() call site migration

Migrate all callers of Hooks::run() to use the new
HookContainer/HookRunner system.

General principles:
* Use DI if it is already used. We're not changing the way state is
  managed in this patch.
* HookContainer is always injected, not HookRunner. HookContainer
  is a service, it's a more generic interface, it is the only
  thing that provides isRegistered() which is needed in some cases,
  and a HookRunner can be efficiently constructed from it
  (confirmed by benchmark). Because HookContainer is needed
  for object construction, it is also needed by all factories.
* "Ask your friendly local base class". Big hierarchies like
  SpecialPage and ApiBase have getHookContainer() and getHookRunner()
  methods in the base class, and classes that extend that base class
  are not expected to know or care where the base class gets its
  HookContainer from.
* ProtectedHookAccessorTrait provides protected getHookContainer() and
  getHookRunner() methods, getting them from the global service
  container. The point of this is to ease migration to DI by ensuring
  that call sites ask their local friendly base class rather than
  getting a HookRunner from the service container directly.
* Private $this->hookRunner. In some smaller classes where accessor
  methods did not seem warranted, there is a private HookRunner property
  which is accessed directly. Very rarely (two cases), there is a
  protected property, for consistency with code that conventionally
  assumes protected=private, but in cases where the class might actually
  be overridden, a protected accessor is preferred over a protected
  property.
* The last resort: Hooks::runner(). Mostly for static, file-scope and
  global code. In a few cases it was used for objects with broken
  construction schemes, out of horror or laziness.

Constructors with new required arguments:
* AuthManager
* BadFileLookup
* BlockManager
* ClassicInterwikiLookup
* ContentHandlerFactory
* ContentSecurityPolicy
* DefaultOptionsManager
* DerivedPageDataUpdater
* FullSearchResultWidget
* HtmlCacheUpdater
* LanguageFactory
* LanguageNameUtils
* LinkRenderer
* LinkRendererFactory
* LocalisationCache
* MagicWordFactory
* MessageCache
* NamespaceInfo
* PageEditStash
* PageHandlerFactory
* PageUpdater
* ParserFactory
* PermissionManager
* RevisionStore
* RevisionStoreFactory
* SearchEngineConfig
* SearchEngineFactory
* SearchFormWidget
* SearchNearMatcher
* SessionBackend
* SpecialPageFactory
* UserNameUtils
* UserOptionsManager
* WatchedItemQueryService
* WatchedItemStore

Constructors with new optional arguments:
* DefaultPreferencesFactory
* Language
* LinkHolderArray
* MovePage
* Parser
* ParserCache
* PasswordReset
* Router

setHookContainer() now required after construction:
* AuthenticationProvider
* ResourceLoaderModule
* SearchEngine

Change-Id: Id442b0dbe43aba84bd5cf801d86dedc768b082c7
This commit is contained in:
Tim Starling 2020-03-19 13:42:09 +11:00 committed by Reedy
parent 2530009b8c
commit 68c433bd23
293 changed files with 2485 additions and 1420 deletions

View file

@ -601,6 +601,49 @@ because of Phabricator reports.
instead.
* SpecialVersion::getExtensionCredits() and SpecialVersion::getSkinCredits()
have become private without deprecation.
* As part of the migration to a new hook system (T240307), the following classes
now require an additional HookContainer constructor parameter:
- AuthManager
- BadFileLookup
- BlockManager
- ClassicInterwikiLookup
- ContentHandlerFactory
- ContentSecurityPolicy
- DefaultOptionsManager
- DerivedPageDataUpdater
- FullSearchResultWidget
- HtmlCacheUpdater
- LanguageFactory
- LanguageNameUtils
- LinkRenderer
- LinkRendererFactory
- LocalisationCache
- MagicWordFactory
- MessageCache
- NamespaceInfo
- PageEditStash
- PageHandlerFactory
- PageUpdater
- ParserFactory
- PermissionManager
- RevisionStore
- RevisionStoreFactory
- Router
- SearchEngineConfig
- SearchEngineFactory
- SearchFormWidget
- SearchNearMatcher
- SessionBackend
- SpecialPageFactory
- UserNameUtils
- UserOptionsManager
- WatchedItemQueryService
- WatchedItemStore
* The following classes now require setHookContainer() to be called after
construction:
- AuthenticationProvider
- ResourceLoaderModule
- SearchEngine
* …
=== Deprecations in 1.35 ===

View file

@ -69,7 +69,7 @@ try {
$processor = new ApiMain( RequestContext::getMain(), true );
// Last chance hook before executing the API
Hooks::run( 'ApiBeforeMain', [ &$processor ] );
Hooks::runner()->onApiBeforeMain( $processor );
if ( !$processor instanceof ApiMain ) {
throw new MWException( 'ApiBeforeMain hook set $processor to a non-ApiMain class' );
}

View file

@ -157,7 +157,7 @@ function wfImageAuthMain() {
// Run hook for extension authorization plugins
/** @var array $result */
$result = null;
if ( !Hooks::run( 'ImgAuthBeforeStream', [ &$title, &$path, &$name, &$result ] ) ) {
if ( !Hooks::runner()->onImgAuthBeforeStream( $title, $path, $name, $result ) ) {
wfForbidden( $result[0], $result[1], array_slice( $result, 2 ) );
return;
}
@ -183,7 +183,7 @@ function wfImageAuthMain() {
}
// Allow modification of headers before streaming a file
Hooks::run( 'ImgAuthModifyHeaders', [ $title->getTitleValue(), &$headers ] );
Hooks::runner()->onImgAuthModifyHeaders( $title->getTitleValue(), $headers );
// Stream the requested file
list( $headers, $options ) = HTTPFileStreamer::preprocessHeaders( $headers );

View file

@ -46,7 +46,7 @@ class Autopromote {
}
}
Hooks::run( 'GetAutoPromoteGroups', [ $user, &$promote ] );
Hooks::runner()->onGetAutoPromoteGroups( $user, $promote );
return $promote;
}
@ -208,8 +208,8 @@ class Autopromote {
->getGroupPermissions( $user->getGroups() ) );
default:
$result = null;
Hooks::run( 'AutopromoteCondition', [ $cond[0],
array_slice( $cond, 1 ), $user, &$result ] );
Hooks::runner()->onAutopromoteCondition( $cond[0],
array_slice( $cond, 1 ), $user, $result );
if ( $result === null ) {
throw new MWException( "Unrecognized condition {$cond[0]} for autopromotion!" );
}

View file

@ -3,8 +3,9 @@
namespace MediaWiki;
use BagOStuff;
use Hooks;
use MalformedTitleException;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\Linker\LinkTarget;
use RepoGroup;
use TitleParser;
@ -25,6 +26,9 @@ class BadFileLookup {
/** @var array|null Parsed blacklist */
private $badFiles;
/** @var HookRunner */
private $hookRunner;
/**
* Do not call directly. Use MediaWikiServices.
*
@ -32,17 +36,20 @@ class BadFileLookup {
* @param BagOStuff $cache For caching parsed versions of the blacklist
* @param RepoGroup $repoGroup
* @param TitleParser $titleParser
* @param HookContainer $hookContainer
*/
public function __construct(
callable $blacklistCallback,
BagOStuff $cache,
RepoGroup $repoGroup,
TitleParser $titleParser
TitleParser $titleParser,
HookContainer $hookContainer
) {
$this->blacklistCallback = $blacklistCallback;
$this->cache = $cache;
$this->repoGroup = $repoGroup;
$this->titleParser = $titleParser;
$this->hookRunner = new HookRunner( $hookContainer );
}
/**
@ -70,7 +77,7 @@ class BadFileLookup {
// Run the extension hook
$bad = false;
if ( !Hooks::run( 'BadImage', [ $name, &$bad ] ) ) {
if ( !$this->hookRunner->onBadImage( $name, $bad ) ) {
return (bool)$bad;
}

View file

@ -19,9 +19,13 @@
*
* @file
*/
use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
use MediaWiki\MediaWikiServices;
class CategoryViewer extends ContextSource {
use ProtectedHookAccessorTrait;
/** @var int */
public $limit;
@ -194,7 +198,7 @@ class CategoryViewer extends ContextSource {
private function generateLink( $type, Title $title, $isRedirect, $html = null ) {
$link = null;
Hooks::run( 'CategoryViewer::generateLink', [ $type, $title, $html, &$link ] );
$this->getHookRunner()->onCategoryViewer__generateLink( $type, $title, $html, $link );
if ( $link === null ) {
$linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
if ( $html !== null ) {
@ -347,7 +351,7 @@ class CategoryViewer extends ContextSource {
]
);
Hooks::run( 'CategoryViewer::doCategoryQuery', [ $type, $res ] );
$this->getHookRunner()->onCategoryViewer__doCategoryQuery( $type, $res );
$linkCache = MediaWikiServices::getInstance()->getLinkCache();
$count = 0;

View file

@ -25,6 +25,8 @@
* @file
*/
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\MediaWikiServices;
class ContentSecurityPolicy {
@ -45,17 +47,24 @@ class ContentSecurityPolicy {
/** @var array */
private $extraStyleSrc = [];
/** @var HookRunner */
private $hookRunner;
/**
* @note As a general rule, you would not construct this class directly
* but use the instance from OutputPage::getCSP()
* @internal
* @param WebResponse $response
* @param Config $mwConfig
* @param HookContainer $hookContainer
* @since 1.35 Method signature changed
*/
public function __construct( WebResponse $response, Config $mwConfig ) {
public function __construct( WebResponse $response, Config $mwConfig,
HookContainer $hookContainer
) {
$this->response = $response;
$this->mwConfig = $mwConfig;
$this->hookRunner = new HookRunner( $hookContainer );
}
/**
@ -215,8 +224,8 @@ class ContentSecurityPolicy {
$cssSrc = array_merge( $defaultSrc, $this->extraStyleSrc, [ "'unsafe-inline'" ] );
Hooks::run( 'ContentSecurityPolicyDefaultSource', [ &$defaultSrc, $policyConfig, $mode ] );
Hooks::run( 'ContentSecurityPolicyScriptSource', [ &$scriptSrc, $policyConfig, $mode ] );
$this->hookRunner->onContentSecurityPolicyDefaultSource( $defaultSrc, $policyConfig, $mode );
$this->hookRunner->onContentSecurityPolicyScriptSource( $scriptSrc, $policyConfig, $mode );
if ( isset( $policyConfig['report-uri'] ) && $policyConfig['report-uri'] !== true ) {
if ( $policyConfig['report-uri'] === false ) {
@ -282,7 +291,7 @@ class ContentSecurityPolicy {
$directives[] = 'report-uri ' . $reportUri;
}
Hooks::run( 'ContentSecurityPolicyDirectives', [ &$directives, $policyConfig, $mode ] );
$this->hookRunner->onContentSecurityPolicyDirectives( $directives, $policyConfig, $mode );
return implode( '; ', $directives );
}

View file

@ -24,6 +24,7 @@ use MediaWiki\Block\DatabaseBlock;
use MediaWiki\Content\IContentHandlerFactory;
use MediaWiki\EditPage\TextboxBuilder;
use MediaWiki\EditPage\TextConflictHelper;
use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
use MediaWiki\Logger\LoggerFactory;
use MediaWiki\MediaWikiServices;
use MediaWiki\Permissions\PermissionManager;
@ -49,8 +50,8 @@ use Wikimedia\ScopedCallback;
* headaches, which may be fatal.
*/
class EditPage {
use DeprecationHelper;
use ProtectedHookAccessorTrait;
/**
* Used for Unicode support checks
@ -627,7 +628,7 @@ class EditPage {
*/
public function edit() {
// Allow extensions to modify/prevent this form or submission
if ( !Hooks::run( 'AlternateEdit', [ $this ] ) ) {
if ( !$this->getHookRunner()->onAlternateEdit( $this ) ) {
return;
}
@ -749,9 +750,9 @@ class EditPage {
}
if ( !$this->mTitle->getArticleID() ) {
Hooks::run( 'EditFormPreloadText', [ &$this->textbox1, &$this->mTitle ] );
$this->getHookRunner()->onEditFormPreloadText( $this->textbox1, $this->mTitle );
} else {
Hooks::run( 'EditFormInitialText', [ $this ] );
$this->getHookRunner()->onEditFormInitialText( $this );
}
}
@ -848,7 +849,7 @@ class EditPage {
*/
protected function displayViewSourcePage( Content $content, $errorMessage = '' ) {
$out = $this->context->getOutput();
Hooks::run( 'EditPage::showReadOnlyForm:initial', [ $this, &$out ] );
$this->getHookRunner()->onEditPage__showReadOnlyForm_initial( $this, $out );
$out->setRobotPolicy( 'noindex,nofollow' );
$out->setPageTitle( $this->context->msg(
@ -1180,7 +1181,7 @@ class EditPage {
$this->section === 'new' ? 'MediaWiki:addsection-editintro' : '' );
// Allow extensions to modify form data
Hooks::run( 'EditPage::importFormData', [ $this, $request ] );
$this->getHookRunner()->onEditPage__importFormData( $this, $request );
}
/**
@ -1757,7 +1758,7 @@ class EditPage {
&& $this->permManager->userHasRight( $this->context->getUser(), 'bot' );
$status = $this->internalAttemptSave( $resultDetails, $markAsBot );
Hooks::run( 'EditPage::attemptSave:after', [ $this, $status, $resultDetails ] );
$this->getHookRunner()->onEditPage__attemptSave_after( $this, $status, $resultDetails );
return $status;
}
@ -1851,10 +1852,8 @@ class EditPage {
$sectionanchor = $resultDetails['sectionanchor'];
// Give extensions a chance to modify URL query on update
Hooks::run(
'ArticleUpdateBeforeRedirect',
[ $this->mArticle, &$sectionanchor, &$extraQuery ]
);
$this->getHookRunner()->onArticleUpdateBeforeRedirect( $this->mArticle,
$sectionanchor, $extraQuery );
if ( $resultDetails['redirect'] ) {
if ( $extraQuery !== '' ) {
@ -1936,9 +1935,8 @@ class EditPage {
}
// Run new style post-section-merge edit filter
if ( !Hooks::run( 'EditFilterMergedContent',
[ $this->context, $content, $status, $this->summary,
$user, $this->minoredit ] )
if ( !$this->getHookRunner()->onEditFilterMergedContent( $this->context, $content,
$status, $this->summary, $user, $this->minoredit )
) {
# Error messages etc. could be handled within the hook...
if ( $status->isGood() ) {
@ -2049,7 +2047,7 @@ ERROR;
$status = Status::newGood();
$user = $this->context->getUser();
if ( !Hooks::run( 'EditPage::attemptSave', [ $this ] ) ) {
if ( !$this->getHookRunner()->onEditPage__attemptSave( $this ) ) {
wfDebug( "Hook 'EditPage::attemptSave' aborted article saving\n" );
$status->fatal( 'hookaborted' );
$status->value = self::AS_HOOK_ERROR;
@ -2132,9 +2130,8 @@ ERROR;
$status->value = self::AS_SPAM_ERROR;
return $status;
}
if ( !Hooks::run(
'EditFilter',
[ $this, $this->textbox1, $this->section, &$this->hookError, $this->summary ] )
if ( !$this->getHookRunner()->onEditFilter( $this, $this->textbox1, $this->section,
$this->hookError, $this->summary )
) {
# Error messages etc. could be handled within the hook...
$status->fatal( 'hookaborted' );
@ -2994,9 +2991,7 @@ ERROR;
$out = $this->context->getOutput();
// Avoid PHP 7.1 warning of passing $this by reference
$editPage = $this;
Hooks::run( 'EditPage::showEditForm:initial', [ &$editPage, &$out ] );
$this->getHookRunner()->onEditPage__showEditForm_initial( $this, $out );
$this->setHeaders();
@ -3071,9 +3066,7 @@ ERROR;
. Xml::closeElement( 'div' )
);
// Avoid PHP 7.1 warning of passing $this by reference
$editPage = $this;
Hooks::run( 'EditPage::showEditForm:fields', [ &$editPage, &$out ] );
$this->getHookRunner()->onEditPage__showEditForm_fields( $this, $out );
// Put these up at the top to ensure they aren't lost on early form submission
$this->showFormBeforeText();
@ -3726,7 +3719,7 @@ ERROR;
# This hook seems slightly odd here, but makes things more
# consistent for extensions.
$out = $this->context->getOutput();
Hooks::run( 'OutputPageBeforeHTML', [ &$out, &$text ] );
$this->getHookRunner()->onOutputPageBeforeHTML( $out, $text );
$out->addHTML( $text );
if ( $this->mArticle instanceof CategoryPage ) {
$this->mArticle->closeShowCategory();
@ -3767,7 +3760,7 @@ ERROR;
}
if ( $newContent ) {
Hooks::run( 'EditPageGetDiffContent', [ $this, &$newContent ] );
$this->getHookRunner()->onEditPageGetDiffContent( $this, $newContent );
$user = $this->context->getUser();
$popts = ParserOptions::newFromUserAndLang( $user,
@ -3820,7 +3813,7 @@ ERROR;
*/
protected function showTosSummary() {
$msg = 'editpage-tos-summary';
Hooks::run( 'EditPageTosSummary', [ $this->mTitle, &$msg ] );
$this->getHookRunner()->onEditPageTosSummary( $this->mTitle, $msg );
if ( !$this->context->msg( $msg )->isDisabled() ) {
$out = $this->context->getOutput();
$out->addHTML( '<div class="mw-tos-summary">' );
@ -3868,7 +3861,7 @@ ERROR;
'[[' . wfMessage( 'copyrightpage' )->inContentLanguage()->text() . ']]' ];
}
// Allow for site and per-namespace customization of contribution/copyright notice.
Hooks::run( 'EditPageCopyrightWarning', [ $title, &$copywarnMsg ] );
Hooks::runner()->onEditPageCopyrightWarning( $title, $copywarnMsg );
$msg = wfMessage( ...$copywarnMsg )->title( $title );
if ( $langcode ) {
@ -3905,9 +3898,7 @@ ERROR;
Html::openElement( 'tbody' );
foreach ( $output->getLimitReportData() as $key => $value ) {
if ( Hooks::run( 'ParserLimitReportFormat',
[ $key, &$value, &$limitReport, true, true ]
) ) {
if ( Hooks::runner()->onParserLimitReportFormat( $key, $value, $limitReport, true, true ) ) {
$keyMsg = wfMessage( $key );
$valueMsg = wfMessage( [ "$key-value-html", "$key-value" ] );
if ( !$valueMsg->exists() ) {
@ -3972,7 +3963,7 @@ ERROR;
$out->addHTML( " <span class='editHelp'>{$edithelp}</span>\n" );
$out->addHTML( "</div><!-- editButtons -->\n" );
Hooks::run( 'EditPage::showStandardInputs:options', [ $this, $out, &$tabindex ] );
$this->getHookRunner()->onEditPage__showStandardInputs_options( $this, $out, $tabindex );
$out->addHTML( "</div><!-- editOptions -->\n" );
}
@ -3985,7 +3976,7 @@ ERROR;
$out = $this->context->getOutput();
// Avoid PHP 7.1 warning of passing $this by reference
$editPage = $this;
if ( Hooks::run( 'EditPageBeforeConflictDiff', [ &$editPage, &$out ] ) ) {
if ( $this->getHookRunner()->onEditPageBeforeConflictDiff( $editPage, $out ) ) {
$this->incrementConflictStats();
$this->getEditConflictHelper()->showEditFormTextAfterFooters();
@ -4139,9 +4130,8 @@ ERROR;
$content = $this->toEditContent( $this->textbox1 );
$previewHTML = '';
if ( !Hooks::run(
'AlternateEditPreview',
[ $this, &$content, &$previewHTML, &$this->mParserOutput ] )
if ( !$this->getHookRunner()->onAlternateEditPreview(
$this, $content, $previewHTML, $this->mParserOutput )
) {
return $previewHTML;
}
@ -4213,7 +4203,7 @@ ERROR;
$content = $content->addSectionHeader( $this->summary );
}
Hooks::run( 'EditPageGetPreviewContent', [ $this, &$content ] );
$this->getHookRunner()->onEditPageGetPreviewContent( $this, $content );
$parserResult = $this->doPreviewParse( $content );
$parserOutput = $parserResult['parserOutput'];
@ -4349,7 +4339,7 @@ ERROR;
$startingToolbar = '<div id="toolbar"></div>';
$toolbar = $startingToolbar;
if ( !Hooks::run( 'EditPageBeforeEditToolbar', [ &$toolbar ] ) ) {
if ( !Hooks::runner()->onEditPageBeforeEditToolbar( $toolbar ) ) {
return null;
}
// Don't add a pointless `<div>` to the page unless a hook caller populated it
@ -4403,8 +4393,7 @@ ERROR;
];
}
$editPage = $this;
Hooks::run( 'EditPageGetCheckboxesDefinition', [ $editPage, &$checkboxes ] );
$this->getHookRunner()->onEditPageGetCheckboxesDefinition( $this, $checkboxes );
return $checkboxes;
}
@ -4547,9 +4536,7 @@ ERROR;
'accessKey' => Linker::accesskey( 'diff' ),
] );
// Avoid PHP 7.1 warning of passing $this by reference
$editPage = $this;
Hooks::run( 'EditPageBeforeEditButtons', [ &$editPage, &$buttons, &$tabindex ] );
$this->getHookRunner()->onEditPageBeforeEditButtons( $this, $buttons, $tabindex );
return $buttons;
}
@ -4564,9 +4551,7 @@ ERROR;
$res = $this->context->msg( 'nosuchsectiontext', $this->section )->parseAsBlock();
// Avoid PHP 7.1 warning of passing $this by reference
$editPage = $this;
Hooks::run( 'EditPageNoSuchSection', [ &$editPage, &$res ] );
$this->getHookRunner()->onEditPageNoSuchSection( $this, $res );
$out->addHTML( $res );
$out->returnToMain( false, $this->mTitle );

View file

@ -277,7 +277,7 @@ class FileDeleteForm {
}
if ( $status->isOK() ) {
Hooks::run( 'FileDeleteComplete', [ &$file, &$oldimage, &$page, &$user, &$reason ] );
Hooks::runner()->onFileDeleteComplete( $file, $oldimage, $page, $user, $reason );
}
return $status;

View file

@ -418,7 +418,7 @@ class GitInfo {
if ( self::$viewers === false ) {
self::$viewers = $wgGitRepositoryViewers;
Hooks::run( 'GitViewers', [ &self::$viewers ] );
Hooks::runner()->onGitViewers( self::$viewers );
}
return self::$viewers;

View file

@ -2128,7 +2128,7 @@ function wfShellWikiCmd( $script, array $parameters = [], array $options = [] )
global $wgPhpCli;
// Give site config file a chance to run the script in a wrapper.
// The caller may likely want to call wfBasename() on $script.
Hooks::run( 'wfShellWikiCmd', [ &$script, &$parameters, &$options ] );
Hooks::runner()->onWfShellWikiCmd( $script, $parameters, $options );
$cmd = [ $options['php'] ?? $wgPhpCli ];
if ( isset( $options['wrapper'] ) ) {
$cmd[] = $options['wrapper'];
@ -2812,7 +2812,8 @@ function wfIsBadImage( $name, $contextTitle = false, $blacklist = null ) {
},
$services->getLocalServerObjectCache(),
$services->getRepoGroup(),
$services->getTitleParser()
$services->getTitleParser(),
$services->getHookContainer()
) )->isBadFile( $name, $contextTitle ?: null );
}
return $services->getBadFileLookup()->isBadFile( $name, $contextTitle ?: null );
@ -2827,7 +2828,7 @@ function wfIsBadImage( $name, $contextTitle = false, $blacklist = null ) {
*/
function wfCanIPUseHTTPS( $ip ) {
$canDo = true;
Hooks::run( 'CanIPUseHTTPS', [ $ip, &$canDo ] );
Hooks::runner()->onCanIPUseHTTPS( $ip, $canDo );
return (bool)$canDo;
}

View file

@ -164,7 +164,7 @@ class Linker {
public static function makeSelfLinkObj( $nt, $html = '', $query = '', $trail = '', $prefix = '' ) {
$nt = Title::newFromLinkTarget( $nt );
$ret = "<a class=\"mw-selflink selflink\">{$prefix}{$html}</a>{$trail}";
if ( !Hooks::run( 'SelfLinkBegin', [ $nt, &$html, &$trail, &$prefix, &$ret ] ) ) {
if ( !Hooks::runner()->onSelfLinkBegin( $nt, $html, $trail, $prefix, $ret ) ) {
return $ret;
}
@ -245,7 +245,7 @@ class Linker {
$alt = self::fnamePart( $url );
}
$img = '';
$success = Hooks::run( 'LinkerMakeExternalImage', [ &$url, &$alt, &$img ] );
$success = Hooks::runner()->onLinkerMakeExternalImage( $url, $alt, $img );
if ( !$success ) {
wfDebug( "Hook LinkerMakeExternalImage changed the output of external image "
. "with url {$url} and alt text {$alt} to {$img}\n", true );
@ -303,10 +303,10 @@ class Linker {
$title = Title::newFromLinkTarget( $title );
$res = null;
$dummy = new DummyLinker;
if ( !Hooks::run( 'ImageBeforeProduceHTML', [ &$dummy, &$title,
&$file, &$frameParams, &$handlerParams, &$time, &$res,
$parser, &$query, &$widthOption
] ) ) {
if ( !Hooks::runner()->onImageBeforeProduceHTML( $dummy, $title,
$file, $frameParams, $handlerParams, $time, $res,
$parser, $query, $widthOption )
) {
return $res;
}
@ -796,8 +796,9 @@ class Linker {
'title' => $alt
];
if ( !Hooks::run( 'LinkerMakeMediaLinkFile',
[ Title::castFromLinkTarget( $title ), $file, &$html, &$attribs, &$ret ] ) ) {
if ( !Hooks::runner()->onLinkerMakeMediaLinkFile(
Title::castFromLinkTarget( $title ), $file, $html, $attribs, $ret )
) {
wfDebug( "Hook LinkerMakeMediaLinkFile changed the output of link "
. "with url {$url} and text {$html} to {$ret}\n", true );
return $ret;
@ -873,8 +874,8 @@ class Linker {
$attribs['rel'] = implode( ' ', $combined );
}
$link = '';
$success = Hooks::run( 'LinkerMakeExternalLink',
[ &$url, &$text, &$link, &$attribs, $linktype ] );
$success = Hooks::runner()->onLinkerMakeExternalLink(
$url, $text, $link, $attribs, $linktype );
if ( !$success ) {
wfDebug( "Hook LinkerMakeExternalLink changed the output of link "
. "with url {$url} and text {$text} to {$link}\n", true );
@ -989,7 +990,7 @@ class Linker {
$items[] = self::emailLink( $userId, $userText );
}
Hooks::run( 'UserToolLinksEdit', [ $userId, $userText, &$items ] );
Hooks::runner()->onUserToolLinksEdit( $userId, $userText, $items );
if ( !$items ) {
return '';
@ -1252,11 +1253,9 @@ class Linker {
$post = $match[3] !== '';
$comment = null;
Hooks::run(
'FormatAutocomments',
[ &$comment, $pre, $auto, $post, Title::castFromLinkTarget( $title ), $local,
$wikiId ]
);
Hooks::runner()->onFormatAutocomments(
$comment, $pre, $auto, $post, Title::castFromLinkTarget( $title ), $local,
$wikiId );
if ( $comment === null ) {
if ( $title ) {

View file

@ -162,10 +162,9 @@ class MWTimestamp extends ConvertibleTimestamp {
$ts = '';
$diff = $this->diff( $relativeTo );
if ( Hooks::run(
'GetRelativeTimestamp',
[ &$ts, &$diff, $this, $relativeTo, $user, $lang ]
) ) {
if ( Hooks::runner()->onGetRelativeTimestamp(
$ts, $diff, $this, $relativeTo, $user, $lang )
) {
$seconds = ( ( ( $diff->days * 24 + $diff->h ) * 60 + $diff->i ) * 60 + $diff->s );
$ts = wfMessage( 'ago', $lang->formatDuration( $seconds, $chosenIntervals ) )
->inLanguage( $lang )->text();

View file

@ -21,6 +21,9 @@
* @ingroup Parser
*/
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
/**
* A factory that stores information about MagicWords, and creates them on demand with caching.
*
@ -196,13 +199,18 @@ class MagicWordFactory {
/** @var Language */
private $contLang;
/** @var HookRunner */
private $hookRunner;
/** #@- */
/**
* @param Language $contLang Content language
* @param HookContainer $hookContainer
*/
public function __construct( Language $contLang ) {
public function __construct( Language $contLang, HookContainer $hookContainer ) {
$this->contLang = $contLang;
$this->hookRunner = new HookRunner( $hookContainer );
}
public function getContentLanguage() {
@ -233,7 +241,7 @@ class MagicWordFactory {
public function getVariableIDs() {
if ( !$this->mVariableIDsInitialised ) {
# Get variable IDs
Hooks::run( 'MagicWordwgVariableIDs', [ &$this->mVariableIDs ] );
$this->hookRunner->onMagicWordwgVariableIDs( $this->mVariableIDs );
$this->mVariableIDsInitialised = true;
}
return $this->mVariableIDs;
@ -268,7 +276,7 @@ class MagicWordFactory {
*/
public function getDoubleUnderscoreArray() {
if ( $this->mDoubleUnderscoreArray === null ) {
Hooks::run( 'GetDoubleUnderscoreIDs', [ &$this->mDoubleUnderscoreIDs ] );
$this->hookRunner->onGetDoubleUnderscoreIDs( $this->mDoubleUnderscoreIDs );
$this->mDoubleUnderscoreArray = $this->newArray( $this->mDoubleUnderscoreIDs );
}
return $this->mDoubleUnderscoreArray;

View file

@ -21,6 +21,7 @@
*/
use Liuggio\StatsdClient\Sender\SocketSender;
use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
use MediaWiki\Logger\LoggerFactory;
use MediaWiki\MediaWikiServices;
use Psr\Log\LoggerInterface;
@ -33,6 +34,8 @@ use Wikimedia\Rdbms\ILBFactory;
* The MediaWiki class is the helper class for the index.php entry point.
*/
class MediaWiki {
use ProtectedHookAccessorTrait;
/** @var IContextSource */
private $context;
/** @var Config */
@ -184,8 +187,7 @@ class MediaWiki {
$output->setPrintable();
}
$unused = null; // To pass it by reference
Hooks::run( 'BeforeInitialize', [ &$title, &$unused, &$output, &$user, $request, $this ] );
$this->getHookRunner()->onBeforeInitialize( $title, null, $output, $user, $request, $this );
// Invalid titles. T23776: The interwikis must redirect even if the page name is empty.
if ( $title === null || ( $title->getDBkey() == '' && !$title->isExternal() )
@ -345,7 +347,7 @@ class MediaWiki {
|| ( $request->getCheck( 'title' )
&& $title->getPrefixedDBkey() == $request->getVal( 'title' ) )
|| count( $request->getValueNames( [ 'action', 'title' ] ) )
|| !Hooks::run( 'TestCanonicalRedirect', [ $request, $title, $output ] )
|| !$this->getHookRunner()->onTestCanonicalRedirect( $request, $title, $output )
) {
return false;
}
@ -439,8 +441,8 @@ class MediaWiki {
// Give extensions a change to ignore/handle redirects as needed
$ignoreRedirect = $target = false;
Hooks::run( 'InitializeArticleMaybeRedirect',
[ &$title, &$request, &$ignoreRedirect, &$target, &$article ] );
$this->getHookRunner()->onInitializeArticleMaybeRedirect( $title, $request,
$ignoreRedirect, $target, $article );
$page = $article->getPage(); // reflect any hook changes
// Follow redirects only for... redirects.
@ -487,8 +489,8 @@ class MediaWiki {
$title = $this->context->getTitle();
$user = $this->context->getUser();
if ( !Hooks::run( 'MediaWikiPerformAction',
[ $output, $article, $title, $user, $request, $this ] )
if ( !$this->getHookRunner()->onMediaWikiPerformAction(
$output, $article, $title, $user, $request, $this )
) {
return;
}
@ -931,7 +933,7 @@ class MediaWiki {
$redirUrl = preg_replace( '#^http://#', 'https://', $oldUrl );
// ATTENTION: This hook is likely to be removed soon due to overall design of the system.
if ( Hooks::run( 'BeforeHttpsRedirect', [ $this->context, &$redirUrl ] ) ) {
if ( $this->getHookRunner()->onBeforeHttpsRedirect( $this->context, $redirUrl ) ) {
if ( $request->wasPosted() ) {
// This is weird and we'd hope it almost never happens. This
// means that a POST came in via HTTP and policy requires us

View file

@ -16,7 +16,6 @@ use ExternalStoreFactory;
use FileBackendGroup;
use GenderCache;
use GlobalVarConfig;
use Hooks;
use HtmlCacheUpdater;
use IBufferingStatsdDataFactory;
use JobRunner;
@ -37,6 +36,7 @@ use MediaWiki\EditPage\SpamChecker;
use MediaWiki\FileBackend\FSFile\TempFSFileFactory;
use MediaWiki\FileBackend\LockManager\LockManagerGroupFactory;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\Http\HttpRequestFactory;
use MediaWiki\Interwiki\InterwikiLookup;
use MediaWiki\Languages\LanguageConverterFactory;
@ -183,7 +183,8 @@ class MediaWikiServices extends ServiceContainer {
// Provides a traditional hook point to allow extensions to configure services.
// NOTE: Ideally this would be in newInstance() but it causes an infinite run loop
Hooks::run( 'MediaWikiServices', [ self::$instance ] );
$runner = new HookRunner( self::$instance->getHookContainer() );
$runner->onMediaWikiServices( self::$instance );
}
return self::$instance;
}
@ -268,7 +269,8 @@ class MediaWikiServices extends ServiceContainer {
self::$instance = self::newInstance( $bootstrapConfig, 'load' );
// Provides a traditional hook point to allow extensions to configure services.
Hooks::run( 'MediaWikiServices', [ self::$instance ] );
$runner = new HookRunner( self::$instance->getHookContainer() );
$runner->onMediaWikiServices( self::$instance );
self::$instance->importWiring( $oldInstance, [ 'BootstrapConfig' ] );

View file

@ -431,7 +431,7 @@ class MergeHistory {
$logId = $logEntry->insert();
$logEntry->publish( $logId );
Hooks::run( 'ArticleMergeComplete', [ $this->source, $this->dest ] );
Hooks::runner()->onArticleMergeComplete( $this->source, $this->dest );
$this->dbw->endAtomic( __METHOD__ );

View file

@ -22,6 +22,8 @@
use MediaWiki\Config\ServiceOptions;
use MediaWiki\Content\IContentHandlerFactory;
use MediaWiki\EditPage\SpamChecker;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\MediaWikiServices;
use MediaWiki\Permissions\PermissionManager;
use MediaWiki\Revision\MutableRevisionRecord;
@ -94,6 +96,11 @@ class MovePage {
*/
private $spamChecker;
/**
* @var HookRunner
*/
private $hookRunner;
public const CONSTRUCTOR_OPTIONS = [
'CategoryCollation'
];
@ -112,6 +119,7 @@ class MovePage {
* @param IContentHandlerFactory|null $contentHandlerFactory
* @param RevisionStore|null $revisionStore
* @param SpamChecker|null $spamChecker
* @param HookContainer|null $hookContainer
*/
public function __construct(
Title $oldTitle,
@ -124,7 +132,8 @@ class MovePage {
RepoGroup $repoGroup = null,
IContentHandlerFactory $contentHandlerFactory = null,
RevisionStore $revisionStore = null,
SpamChecker $spamChecker = null
SpamChecker $spamChecker = null,
HookContainer $hookContainer = null
) {
$this->oldTitle = $oldTitle;
$this->newTitle = $newTitle;
@ -145,6 +154,8 @@ class MovePage {
$this->revisionStore = $revisionStore ?? $services->getRevisionStore();
$this->spamChecker = $spamChecker ?? $services->getSpamChecker();
$this->hookRunner = new HookRunner(
$hookContainer ?? $services->getHookContainer() );
}
/**
@ -183,9 +194,8 @@ class MovePage {
$status->fatal( 'cantmove-titleprotected' );
}
Hooks::run( 'MovePageCheckPermissions',
[ $this->oldTitle, $this->newTitle, $user, $reason, $status ]
);
$this->hookRunner->onMovePageCheckPermissions(
$this->oldTitle, $this->newTitle, $user, $reason, $status );
return $status;
}
@ -262,7 +272,7 @@ class MovePage {
}
// Hook for extensions to say a title can't be moved for technical reasons
Hooks::run( 'MovePageIsValidMove', [ $this->oldTitle, $this->newTitle, $status ] );
$this->hookRunner->onMovePageIsValidMove( $this->oldTitle, $this->newTitle, $status );
return $status;
}
@ -540,7 +550,7 @@ class MovePage {
*/
private function moveUnsafe( User $user, $reason, $createRedirect, array $changeTags ) {
$status = Status::newGood();
Hooks::run( 'TitleMove', [ $this->oldTitle, $this->newTitle, $user, $reason, &$status ] );
$this->hookRunner->onTitleMove( $this->oldTitle, $this->newTitle, $user, $reason, $status );
if ( !$status->isOK() ) {
// Move was aborted by the hook
return $status;
@ -549,7 +559,7 @@ class MovePage {
$dbw = $this->loadBalancer->getConnection( DB_MASTER );
$dbw->startAtomic( __METHOD__, IDatabase::ATOMIC_CANCELABLE );
Hooks::run( 'TitleMoveStarting', [ $this->oldTitle, $this->newTitle, $user ] );
$this->hookRunner->onTitleMoveStarting( $this->oldTitle, $this->newTitle, $user );
$pageid = $this->oldTitle->getArticleID( Title::READ_LATEST );
$protected = $this->oldTitle->isProtected();
@ -685,11 +695,9 @@ class MovePage {
}
$nullRevisionObj = new Revision( $nullRevision );
Hooks::run(
'TitleMoveCompleting',
[ $this->oldTitle, $this->newTitle,
$user, $pageid, $redirid, $reason, $nullRevisionObj ]
);
$this->hookRunner->onTitleMoveCompleting(
$this->oldTitle, $this->newTitle,
$user, $pageid, $redirid, $reason, $nullRevisionObj );
$dbw->endAtomic( __METHOD__ );
@ -699,15 +707,13 @@ class MovePage {
$dbw,
__METHOD__,
function () use ( $user, $pageid, $redirid, $reason, $nullRevisionObj ) {
Hooks::run( 'TitleMoveComplete', [
&$this->oldTitle,
&$this->newTitle,
&$user,
$pageid,
$this->hookRunner->onTitleMoveComplete(
$this->oldTitle,
$this->newTitle,
$user, $pageid,
$redirid,
$reason,
$nullRevisionObj
] );
$nullRevisionObj );
}
)
);
@ -890,13 +896,13 @@ class MovePage {
// TODO cleanup hooks and use of $nullRevisionObj
$nullRevisionObj = new Revision( $nullRevision );
$fakeTags = [];
Hooks::run( 'RevisionFromEditComplete',
[ $newpage, $nullRevision, $nullRevision->getParentId(), $user, &$fakeTags ] );
$this->hookRunner->onRevisionFromEditComplete(
$newpage, $nullRevision, $nullRevision->getParentId(), $user, $fakeTags );
// TODO hard deprecate hook
$nullRevisionObj = new Revision( $nullRevision );
Hooks::run( 'NewRevisionFromEditComplete',
[ $newpage, $nullRevisionObj, $nullRevision->getParentId(), $user, &$fakeTags ] );
$this->hookRunner->onNewRevisionFromEditComplete(
$newpage, $nullRevisionObj, $nullRevision->getParentId(), $user, $fakeTags );
$newpage->doEditUpdates( $nullRevisionObj, $user,
[ 'changed' => false, 'moved' => true, 'oldcountable' => $oldcountable ] );
@ -925,18 +931,18 @@ class MovePage {
$redirectArticle->updateRevisionOn( $dbw, $inserted, 0 );
$fakeTags = [];
Hooks::run( 'RevisionFromEditComplete', [
$this->hookRunner->onRevisionFromEditComplete(
$redirectArticle,
$inserted,
false,
$user,
&$fakeTags
] );
$fakeTags
);
// TODO hard deprecate hook
$redirectRevisionObj = new Revision( $inserted );
Hooks::run( 'NewRevisionFromEditComplete',
[ $redirectArticle, $redirectRevisionObj, false, $user, &$fakeTags ] );
$this->hookRunner->onNewRevisionFromEditComplete(
$redirectArticle, $redirectRevisionObj, false, $user, $fakeTags );
// TODO WikiPage::doEditUpdates is deprecated
$redirectArticle->doEditUpdates(

View file

@ -20,6 +20,7 @@
* @file
*/
use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
use MediaWiki\Linker\LinkTarget;
use MediaWiki\MediaWikiServices;
use MediaWiki\Session\SessionManager;
@ -44,6 +45,8 @@ use Wikimedia\WrappedStringList;
* @todo document
*/
class OutputPage extends ContextSource {
use ProtectedHookAccessorTrait;
/** @var string[][] Should be private. Used with addMeta() which adds "<meta>" */
protected $mMetatags = [];
@ -345,7 +348,8 @@ class OutputPage extends ContextSource {
$this->setContext( $context );
$this->CSP = new ContentSecurityPolicy(
$context->getRequest()->response(),
$context->getConfig()
$context->getConfig(),
$this->getHookContainer()
);
}
@ -772,7 +776,7 @@ class OutputPage extends ContextSource {
$config->get( 'CdnMaxAge' )
) );
}
Hooks::run( 'OutputPageCheckLastModified', [ &$modifiedTimes, $this ] );
$this->getHookRunner()->onOutputPageCheckLastModified( $modifiedTimes, $this );
$maxModified = max( $modifiedTimes );
$this->mLastModified = wfTimestamp( TS_RFC2822, $maxModified );
@ -1377,12 +1381,9 @@ class OutputPage extends ContextSource {
}
}
// Avoid PHP 7.1 warning of passing $this by reference
$outputPage = $this;
# Add the remaining categories to the skin
if ( Hooks::run(
'OutputPageMakeCategoryLinks',
[ &$outputPage, $categories, &$this->mCategoryLinks ] )
if ( $this->getHookRunner()->onOutputPageMakeCategoryLinks(
$this, $categories, $this->mCategoryLinks )
) {
$services = MediaWikiServices::getInstance();
$linkRenderer = $services->getLinkRenderer();
@ -1964,10 +1965,8 @@ class OutputPage extends ContextSource {
// Link flags are ignored for now, but may in the future be
// used to mark individual language links.
$linkFlags = [];
// Avoid PHP 7.1 warning of passing $this by reference
$outputPage = $this;
Hooks::run( 'LanguageLinks', [ $this->getTitle(), &$this->mLanguageLinks, &$linkFlags ] );
Hooks::runWithoutAbort( 'OutputPageParserOutput', [ &$outputPage, $parserOutput ] );
$this->getHookRunner()->onLanguageLinks( $this->getTitle(), $this->mLanguageLinks, $linkFlags );
$this->getHookRunner()->onOutputPageParserOutput( $this, $parserOutput );
// This check must be after 'OutputPageParserOutput' runs in addParserOutputMetadata
// so that extensions may modify ParserOutput to toggle TOC.
@ -2004,9 +2003,7 @@ class OutputPage extends ContextSource {
*/
public function addParserOutputText( ParserOutput $parserOutput, $poOptions = [] ) {
$text = $parserOutput->getText( $poOptions );
// Avoid PHP 7.1 warning of passing $this by reference
$outputPage = $this;
Hooks::runWithoutAbort( 'OutputPageBeforeHTML', [ &$outputPage, &$text ] );
$this->getHookRunner()->onOutputPageBeforeHTML( $this, $text );
$this->addHTML( $text );
}
@ -2231,7 +2228,7 @@ class OutputPage extends ContextSource {
],
$config->get( 'CacheVaryCookies' )
) ) );
Hooks::run( 'GetCacheVaryCookies', [ $this, &self::$cacheVaryCookies ] );
$this->getHookRunner()->onGetCacheVaryCookies( $this, self::$cacheVaryCookies );
}
return self::$cacheVaryCookies;
}
@ -2532,7 +2529,7 @@ class OutputPage extends ContextSource {
$redirect = $this->mRedirect;
$code = $this->mRedirectCode;
if ( Hooks::run( "BeforePageRedirect", [ $this, &$redirect, &$code ] ) ) {
if ( $this->getHookRunner()->onBeforePageRedirect( $this, $redirect, $code ) ) {
if ( $code == '301' || $code == '303' ) {
if ( !$config->get( 'DebugRedirects' ) ) {
$response->statusHeader( $code );
@ -2607,11 +2604,9 @@ class OutputPage extends ContextSource {
MWDebug::addModules( $this );
// Avoid PHP 7.1 warning of passing $this by reference
$outputPage = $this;
// Hook that allows last minute changes to the output page, e.g.
// adding of CSS or Javascript by extensions, adding CSP sources.
Hooks::runWithoutAbort( 'BeforePageDisplay', [ &$outputPage, &$sk ] );
$this->getHookRunner()->onBeforePageDisplay( $this, $sk );
$this->CSP->sendHeaders();
@ -2625,7 +2620,7 @@ class OutputPage extends ContextSource {
try {
// This hook allows last minute changes to final overall output by modifying output buffer
Hooks::runWithoutAbort( 'AfterFinalPageOutput', [ $this ] );
$this->getHookRunner()->onAfterFinalPageOutput( $this );
} catch ( Exception $e ) {
ob_end_clean(); // bug T129657
throw $e;
@ -3134,7 +3129,7 @@ class OutputPage extends ContextSource {
// Allow skins and extensions to add body attributes they need
$sk->addToBodyAttributes( $this, $bodyAttrs );
Hooks::run( 'OutputPageBodyAttributes', [ $this, $sk, &$bodyAttrs ] );
$this->getHookRunner()->onOutputPageBodyAttributes( $this, $sk, $bodyAttrs );
$pieces[] = Html::openElement( 'body', $bodyAttrs );
@ -3379,7 +3374,7 @@ class OutputPage extends ContextSource {
// Use the 'ResourceLoaderGetConfigVars' hook if the variable is not
// page-dependant but site-wide (without state).
// Alternatively, you may want to use OutputPage->addJsConfigVars() instead.
Hooks::run( 'MakeGlobalVariablesScript', [ &$vars, $this ] );
$this->getHookRunner()->onMakeGlobalVariablesScript( $vars, $this );
// Merge in variables from addJsConfigVars last
return array_merge( $vars, $this->getJsConfigVars() );
@ -3661,7 +3656,7 @@ class OutputPage extends ContextSource {
# Allow extensions to change the list pf feeds. This hook is primarily for changing,
# manipulating or removing existing feed tags. If you want to add new feeds, you should
# use OutputPage::addFeedLink() instead.
Hooks::run( 'AfterBuildFeedLinks', [ &$feedLinks ] );
$this->getHookRunner()->onAfterBuildFeedLinks( $feedLinks );
$tags += $feedLinks;
}
@ -3702,7 +3697,7 @@ class OutputPage extends ContextSource {
// (or addHeadItems() for multiple items) method instead.
// This hook is provided as a last resort for extensions to modify these
// links before the output is sent to client.
Hooks::run( 'OutputPageAfterGetHeadLinksArray', [ &$tags, $this ] );
$this->getHookRunner()->onOutputPageAfterGetHeadLinksArray( $tags, $this );
return $tags;
}

View file

@ -22,9 +22,10 @@ namespace MediaWiki\Permissions;
use Action;
use Article;
use Exception;
use Hooks;
use MediaWiki\Block\BlockErrorFormatter;
use MediaWiki\Config\ServiceOptions;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\Linker\LinkTarget;
use MediaWiki\Revision\RevisionLookup;
use MediaWiki\Revision\RevisionRecord;
@ -90,6 +91,9 @@ class PermissionManager {
/** @var BlockErrorFormatter */
private $blockErrorFormatter;
/** @var HookRunner */
private $hookRunner;
/** @var string[][] Cached user rights */
private $usersRights = null;
@ -197,13 +201,15 @@ class PermissionManager {
* @param RevisionLookup $revisionLookup
* @param NamespaceInfo $nsInfo
* @param BlockErrorFormatter $blockErrorFormatter
* @param HookContainer $hookContainer
*/
public function __construct(
ServiceOptions $options,
SpecialPageFactory $specialPageFactory,
RevisionLookup $revisionLookup,
NamespaceInfo $nsInfo,
BlockErrorFormatter $blockErrorFormatter
BlockErrorFormatter $blockErrorFormatter,
HookContainer $hookContainer
) {
$options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
$this->options = $options;
@ -211,6 +217,7 @@ class PermissionManager {
$this->revisionLookup = $revisionLookup;
$this->nsInfo = $nsInfo;
$this->blockErrorFormatter = $blockErrorFormatter;
$this->hookRunner = new HookRunner( $hookContainer );
}
/**
@ -330,7 +337,7 @@ class PermissionManager {
$allowUsertalk = $user->isAllowUsertalk();
// Allow extensions to let a blocked user access a particular page
Hooks::run( 'UserIsBlockedFrom', [ $user, $title, &$blocked, &$allowUsertalk ] );
$this->hookRunner->onUserIsBlockedFrom( $user, $title, $blocked, $allowUsertalk );
return $blocked;
}
@ -437,18 +444,19 @@ class PermissionManager {
$title = Title::newFromLinkTarget( $page );
// Use getUserPermissionsErrors instead
$result = '';
if ( !Hooks::run( 'userCan', [ &$title, &$user, $action, &$result ] ) ) {
if ( !$this->hookRunner->onUserCan( $title, $user, $action, $result ) ) {
return $result ? [] : [ [ 'badaccess-group0' ] ];
}
// Check getUserPermissionsErrors hook
if ( !Hooks::run( 'getUserPermissionsErrors', [ &$title, &$user, $action, &$result ] ) ) {
if ( !$this->hookRunner->onGetUserPermissionsErrors( $title, $user, $action, $result ) ) {
$errors = $this->resultToError( $errors, $result );
}
// Check getUserPermissionsErrorsExpensive hook
if (
$rigor !== self::RIGOR_QUICK
&& !( $short && count( $errors ) > 0 )
&& !Hooks::run( 'getUserPermissionsErrorsExpensive', [ &$title, &$user, $action, &$result ] )
&& !$this->hookRunner->onGetUserPermissionsErrorsExpensive(
$title, $user, $action, $result )
) {
$errors = $this->resultToError( $errors, $result );
}
@ -571,7 +579,7 @@ class PermissionManager {
if ( !$whitelisted ) {
# If the title is not whitelisted, give extensions a chance to do so...
Hooks::run( 'TitleReadWhitelist', [ $title, $user, &$whitelisted ] );
$this->hookRunner->onTitleReadWhitelist( $title, $user, $whitelisted );
if ( !$whitelisted ) {
$errors[] = $this->missingPermissionError( $action, $short );
}
@ -742,8 +750,8 @@ class PermissionManager {
// TODO: remove when LinkTarget usage will expand further
$title = Title::newFromLinkTarget( $page );
if ( !Hooks::run( 'TitleQuickPermissions',
[ $title, $user, $action, &$errors, ( $rigor !== self::RIGOR_QUICK ), $short ] )
if ( !$this->hookRunner->onTitleQuickPermissions( $title, $user, $action,
$errors, $rigor !== self::RIGOR_QUICK, $short )
) {
return $errors;
}
@ -1282,7 +1290,7 @@ class PermissionManager {
$this->usersRights[ $rightsCacheKey ] = $this->getGroupPermissions(
$user->getEffectiveGroups()
);
Hooks::run( 'UserGetRights', [ $user, &$this->usersRights[ $rightsCacheKey ] ] );
$this->hookRunner->onUserGetRights( $user, $this->usersRights[ $rightsCacheKey ] );
// Deny any rights denied by the user's session, unless this
// endpoint has no sessions.
@ -1297,7 +1305,8 @@ class PermissionManager {
}
}
Hooks::run( 'UserGetRightsRemove', [ $user, &$this->usersRights[ $rightsCacheKey ] ] );
$this->hookRunner->onUserGetRightsRemove(
$user, $this->usersRights[ $rightsCacheKey ] );
// Force reindexation of rights when a hook has unset one of them
$this->usersRights[ $rightsCacheKey ] = array_values(
array_unique( $this->usersRights[ $rightsCacheKey ] )
@ -1466,7 +1475,7 @@ class PermissionManager {
}
// Allow extensions to say false
if ( !Hooks::run( 'UserIsEveryoneAllowed', [ $right ] ) ) {
if ( !$this->hookRunner->onUserIsEveryoneAllowed( $right ) ) {
$this->cachedRights[$right] = false;
return false;
}
@ -1492,7 +1501,7 @@ class PermissionManager {
} else {
$this->allRights = $this->coreRights;
}
Hooks::run( 'UserGetAllRights', [ &$this->allRights ] );
$this->hookRunner->onUserGetAllRights( $this->allRights );
}
return $this->allRights;
}

View file

@ -22,6 +22,8 @@
*
* @file
*/
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\MediaWikiServices;
use MediaWiki\Permissions\PermissionManager;
@ -77,6 +79,9 @@ class ProtectionForm {
/** @var PermissionManager */
private $permManager;
/** @var HookRunner */
private $hookRunner;
public function __construct( Article $article ) {
// Set instance variables.
$this->mArticle = $article;
@ -84,7 +89,9 @@ class ProtectionForm {
$this->mApplicableTypes = $this->mTitle->getRestrictionTypes();
$this->mContext = $article->getContext();
$this->permManager = MediaWikiServices::getInstance()->getPermissionManager();
$services = MediaWikiServices::getInstance();
$this->permManager = $services->getPermissionManager();
$this->hookRunner = new HookRunner( $services->getHookContainer() );
// Check if the form should be disabled.
// If it is, the form will be available in read-only to show levels.
@ -356,7 +363,7 @@ class ProtectionForm {
* you can also return an array of message name and its parameters
*/
$errorMsg = '';
if ( !Hooks::run( 'ProtectionForm::save', [ $this->mArticle, &$errorMsg, $reasonstr ] ) ) {
if ( !$this->hookRunner->onProtectionForm__save( $this->mArticle, $errorMsg, $reasonstr ) ) {
if ( $errorMsg == '' ) {
$errorMsg = [ 'hookaborted' ];
}
@ -478,7 +485,7 @@ class ProtectionForm {
"</td></tr>";
}
# Give extensions a chance to add items to the form
Hooks::run( 'ProtectionForm::buildForm', [ $this->mArticle, &$out ] );
$this->hookRunner->onProtectionForm__buildForm( $this->mArticle, $out );
$out .= Xml::closeElement( 'tbody' ) . Xml::closeElement( 'table' );
@ -656,6 +663,6 @@ class ProtectionForm {
$out->addHTML( Xml::element( 'h2', null, $protectLogPage->getName()->text() ) );
LogEventsList::showLogExtract( $out, 'protect', $this->mTitle );
# Let extensions add other relevant log extracts
Hooks::run( 'ProtectionForm::showLogExtract', [ $this->mArticle, $out ] );
$this->hookRunner->onProtectionForm__showLogExtract( $this->mArticle, $out );
}
}

View file

@ -79,7 +79,7 @@ class ProxyLookup {
*/
public function isTrustedProxy( $ip ) {
$trusted = $this->isConfiguredProxy( $ip );
Hooks::run( 'IsTrustedProxy', [ &$ip, &$trusted ] );
Hooks::runner()->onIsTrustedProxy( $ip, $trusted );
return $trusted;
}
}

View file

@ -67,7 +67,8 @@ class EntryPoint {
$responseFactory,
$authorizer,
$objectFactory,
$restValidator
$restValidator,
$services->getHookContainer()
);
}

View file

@ -2,6 +2,8 @@
namespace MediaWiki\Rest;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\Rest\Validator\BodyValidator;
use MediaWiki\Rest\Validator\NullBodyValidator;
use MediaWiki\Rest\Validator\Validator;
@ -35,6 +37,12 @@ abstract class Handler {
/** @var ConditionalHeaderUtil */
private $conditionalHeaderUtil;
/** @var HookContainer */
private $hookContainer;
/** @var HookRunner */
private $hookRunner;
/**
* Initialise with dependencies from the Router. This is called after construction.
* @internal
@ -42,14 +50,17 @@ abstract class Handler {
* @param RequestInterface $request
* @param array $config
* @param ResponseFactory $responseFactory
* @param HookContainer $hookContainer
*/
final public function init( Router $router, RequestInterface $request, array $config,
ResponseFactory $responseFactory
ResponseFactory $responseFactory, HookContainer $hookContainer
) {
$this->router = $router;
$this->request = $request;
$this->config = $config;
$this->responseFactory = $responseFactory;
$this->hookContainer = $hookContainer;
$this->hookRunner = new HookRunner( $hookContainer );
$this->postInitSetup();
}
@ -202,6 +213,28 @@ abstract class Handler {
return $this->validatedBody;
}
/**
* Get a HookContainer, for running extension hooks or for hook metadata.
*
* @since 1.35
* @return HookContainer
*/
protected function getHookContainer() {
return $this->hookContainer;
}
/**
* Get a HookRunner for running core hooks.
*
* @internal This is for use by core only. Hook interfaces may be removed
* without notice.
* @since 1.35
* @return HookRunner
*/
protected function getHookRunner() {
return $this->hookRunner;
}
/**
* The subclass should override this to provide the maximum last modified
* timestamp for the current request. This is called before execute() in

View file

@ -3,7 +3,6 @@
namespace MediaWiki\Rest\Handler;
use Config;
use Hooks;
use InvalidArgumentException;
use ISearchResultSet;
use MediaWiki\Permissions\PermissionManager;
@ -290,7 +289,7 @@ class SearchHandler extends Handler {
private function buildDescriptionsFromPageIdentities( array $pageIdentities ) {
$descriptions = array_fill_keys( array_keys( $pageIdentities ), null );
Hooks::run( 'SearchResultProvideDescription', [ $pageIdentities, &$descriptions ] );
$this->getHookRunner()->onSearchResultProvideDescription( $pageIdentities, $descriptions );
return array_map( function ( $description ) {
return [ 'description' => $description ];
@ -311,7 +310,7 @@ class SearchHandler extends Handler {
private function buildThumbnailsFromPageIdentities( array $pageIdentities ) {
$thumbnails = array_fill_keys( array_keys( $pageIdentities ), null );
Hooks::run( 'SearchResultProvideThumbnail', [ $pageIdentities, &$thumbnails ] );
$this->getHookRunner()->onSearchResultProvideThumbnail( $pageIdentities, $thumbnails );
return array_map( function ( $thumbnail ) {
return [ 'thumbnail' => $this->serializeThumbnail( $thumbnail ) ];

View file

@ -5,6 +5,8 @@ namespace MediaWiki\Rest;
use AppendIterator;
use BagOStuff;
use GuzzleHttp\Psr7\Uri;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\MediaWikiServices;
use MediaWiki\Rest\BasicAccess\BasicAuthorizerInterface;
use MediaWiki\Rest\PathTemplateMatcher\PathMatcher;
use MediaWiki\Rest\Validator\Validator;
@ -56,6 +58,9 @@ class Router {
/** @var Validator */
private $restValidator;
/** @var HookContainer */
private $hookContainer;
/**
* @internal
* @param string[] $routeFiles List of names of JSON files containing routes
@ -67,11 +72,12 @@ class Router {
* @param BasicAuthorizerInterface $basicAuth
* @param ObjectFactory $objectFactory
* @param Validator $restValidator
* @param HookContainer|null $hookContainer
*/
public function __construct( $routeFiles, $extraRoutes, $baseUrl, $rootPath,
BagOStuff $cacheBag, ResponseFactory $responseFactory,
BasicAuthorizerInterface $basicAuth, ObjectFactory $objectFactory,
Validator $restValidator
Validator $restValidator, HookContainer $hookContainer = null
) {
$this->routeFiles = $routeFiles;
$this->extraRoutes = $extraRoutes;
@ -82,6 +88,12 @@ class Router {
$this->basicAuth = $basicAuth;
$this->objectFactory = $objectFactory;
$this->restValidator = $restValidator;
if ( !$hookContainer ) {
// b/c for OAuth extension
$hookContainer = MediaWikiServices::getInstance()->getHookContainer();
}
$this->hookContainer = $hookContainer;
}
/**
@ -322,7 +334,7 @@ class Router {
[ 'factory' => true, 'class' => true, 'args' => true, 'services' => true ] );
/** @var $handler Handler (annotation for PHPStorm) */
$handler = $this->objectFactory->createObject( $objectFactorySpec );
$handler->init( $this, $request, $spec, $this->responseFactory );
$handler->init( $this, $request, $spec, $this->responseFactory, $this->hookContainer );
return $handler;
}

View file

@ -99,7 +99,7 @@ class MainSlotRoleHandler extends SlotRoleHandler {
// Hook can determine default model
$title = Title::newFromLinkTarget( $page );
if ( !Hooks::run( 'ContentHandlerDefaultModelFor', [ $title, &$model ] ) && $model !== null ) {
if ( !Hooks::runner()->onContentHandlerDefaultModelFor( $title, $model ) && $model !== null ) {
return $model;
}

View file

@ -32,10 +32,11 @@ use CommentStoreComment;
use Content;
use ContentHandler;
use DBAccessObjectUtils;
use Hooks;
use IDBAccessObject;
use InvalidArgumentException;
use MediaWiki\Content\IContentHandlerFactory;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\Linker\LinkTarget;
use MediaWiki\Storage\BlobAccessException;
use MediaWiki\Storage\BlobStore;
@ -131,6 +132,9 @@ class RevisionStore
/** @var IContentHandlerFactory */
private $contentHandlerFactory;
/** @var HookRunner */
private $hookRunner;
/**
* @todo $blobStore should be allowed to be any BlobStore!
*
@ -148,6 +152,7 @@ class RevisionStore
* @param SlotRoleRegistry $slotRoleRegistry
* @param ActorMigration $actorMigration
* @param IContentHandlerFactory $contentHandlerFactory
* @param HookContainer $hookContainer
* @param bool|string $dbDomain DB domain of the relevant wiki or false for the current one
*/
public function __construct(
@ -160,6 +165,7 @@ class RevisionStore
SlotRoleRegistry $slotRoleRegistry,
ActorMigration $actorMigration,
IContentHandlerFactory $contentHandlerFactory,
HookContainer $hookContainer,
$dbDomain = false
) {
Assert::parameterType( 'string|boolean', $dbDomain, '$dbDomain' );
@ -175,6 +181,7 @@ class RevisionStore
$this->dbDomain = $dbDomain;
$this->logger = new NullLogger();
$this->contentHandlerFactory = $contentHandlerFactory;
$this->hookRunner = new HookRunner( $hookContainer );
}
public function setLogger( LoggerInterface $logger ) {
@ -446,11 +453,11 @@ class RevisionStore
);
}
Hooks::run( 'RevisionRecordInserted', [ $rev ] );
$this->hookRunner->onRevisionRecordInserted( $rev );
// Soft deprecated in 1.31, hard deprecated in 1.35
$legacyRevision = new Revision( $rev );
Hooks::run( 'RevisionInsertComplete', [ &$legacyRevision, null, null ], '1.31' );
$this->hookRunner->onRevisionInsertComplete( $legacyRevision, null, null );
return $rev;
}

View file

@ -28,6 +28,7 @@ namespace MediaWiki\Revision;
use ActorMigration;
use CommentStore;
use MediaWiki\Content\IContentHandlerFactory;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\Storage\BlobStoreFactory;
use MediaWiki\Storage\NameTableStoreFactory;
use Psr\Log\LoggerInterface;
@ -72,6 +73,9 @@ class RevisionStoreFactory {
/** @var IContentHandlerFactory */
private $contentHandlerFactory;
/** @var HookContainer */
private $hookContainer;
/**
* @param ILBFactory $dbLoadBalancerFactory
* @param BlobStoreFactory $blobStoreFactory
@ -82,6 +86,7 @@ class RevisionStoreFactory {
* @param ActorMigration $actorMigration
* @param LoggerInterface $logger
* @param IContentHandlerFactory $contentHandlerFactory
* @param HookContainer $hookContainer
*/
public function __construct(
ILBFactory $dbLoadBalancerFactory,
@ -92,7 +97,8 @@ class RevisionStoreFactory {
CommentStore $commentStore,
ActorMigration $actorMigration,
LoggerInterface $logger,
IContentHandlerFactory $contentHandlerFactory
IContentHandlerFactory $contentHandlerFactory,
HookContainer $hookContainer
) {
$this->dbLoadBalancerFactory = $dbLoadBalancerFactory;
$this->blobStoreFactory = $blobStoreFactory;
@ -103,6 +109,7 @@ class RevisionStoreFactory {
$this->actorMigration = $actorMigration;
$this->logger = $logger;
$this->contentHandlerFactory = $contentHandlerFactory;
$this->hookContainer = $hookContainer;
}
/**
@ -125,6 +132,7 @@ class RevisionStoreFactory {
$this->slotRoleRegistry,
$this->actorMigration,
$this->contentHandlerFactory,
$this->hookContainer,
$dbDomain
);

View file

@ -27,7 +27,7 @@ use MediaWiki\Linker\LinkTarget;
/**
* SlotRoleHandler instances are used to declare the existence and behavior of slot roles.
* Most importantly, they control which content model can be used for the slot, and how it is
* represented in the rendered verswion of page content.
* represented in the rendered version of page content.
*
* @since 1.33
*/

View file

@ -61,6 +61,7 @@ use MediaWiki\FileBackend\LockManager\LockManagerGroupFactory;
use MediaWiki\HookContainer\DeprecatedHooks;
use MediaWiki\HookContainer\GlobalHookRegistry;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\Http\HttpRequestFactory;
use MediaWiki\Interwiki\ClassicInterwikiLookup;
use MediaWiki\Interwiki\InterwikiLookup;
@ -118,7 +119,8 @@ return [
RequestContext::getMain()->getRequest(),
$services->getMainConfig(),
$services->getObjectFactory(),
$services->getPermissionManager()
$services->getPermissionManager(),
$services->getHookContainer()
);
$authManager->setLogger( LoggerFactory::getInstance( 'authentication' ) );
return $authManager;
@ -131,7 +133,8 @@ return [
},
$services->getLocalServerObjectCache(),
$services->getRepoGroup(),
$services->getTitleParser()
$services->getTitleParser(),
$services->getHookContainer()
);
},
@ -159,7 +162,8 @@ return [
BlockManager::CONSTRUCTOR_OPTIONS, $services->getMainConfig()
),
$services->getPermissionManager(),
LoggerFactory::getInstance( 'BlockManager' )
LoggerFactory::getInstance( 'BlockManager' ),
$services->getHookContainer()
);
},
@ -208,7 +212,8 @@ return [
return new ContentHandlerFactory(
$contentHandlerConfig,
$services->getObjectFactory()
$services->getObjectFactory(),
$services->getHookContainer()
);
},
@ -392,6 +397,7 @@ return [
$config = $services->getMainConfig();
return new HtmlCacheUpdater(
$services->getHookContainer(),
$config->get( 'CdnReboundPurgeDelay' ),
$config->get( 'UseFileCache' ),
$config->get( 'CdnMaxAge' )
@ -414,6 +420,7 @@ return [
return new ClassicInterwikiLookup(
$services->getContentLanguage(),
$services->getMainWANObjectCache(),
$services->getHookContainer(),
$config->get( 'InterwikiExpiry' ),
$config->get( 'InterwikiCache' ),
$config->get( 'InterwikiScopes' ),
@ -446,7 +453,8 @@ return [
$services->getLocalisationCache(),
$services->getLanguageNameUtils(),
$services->getLanguageFallback(),
$services->getLanguageConverterFactory()
$services->getLanguageConverterFactory(),
$services->getHookContainer()
);
},
@ -459,10 +467,13 @@ return [
},
'LanguageNameUtils' => function ( MediaWikiServices $services ) : LanguageNameUtils {
return new LanguageNameUtils( new ServiceOptions(
LanguageNameUtils::CONSTRUCTOR_OPTIONS,
$services->getMainConfig()
) );
return new LanguageNameUtils(
new ServiceOptions(
LanguageNameUtils::CONSTRUCTOR_OPTIONS,
$services->getMainConfig()
),
$services->getHookContainer()
);
},
'LinkBatchFactory' => function ( MediaWikiServices $services ) : LinkBatchFactory {
@ -500,7 +511,8 @@ return [
$services->getTitleFormatter(),
$services->getLinkCache(),
$services->getNamespaceInfo(),
$services->getSpecialPageFactory()
$services->getSpecialPageFactory(),
$services->getHookContainer()
);
},
@ -534,7 +546,8 @@ return [
// T231866: Avoid circular dependency via ResourceLoader.
MessageBlobStore::clearGlobalCacheEntry( $services->getMainWANObjectCache() );
} ],
$services->getLanguageNameUtils()
$services->getLanguageNameUtils(),
$services->getHookContainer()
);
},
@ -551,7 +564,10 @@ return [
},
'MagicWordFactory' => function ( MediaWikiServices $services ) : MagicWordFactory {
return new MagicWordFactory( $services->getContentLanguage() );
return new MagicWordFactory(
$services->getContentLanguage(),
$services->getHookContainer()
);
},
'MainConfig' => function ( MediaWikiServices $services ) : Config {
@ -655,7 +671,8 @@ return [
$services->getLanguageFactory(),
$services->getLocalisationCache(),
$services->getLanguageNameUtils(),
$services->getLanguageFallback()
$services->getLanguageFallback(),
$services->getHookContainer()
);
},
@ -666,12 +683,14 @@ return [
'MimeAnalyzer' => function ( MediaWikiServices $services ) : MimeAnalyzer {
$logger = LoggerFactory::getInstance( 'Mime' );
$mainConfig = $services->getMainConfig();
$hookRunner = new HookRunner( $services->getHookContainer() );
$params = [
'typeFile' => $mainConfig->get( 'MimeTypeFile' ),
'infoFile' => $mainConfig->get( 'MimeInfoFile' ),
'xmlTypes' => $mainConfig->get( 'XMLMimeTypes' ),
'guessCallback' =>
function ( $mimeAnalyzer, &$head, &$tail, $file, &$mime ) use ( $logger ) {
function ( $mimeAnalyzer, &$head, &$tail, $file, &$mime )
use ( $logger, $hookRunner ) {
// Also test DjVu
$deja = new DjVuImage( $file );
if ( $deja->isValid() ) {
@ -681,18 +700,16 @@ return [
return;
}
// Some strings by reference for performance - assuming well-behaved hooks
Hooks::run(
'MimeMagicGuessFromContent',
[ $mimeAnalyzer, &$head, &$tail, $file, &$mime ]
);
$hookRunner->onMimeMagicGuessFromContent(
$mimeAnalyzer, $head, $tail, $file, $mime );
},
'extCallback' => function ( $mimeAnalyzer, $ext, &$mime ) {
'extCallback' => function ( $mimeAnalyzer, $ext, &$mime ) use ( $hookRunner ) {
// Media handling extensions can improve the MIME detected
Hooks::run( 'MimeMagicImproveFromExtension', [ $mimeAnalyzer, $ext, &$mime ] );
$hookRunner->onMimeMagicImproveFromExtension( $mimeAnalyzer, $ext, $mime );
},
'initCallback' => function ( $mimeAnalyzer ) {
'initCallback' => function ( $mimeAnalyzer ) use ( $hookRunner ) {
// Allow media handling extensions adding MIME-types and MIME-info
Hooks::run( 'MimeMagicInit', [ $mimeAnalyzer ] );
$hookRunner->onMimeMagicInit( $mimeAnalyzer );
},
'logger' => $logger
];
@ -726,8 +743,10 @@ return [
},
'NamespaceInfo' => function ( MediaWikiServices $services ) : NamespaceInfo {
return new NamespaceInfo( new ServiceOptions( NamespaceInfo::CONSTRUCTOR_OPTIONS,
$services->getMainConfig() ) );
return new NamespaceInfo(
new ServiceOptions( NamespaceInfo::CONSTRUCTOR_OPTIONS, $services->getMainConfig() ),
$services->getHookContainer()
);
},
'NameTableStoreFactory' => function ( MediaWikiServices $services ) : NameTableStoreFactory {
@ -758,6 +777,7 @@ return [
$services->getDBLoadBalancer(),
LoggerFactory::getInstance( 'StashEdit' ),
$services->getStatsdDataFactory(),
$services->getHookContainer(),
defined( 'MEDIAWIKI_JOB_RUNNER' ) || $config->get( 'CommandLineMode' )
? PageEditStash::INITIATOR_JOB_OR_CLI
: PageEditStash::INITIATOR_USER
@ -775,7 +795,8 @@ return [
return new ParserCache(
$cache,
$config->get( 'CacheEpoch' )
$config->get( 'CacheEpoch' ),
$services->getHookContainer()
);
},
@ -803,7 +824,8 @@ return [
$services->getNamespaceInfo(),
LoggerFactory::getInstance( 'Parser' ),
$services->getBadFileLookup(),
$services->getLanguageConverterFactory()
$services->getLanguageConverterFactory(),
$services->getHookContainer()
);
},
@ -822,7 +844,8 @@ return [
AuthManager::singleton(),
$services->getPermissionManager(),
$services->getDBLoadBalancer(),
LoggerFactory::getInstance( 'authentication' )
LoggerFactory::getInstance( 'authentication' ),
$services->getHookContainer()
);
},
@ -844,7 +867,8 @@ return [
$services->getSpecialPageFactory(),
$services->getRevisionLookup(),
$services->getNamespaceInfo(),
$services->getBlockErrorFormatter()
$services->getBlockErrorFormatter(),
$services->getHookContainer()
);
},
@ -858,7 +882,8 @@ return [
$services->getNamespaceInfo(),
$services->getPermissionManager(),
$services->getLanguageConverterFactory()->getLanguageConverter(),
$services->getLanguageNameUtils()
$services->getLanguageNameUtils(),
$services->getHookContainer()
);
$factory->setLogger( LoggerFactory::getInstance( 'preferences' ) );
@ -916,7 +941,8 @@ return [
// Core modules, then extension/skin modules
$rl->register( include "$IP/resources/Resources.php" );
$rl->register( $modules );
Hooks::run( 'ResourceLoaderRegisterModules', [ &$rl ] );
$hookRunner = new HookRunner( $services->getHookContainer() );
$hookRunner->onResourceLoaderRegisterModules( $rl );
$msgPosterAttrib = $extRegistry->getAttribute( 'MessagePosterModule' );
$rl->register( 'mediawiki.messagePoster', [
@ -990,7 +1016,8 @@ return [
$services->getCommentStore(),
$services->getActorMigration(),
LoggerFactory::getInstance( 'RevisionStore' ),
$services->getContentHandlerFactory()
$services->getContentHandlerFactory(),
$services->getHookContainer()
);
return $store;
@ -1002,12 +1029,16 @@ return [
return new SearchEngineConfig(
$services->getMainConfig(),
$services->getContentLanguage(),
$services->getHookContainer(),
ExtensionRegistry::getInstance()->getAttribute( 'SearchMappings' )
);
},
'SearchEngineFactory' => function ( MediaWikiServices $services ) : SearchEngineFactory {
return new SearchEngineFactory( $services->getSearchEngineConfig() );
return new SearchEngineFactory(
$services->getSearchEngineConfig(),
$services->getHookContainer()
);
},
'ShellCommandFactory' => function ( MediaWikiServices $services ) : CommandFactory {
@ -1112,7 +1143,8 @@ return [
new ServiceOptions(
SpecialPageFactory::CONSTRUCTOR_OPTIONS, $services->getMainConfig() ),
$services->getContentLanguage(),
$services->getObjectFactory()
$services->getObjectFactory(),
$services->getHookContainer()
);
},
@ -1169,7 +1201,8 @@ return [
$services->getService( 'TitleFactory' ),
$messageFormatterFactory->getTextFormatter(
$services->getContentLanguage()->getCode()
)
),
$services->getHookContainer()
);
},
@ -1183,7 +1216,8 @@ return [
$services->get( '_DefaultOptionsLookup' ),
$services->getLanguageConverterFactory(),
$services->getDBLoadBalancer(),
LoggerFactory::getInstance( 'UserOptionsManager' )
LoggerFactory::getInstance( 'UserOptionsManager' ),
$services->getHookContainer()
);
},
@ -1212,6 +1246,7 @@ return [
$services->getActorMigration(),
$services->getWatchedItemStore(),
$services->getPermissionManager(),
$services->getHookContainer(),
$services->getMainConfig()->get( 'WatchlistExpiry' )
);
},
@ -1226,7 +1261,8 @@ return [
new HashBagOStuff( [ 'maxKeys' => 100 ] ),
$services->getReadOnlyMode(),
$services->getNamespaceInfo(),
$services->getRevisionLookup()
$services->getRevisionLookup(),
$services->getHookContainer()
);
$store->setStatsdDataFactory( $services->getStatsdDataFactory() );
@ -1249,7 +1285,8 @@ return [
'_DefaultOptionsLookup' => function ( MediaWikiServices $services ) : DefaultOptionsLookup {
return new DefaultOptionsLookup(
new ServiceOptions( DefaultOptionsLookup::CONSTRUCTOR_OPTIONS, $services->getMainConfig() ),
$services->getContentLanguage()
$services->getContentLanguage(),
$services->getHookContainer()
);
},
@ -1273,7 +1310,8 @@ return [
$services->getRepoGroup(),
$services->getContentHandlerFactory(),
$services->getRevisionStore(),
$services->getSpamChecker()
$services->getSpamChecker(),
$services->getHookContainer()
);
},

View file

@ -684,7 +684,7 @@ if ( $wgCommandLineMode ) {
$wgMemc = ObjectCache::getLocalClusterInstance();
// Most of the config is out, some might want to run hooks here.
Hooks::run( 'SetupAfterCache' );
Hooks::runner()->onSetupAfterCache();
/**
* @var Language $wgContLang

View file

@ -27,7 +27,6 @@ use Content;
use ContentHandler;
use DeferrableUpdate;
use DeferredUpdates;
use Hooks;
use IDBAccessObject;
use InvalidArgumentException;
use JobQueueGroup;
@ -37,6 +36,8 @@ use LinksUpdate;
use LogicException;
use MediaWiki\Content\IContentHandlerFactory;
use MediaWiki\Edit\PreparedEdit;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\MediaWikiServices;
use MediaWiki\Revision\MutableRevisionRecord;
use MediaWiki\Revision\RenderedRevision;
@ -141,6 +142,11 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
*/
private $loadbalancerFactory;
/**
* @var HookRunner
*/
private $hookRunner;
/**
* @var LoggerInterface
*/
@ -285,6 +291,7 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
* @param Language $contLang
* @param ILBFactory $loadbalancerFactory
* @param IContentHandlerFactory $contentHandlerFactory
* @param HookContainer $hookContainer
*/
public function __construct(
WikiPage $wikiPage,
@ -296,7 +303,8 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
MessageCache $messageCache,
Language $contLang,
ILBFactory $loadbalancerFactory,
IContentHandlerFactory $contentHandlerFactory
IContentHandlerFactory $contentHandlerFactory,
HookContainer $hookContainer
) {
$this->wikiPage = $wikiPage;
@ -311,6 +319,7 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
// interface for that.
$this->loadbalancerFactory = $loadbalancerFactory;
$this->contentHandlerFactory = $contentHandlerFactory;
$this->hookRunner = new HookRunner( $hookContainer );
$this->logger = new NullLogger();
}
@ -780,7 +789,7 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
}
$userPopts = ParserOptions::newFromUserAndLang( $user, $this->contLang );
Hooks::run( 'ArticlePrepareTextForEdit', [ $wikiPage, $userPopts ] );
$this->hookRunner->onArticlePrepareTextForEdit( $wikiPage, $userPopts );
$this->user = $user;
$this->slotsUpdate = $slotsUpdate;
@ -1402,10 +1411,8 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
}
// TODO: hard deprecate SecondaryDataUpdates in favor of RevisionDataUpdates in 1.33!
Hooks::run(
'RevisionDataUpdates',
[ $this->getTitle(), $renderedRevision, &$allUpdates ]
);
$this->hookRunner->onRevisionDataUpdates(
$this->getTitle(), $renderedRevision, $allUpdates );
return $allUpdates;
}
@ -1476,13 +1483,10 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
// @note: Extensions should *avoid* calling getCannonicalParserOutput() when using
// this hook whenever possible in order to avoid unnecessary additional parses.
$editInfo = $this->getPreparedEdit();
Hooks::run( 'ArticleEditUpdates',
[ &$wikiPage, &$editInfo, $this->options['changed'] ],
'1.35'
);
$this->hookRunner->onArticleEditUpdates( $wikiPage, $editInfo, $this->options['changed'] );
// TODO: replace legacy hook! Use a listener on PageEventEmitter instead!
if ( Hooks::run( 'ArticleEditUpdatesDeleteFromRecentchanges', [ &$wikiPage ], '1.35' ) ) {
if ( $this->hookRunner->onArticleEditUpdatesDeleteFromRecentchanges( $wikiPage ) ) {
// Flush old entries from the `recentchanges` table
if ( mt_rand( 0, 9 ) == 0 ) {
$this->jobQueueGroup->lazyPush( RecentChangesUpdateJob::newPurgeJob() );
@ -1548,7 +1552,7 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
// Allow extensions to prevent user notification
// when a new message is added to their talk page
// TODO: replace legacy hook! Use a listener on PageEventEmitter instead!
if ( Hooks::run( 'ArticleEditUpdateNewTalk', [ &$wikiPage, $recipient ] ) ) {
if ( $this->hookRunner->onArticleEditUpdateNewTalk( $wikiPage, $recipient ) ) {
$revRecord = $legacyRevision->getRevisionRecord();
$talkPageNotificationManager = MediaWikiServices::getInstance()
->getTalkPageNotificationManager();

View file

@ -25,8 +25,10 @@ namespace MediaWiki\Storage;
use ActorMigration;
use BagOStuff;
use Content;
use Hooks;
use Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\Storage\Hook\ParserOutputStashForEditHook;
use ParserOutput;
use Psr\Log\LoggerInterface;
use stdClass;
@ -50,6 +52,8 @@ class PageEditStash {
private $logger;
/** @var StatsdDataFactoryInterface */
private $stats;
/** @var ParserOutputStashForEditHook */
private $hookRunner;
/** @var int */
private $initiator;
@ -73,6 +77,7 @@ class PageEditStash {
* @param ILoadBalancer $lb
* @param LoggerInterface $logger
* @param StatsdDataFactoryInterface $stats
* @param HookContainer $hookContainer
* @param int $initiator Class INITIATOR__* constant
*/
public function __construct(
@ -80,12 +85,14 @@ class PageEditStash {
ILoadBalancer $lb,
LoggerInterface $logger,
StatsdDataFactoryInterface $stats,
HookContainer $hookContainer,
$initiator
) {
$this->cache = $cache;
$this->lb = $lb;
$this->logger = $logger;
$this->stats = $stats;
$this->hookRunner = new HookRunner( $hookContainer );
$this->initiator = $initiator;
}
@ -136,8 +143,8 @@ class PageEditStash {
if ( $editInfo && $editInfo->output ) {
// Let extensions add ParserOutput metadata or warm other caches
Hooks::run( 'ParserOutputStashForEdit',
[ $page, $content, $editInfo->output, $summary, $user ] );
$this->hookRunner->onParserOutputStashForEdit(
$page, $content, $editInfo->output, $summary, $user );
if ( $alreadyCached ) {
$logger->debug( "Parser output for key '{cachekey}' already cached.", $context );

View file

@ -30,11 +30,12 @@ use CommentStoreComment;
use Content;
use ContentHandler;
use DeferredUpdates;
use Hooks;
use InvalidArgumentException;
use LogicException;
use ManualLogEntry;
use MediaWiki\Content\IContentHandlerFactory;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\Linker\LinkTarget;
use MediaWiki\Revision\MutableRevisionRecord;
use MediaWiki\Revision\RevisionAccessException;
@ -109,6 +110,16 @@ class PageUpdater {
*/
private $contentHandlerFactory;
/**
* @var HookRunner
*/
private $hookRunner;
/**
* @var HookContainer
*/
private $hookContainer;
/**
* @var boolean see $wgUseAutomaticEditSummaries
* @see $wgUseAutomaticEditSummaries
@ -163,6 +174,7 @@ class PageUpdater {
* @param RevisionStore $revisionStore
* @param SlotRoleRegistry $slotRoleRegistry
* @param IContentHandlerFactory $contentHandlerFactory
* @param HookContainer $hookContainer
*/
public function __construct(
User $user,
@ -171,7 +183,8 @@ class PageUpdater {
ILoadBalancer $loadBalancer,
RevisionStore $revisionStore,
SlotRoleRegistry $slotRoleRegistry,
IContentHandlerFactory $contentHandlerFactory
IContentHandlerFactory $contentHandlerFactory,
HookContainer $hookContainer
) {
$this->user = $user;
$this->wikiPage = $wikiPage;
@ -181,6 +194,8 @@ class PageUpdater {
$this->revisionStore = $revisionStore;
$this->slotRoleRegistry = $slotRoleRegistry;
$this->contentHandlerFactory = $contentHandlerFactory;
$this->hookContainer = $hookContainer;
$this->hookRunner = new HookRunner( $hookContainer );
$this->slotsUpdate = new RevisionSlotsUpdate();
}
@ -735,22 +750,20 @@ class PageUpdater {
// Trigger pre-save hook (using provided edit summary)
$renderedRevision = $this->derivedDataUpdater->getRenderedRevision();
$hookStatus = Status::newGood( [] );
$allowedByHook = Hooks::run( 'MultiContentSave', [
$allowedByHook = $this->hookRunner->onMultiContentSave(
$renderedRevision, $user, $summary, $flags, $hookStatus
] );
if ( $allowedByHook && Hooks::isRegistered( 'PageContentSave' ) ) {
);
if ( $allowedByHook && $this->hookContainer->isRegistered( 'PageContentSave' ) ) {
// Also run the legacy hook.
// TODO: avoid pass-by-reference, see T193950
// NOTE: WikiPage should only be used for the legacy hook,
// and only if something uses the legacy hook.
$mainContent = $this->derivedDataUpdater->getSlots()->getContent( SlotRecord::MAIN );
$wikiPage = $this->getWikiPage();
// Deprecated since 1.35.
$allowedByHook = Hooks::run( 'PageContentSave', [
&$wikiPage, &$user, &$mainContent, &$summary,
$flags & EDIT_MINOR, null, null, &$flags, &$hookStatus
] );
$allowedByHook = $this->hookRunner->onPageContentSave(
$this->getWikiPage(), $user, $mainContent, $summary,
$flags & EDIT_MINOR, null, null, $flags, $hookStatus
);
}
if ( !$allowedByHook ) {
@ -1034,17 +1047,14 @@ class PageUpdater {
}
$tags = $this->computeEffectiveTags( $flags );
Hooks::run(
'RevisionFromEditComplete',
[ $wikiPage, $newRevisionRecord, $this->getOriginalRevisionId(), $user, &$tags ]
$this->hookRunner->onRevisionFromEditComplete(
$wikiPage, $newRevisionRecord, $this->getOriginalRevisionId(), $user, $tags
);
// TODO: replace legacy hook!
$newLegacyRevision = new Revision( $newRevisionRecord );
Hooks::run(
'NewRevisionFromEditComplete',
[ $wikiPage, $newLegacyRevision, $this->getOriginalRevisionId(), $user, &$tags ]
);
$this->hookRunner->onNewRevisionFromEditComplete(
$wikiPage, $newLegacyRevision, $this->getOriginalRevisionId(), $user, $tags );
// Update recentchanges
if ( !( $flags & EDIT_SUPPRESS_RC ) ) {
@ -1173,17 +1183,14 @@ class PageUpdater {
}
$tags = $this->computeEffectiveTags( $flags );
Hooks::run(
'RevisionFromEditComplete',
[ $wikiPage, $newRevisionRecord, false, $user, &$tags ]
$this->hookRunner->onRevisionFromEditComplete(
$wikiPage, $newRevisionRecord, false, $user, $tags
);
// TODO: replace legacy hook!
$newLegacyRevision = new Revision( $newRevisionRecord );
Hooks::run(
'NewRevisionFromEditComplete',
[ $wikiPage, $newLegacyRevision, false, $user, &$tags ]
);
$this->hookRunner->onNewRevisionFromEditComplete(
$wikiPage, $newLegacyRevision, false, $user, $tags );
// Update recentchanges
if ( !( $flags & EDIT_SUPPRESS_RC ) ) {
@ -1274,20 +1281,19 @@ class PageUpdater {
$this->derivedDataUpdater->doUpdates();
// TODO: replace legacy hook!
// TODO: avoid pass-by-reference, see T193950
if ( $hints['created'] ?? false ) {
// Trigger post-create hook
Hooks::run( 'PageContentInsertComplete', [ &$wikiPage, &$user,
$mainContent, $summary->text, $flags & EDIT_MINOR, null, null,
&$flags, $newLegacyRevision ] );
$this->hookRunner->onPageContentInsertComplete( $wikiPage, $user,
$mainContent, $summary->text, $flags & EDIT_MINOR,
null, null, $flags, $newLegacyRevision );
}
// Trigger post-save hook
Hooks::run( 'PageContentSaveComplete', [ &$wikiPage, &$user,
$mainContent, $summary->text, $flags & EDIT_MINOR, null, null,
&$flags, $newLegacyRevision,
&$status, $this->getOriginalRevisionId(), $this->undidRevId ] );
$this->hookRunner->onPageContentSaveComplete( $wikiPage, $user, $mainContent,
$summary->text, $flags & EDIT_MINOR, null,
null, $flags, $newLegacyRevision, $status,
$this->getOriginalRevisionId(), $this->undidRevId );
}
);
}

View file

@ -1364,7 +1364,7 @@ class Title implements LinkTarget, IDBAccessObject {
}
$result = true;
Hooks::run( 'TitleIsMovable', [ $this, &$result ] );
Hooks::runner()->onTitleIsMovable( $this, $result );
return $result;
}
@ -2114,9 +2114,7 @@ class Title implements LinkTarget, IDBAccessObject {
# Finally, add the fragment.
$url .= $this->getFragmentForURL();
// Avoid PHP 7.1 warning from passing $this by reference
$titleRef = $this;
Hooks::run( 'GetFullURL', [ &$titleRef, &$url, $query ] );
Hooks::runner()->onGetFullURL( $this, $url, $query );
return $url;
}
@ -2189,9 +2187,7 @@ class Title implements LinkTarget, IDBAccessObject {
$dbkey = wfUrlencode( $this->getPrefixedDBkey() );
if ( $query == '' ) {
$url = str_replace( '$1', $dbkey, $wgArticlePath );
// Avoid PHP 7.1 warning from passing $this by reference
$titleRef = $this;
Hooks::run( 'GetLocalURL::Article', [ &$titleRef, &$url ] );
Hooks::runner()->onGetLocalURL__Article( $this, $url );
} else {
global $wgVariantArticlePath, $wgActionPaths;
$url = false;
@ -2238,9 +2234,7 @@ class Title implements LinkTarget, IDBAccessObject {
$url = "{$wgScript}?title={$dbkey}&{$query}";
}
}
// Avoid PHP 7.1 warning from passing $this by reference
$titleRef = $this;
Hooks::run( 'GetLocalURL::Internal', [ &$titleRef, &$url, $query ] );
Hooks::runner()->onGetLocalURL__Internal( $this, $url, $query );
// @todo FIXME: This causes breakage in various places when we
// actually expected a local URL and end up with dupe prefixes.
@ -2253,9 +2247,7 @@ class Title implements LinkTarget, IDBAccessObject {
return '/';
}
// Avoid PHP 7.1 warning from passing $this by reference
$titleRef = $this;
Hooks::run( 'GetLocalURL', [ &$titleRef, &$url, $query ] );
Hooks::runner()->onGetLocalURL( $this, $url, $query );
return $url;
}
@ -2306,9 +2298,7 @@ class Title implements LinkTarget, IDBAccessObject {
$query = self::fixUrlQueryArgs( $query, $query2 );
$server = $wgInternalServer !== false ? $wgInternalServer : $wgServer;
$url = wfExpandUrl( $server . $this->getLocalURL( $query ), PROTO_HTTP );
// Avoid PHP 7.1 warning from passing $this by reference
$titleRef = $this;
Hooks::run( 'GetInternalURL', [ &$titleRef, &$url, $query ] );
Hooks::runner()->onGetInternalURL( $this, $url, $query );
return $url;
}
@ -2328,9 +2318,7 @@ class Title implements LinkTarget, IDBAccessObject {
public function getCanonicalURL( $query = '', $query2 = false ) {
$query = self::fixUrlQueryArgs( $query, $query2 );
$url = wfExpandUrl( $this->getLocalURL( $query ) . $this->getFragmentForURL(), PROTO_CANONICAL );
// Avoid PHP 7.1 warning from passing $this by reference
$titleRef = $this;
Hooks::run( 'GetCanonicalURL', [ &$titleRef, &$url, $query ] );
Hooks::runner()->onGetCanonicalURL( $this, $url, $query );
return $url;
}
@ -2485,7 +2473,7 @@ class Title implements LinkTarget, IDBAccessObject {
$types = array_diff( $types, [ 'upload' ] );
}
Hooks::run( 'TitleGetRestrictionTypes', [ $this, &$types ] );
Hooks::runner()->onTitleGetRestrictionTypes( $this, $types );
wfDebug( __METHOD__ . ': applicable restrictions to [[' .
$this->getPrefixedText() . ']] are {' . implode( ',', $types ) . "}\n" );
@ -3955,7 +3943,7 @@ class Title implements LinkTarget, IDBAccessObject {
*/
public function exists( $flags = 0 ) {
$exists = $this->getArticleID( $flags ) != 0;
Hooks::run( 'TitleExists', [ $this, &$exists ] );
Hooks::runner()->onTitleExists( $this, $exists );
return $exists;
}
@ -3988,7 +3976,7 @@ class Title implements LinkTarget, IDBAccessObject {
* @param Title $title
* @param bool|null $isKnown
*/
Hooks::run( 'TitleIsAlwaysKnown', [ $this, &$isKnown ] );
Hooks::runner()->onTitleIsAlwaysKnown( $this, $isKnown );
if ( $isKnown !== null ) {
return $isKnown;
@ -4360,7 +4348,7 @@ class Title implements LinkTarget, IDBAccessObject {
// on the Title object passed in, and should probably
// tell the users to run updateCollations.php --force
// in order to re-sort existing category relations.
Hooks::run( 'GetDefaultSortkey', [ $this, &$unprefixed ] );
Hooks::runner()->onGetDefaultSortkey( $this, $unprefixed );
if ( $prefix !== '' ) {
# Separate with a line feed, so the unprefixed part is only used as
# a tiebreaker when two pages have the exact same prefix.
@ -4556,7 +4544,7 @@ class Title implements LinkTarget, IDBAccessObject {
}
}
Hooks::run( 'TitleGetEditNotices', [ $this, $oldid, &$notices ] );
Hooks::runner()->onTitleGetEditNotices( $this, $oldid, $notices );
return $notices;
}

View file

@ -41,7 +41,7 @@ abstract class TitleArray implements Iterator {
*/
public static function newFromResult( $res ) {
$array = null;
if ( !Hooks::run( 'TitleArrayFromResult', [ &$array, $res ] ) ) {
if ( !Hooks::runner()->onTitleArrayFromResult( $array, $res ) ) {
return null;
}
return $array ?? new TitleArrayFromResult( $res );

View file

@ -198,7 +198,7 @@ class WebRequest {
);
}
Hooks::run( 'WebRequestPathInfoRouter', [ $router ] );
Hooks::runner()->onWebRequestPathInfoRouter( $router );
$matches = $router->parse( $path );
} else {
@ -1305,7 +1305,7 @@ class WebRequest {
}
# Allow extensions to improve our guess
Hooks::run( 'GetIP', [ &$ip ] );
Hooks::runner()->onGetIP( $ip );
if ( !$ip ) {
throw new MWException( "Unable to determine IP." );

View file

@ -171,7 +171,7 @@ class WebResponse {
$func = $options['raw'] ? 'setrawcookie' : 'setcookie';
if ( Hooks::run( 'WebResponseSetCookie', [ &$name, &$value, &$expire, &$options ] ) ) {
if ( Hooks::runner()->onWebResponseSetCookie( $name, $value, $expire, $options ) ) {
// Note: Don't try to move this earlier to reuse it for self::$disableForPostSend,
// we need to use the altered values from the hook here. (T198525)
$cookie = $options['prefix'] . $name;

View file

@ -19,6 +19,8 @@
* @file
*/
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\MediaWikiServices;
/**
@ -308,6 +310,24 @@ abstract class Action implements MessageLocalizer {
return $this->getContext()->msg( $key, ...$params );
}
/**
* @since 1.35
* @return HookContainer
*/
protected function getHookContainer() {
return MediaWikiServices::getInstance()->getHookContainer();
}
/**
* @since 1.35
* @internal This is for use by core only. Hook interfaces may be removed
* without notice.
* @return HookRunner
*/
protected function getHookRunner() {
return new HookRunner( $this->getHookContainer() );
}
/**
* Only public since 1.21
*

View file

@ -53,7 +53,7 @@ class EditAction extends FormlessAction {
}
$article = $this->getArticle();
if ( Hooks::run( 'CustomEditor', [ $article, $this->getUser() ] ) ) {
if ( $this->getHookRunner()->onCustomEditor( $article, $this->getUser() ) ) {
$editor = new EditPage( $article );
$editor->setContextTitle( $this->getTitle() );
$editor->edit();

View file

@ -74,13 +74,10 @@ abstract class FormAction extends Action {
$this->fields = $this->getFormFields();
// Give hooks a chance to alter the form, adding extra fields or text etc
Hooks::run(
'ActionModifyFormFields',
[
$this->getName(),
&$this->fields,
$this->getArticle()
]
$this->getHookRunner()->onActionModifyFormFields(
$this->getName(),
$this->fields,
$this->getArticle()
);
if ( $this->usesOOUI() ) {
@ -106,11 +103,11 @@ abstract class FormAction extends Action {
$this->alterForm( $form );
// Give hooks a chance to alter the form, adding extra fields or text etc
Hooks::run( 'ActionBeforeFormDisplay', [
$this->getHookRunner()->onActionBeforeFormDisplay(
$this->getName(),
&$form,
$form,
$this->getArticle()
] );
);
return $form;
}

View file

@ -70,7 +70,7 @@ class HistoryAction extends FormlessAction {
$links = [];
// Allow extensions to add more links
Hooks::run( 'HistoryPageToolLinks', [ $this->getContext(), $linkRenderer, &$links ] );
$this->getHookRunner()->onHistoryPageToolLinks( $this->getContext(), $linkRenderer, $links );
if ( $links ) {
$subtitle .= ''
. $this->msg( 'word-separator' )->escaped()
@ -283,13 +283,9 @@ class HistoryAction extends FormlessAction {
$out->addHTML( $htmlForm->getHTML( false ) );
$article = $this->getArticle(); // must be a variable for hook reference
Hooks::run(
'PageHistoryBeforeList',
[
&$article,
$this->getContext()
]
$this->getHookRunner()->onPageHistoryBeforeList(
$this->getArticle(),
$this->getContext()
);
// Create and output the list.

View file

@ -126,7 +126,7 @@ class InfoAction extends FormlessAction {
$pageInfo = $this->pageInfo();
// Allow extensions to add additional information
Hooks::run( 'InfoAction', [ $this->getContext(), &$pageInfo ] );
$this->getHookRunner()->onInfoAction( $this->getContext(), $pageInfo );
// Render page information
foreach ( $pageInfo as $header => $infoTable ) {

View file

@ -164,9 +164,7 @@ class RawAction extends FormlessAction {
$response->statusHeader( 404 );
}
// Avoid PHP 7.1 warning of passing $this by reference
$rawAction = $this;
if ( !Hooks::run( 'RawPageViewBeforeOutput', [ &$rawAction, &$text ] ) ) {
if ( !$this->getHookRunner()->onRawPageViewBeforeOutput( $this, $text ) ) {
wfDebug( __METHOD__ . ": RawPageViewBeforeOutput hook broke raw page output.\n" );
}

View file

@ -212,10 +212,10 @@ class WatchAction extends FormAction {
$page = WikiPage::factory( $title );
$status = Status::newFatal( 'hookaborted' );
if ( Hooks::run( 'WatchArticle', [ &$user, &$page, &$status, $expiry ] ) ) {
if ( Hooks::runner()->onWatchArticle( $user, $page, $status, $expiry ) ) {
$status = Status::newGood();
$user->addWatch( $title, $checkRights, $expiry );
Hooks::run( 'WatchArticleComplete', [ &$user, &$page ] );
Hooks::runner()->onWatchArticleComplete( $user, $page );
}
return $status;
@ -238,10 +238,10 @@ class WatchAction extends FormAction {
$page = WikiPage::factory( $title );
$status = Status::newFatal( 'hookaborted' );
if ( Hooks::run( 'UnwatchArticle', [ &$user, &$page, &$status ] ) ) {
if ( Hooks::runner()->onUnwatchArticle( $user, $page, $status ) ) {
$status = Status::newGood();
$user->removeWatch( $title );
Hooks::run( 'UnwatchArticleComplete', [ &$user, &$page ] );
Hooks::runner()->onUnwatchArticleComplete( $user, $page );
}
return $status;

View file

@ -112,9 +112,7 @@ class HistoryPager extends ReverseChronologicalPager {
$this->tagFilter
);
// Avoid PHP 7.1 warning of passing $this by reference
$historyPager = $this;
Hooks::run( 'PageHistoryPager::getQueryInfo', [ &$historyPager, &$queryInfo ] );
$this->getHookRunner()->onPageHistoryPager__getQueryInfo( $this, $queryInfo );
return $queryInfo;
}
@ -146,7 +144,7 @@ class HistoryPager extends ReverseChronologicalPager {
}
protected function doBatchLookups() {
if ( !Hooks::run( 'PageHistoryPager::doBatchLookups', [ $this, $this->mResult ] ) ) {
if ( !$this->getHookRunner()->onPageHistoryPager__doBatchLookups( $this, $this->mResult ) ) {
return;
}
@ -482,12 +480,12 @@ class HistoryPager extends ReverseChronologicalPager {
}
// Allow extension to add their own links here
// TODO replace hook with one using RevisionRecord
Hooks::run( 'HistoryRevisionTools', [
$this->getHookRunner()->onHistoryRevisionTools(
new Revision( $revRecord ),
&$tools,
$tools,
$previousRevRecord ? new Revision( $previousRevRecord ) : null,
$user
] );
);
if ( $tools ) {
$s2 .= ' ' . Html::openElement( 'span', [ 'class' => 'mw-changeslist-links' ] );
@ -515,7 +513,7 @@ class HistoryPager extends ReverseChronologicalPager {
$attribs = [ 'data-mw-revid' => $revRecord->getId() ];
Hooks::run( 'PageHistoryLineEnding', [ $this, &$row, &$s, &$classes, &$attribs ] );
$this->getHookRunner()->onPageHistoryLineEnding( $this, $row, $s, $classes, $attribs );
$attribs = array_filter( $attribs,
[ Sanitizer::class, 'isReservedDataAttribute' ],
ARRAY_FILTER_USE_KEY

View file

@ -20,9 +20,11 @@
* @file
*/
use MediaWiki\Api\ApiHookRunner;
use MediaWiki\Api\Validator\SubmoduleDef;
use MediaWiki\Block\AbstractBlock;
use MediaWiki\Block\DatabaseBlock;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\Linker\LinkTarget;
use MediaWiki\MediaWikiServices;
use MediaWiki\ParamValidator\TypeDef\NamespaceDef;
@ -49,6 +51,12 @@ abstract class ApiBase extends ContextSource {
use ApiBlockInfoTrait;
/** @var HookContainer */
private $hookContainer;
/** @var ApiHookRunner */
private $hookRunner;
/**
* @name Old constants for ::getAllowedParams() arrays
* @deprecated since 1.35, use the equivalent ParamValidator or TypeDef constants instead.
@ -609,6 +617,34 @@ abstract class ApiBase extends ContextSource {
return MediaWikiServices::getInstance()->getPermissionManager();
}
/**
* Get a HookContainer, for running extension hooks or for hook metadata.
*
* @since 1.35
* @return HookContainer
*/
protected function getHookContainer() {
if ( !$this->hookContainer ) {
$this->hookContainer = MediaWikiServices::getInstance()->getHookContainer();
}
return $this->hookContainer;
}
/**
* Get an ApiHookRunner for running core API hooks.
*
* @internal This is for use by core only. Hook interfaces may be removed
* without notice.
* @since 1.35
* @return ApiHookRunner
*/
protected function getHookRunner() {
if ( !$this->hookRunner ) {
$this->hookRunner = new ApiHookRunner( $this->getHookContainer() );
}
return $this->hookRunner;
}
/** @} */
/************************************************************************//**
@ -1320,7 +1356,7 @@ abstract class ApiBase extends ContextSource {
// No real need to deduplicate here, ApiErrorFormatter does that for
// us (assuming the hook is deterministic).
$msgs = [ $this->msg( 'api-usage-mailinglist-ref' ) ];
Hooks::run( 'ApiDeprecationHelp', [ &$msgs ] );
$this->getHookRunner()->onApiDeprecationHelp( $msgs );
if ( count( $msgs ) > 1 ) {
$key = '$' . implode( ' $', range( 1, count( $msgs ) ) );
$msg = ( new RawMessage( $key ) )->params( $msgs );
@ -1682,7 +1718,7 @@ abstract class ApiBase extends ContextSource {
$msgs = [ $summary, $extendedDescription ];
Hooks::run( 'APIGetDescriptionMessages', [ $this, &$msgs ] );
$this->getHookRunner()->onAPIGetDescriptionMessages( $this, $msgs );
return $msgs;
}
@ -1714,9 +1750,7 @@ abstract class ApiBase extends ContextSource {
] + ( $params['token'] ?? [] );
}
// Avoid PHP 7.1 warning of passing $this by reference
$apiModule = $this;
Hooks::run( 'APIGetAllowedParams', [ &$apiModule, &$params, $flags ] );
$this->getHookRunner()->onAPIGetAllowedParams( $this, $params, $flags );
return $params;
}
@ -1860,7 +1894,7 @@ abstract class ApiBase extends ContextSource {
}
}
Hooks::run( 'APIGetParamDescriptionMessages', [ $this, &$msgs ] );
$this->getHookRunner()->onAPIGetParamDescriptionMessages( $this, $msgs );
return $msgs;
}

View file

@ -56,7 +56,7 @@ class ApiChangeAuthenticationData extends ApiBase {
// Make the change
$status = $manager->allowsAuthenticationDataChange( $req, true );
Hooks::run( 'ChangeAuthenticationDataAudit', [ $req, $status ] );
$this->getHookRunner()->onChangeAuthenticationDataAudit( $req, $status );
if ( !$status->isGood() ) {
$this->dieStatus( $status );
}

View file

@ -90,8 +90,8 @@ class ApiExpandTemplates extends ApiBase {
$reset = null;
$suppressCache = false;
Hooks::run( 'ApiMakeParserOptions',
[ $options, $titleObj, $params, $this, &$reset, &$suppressCache ] );
$this->getHookRunner()->onApiMakeParserOptions(
$options, $titleObj, $params, $this, $reset, $suppressCache );
$retval = [];

View file

@ -132,10 +132,8 @@ class ApiFeedContributions extends ApiBase {
// ContributionsLineEnding hook. Hook implementers may cancel
// the hook to signal the user is not allowed to read this item.
$feedItem = null;
$hookResult = Hooks::run(
'ApiFeedContributions::feedItem',
[ $row, $this->getContext(), &$feedItem ]
);
$hookResult = $this->getHookRunner()->onApiFeedContributions__feedItem(
$row, $this->getContext(), $feedItem );
// Hook returned a valid feed item
if ( $feedItem instanceof FeedItem ) {
return $feedItem;

View file

@ -292,7 +292,7 @@ abstract class ApiFormatBase extends ApiBase {
}
}
if ( Hooks::run( 'ApiFormatHighlight', [ $context, $result, $mime, $format ] ) ) {
if ( $this->getHookRunner()->onApiFormatHighlight( $context, $result, $mime, $format ) ) {
$out->addHTML(
Html::element( 'pre', [ 'class' => 'api-pretty-content' ], $result )
);

View file

@ -620,7 +620,8 @@ class ApiHelp extends ApiBase {
$module->modifyHelp( $help, $suboptions, $haveModules );
Hooks::run( 'APIHelpModifyOutput', [ $module, &$help, $suboptions, &$haveModules ] );
$module->getHookRunner()->onAPIHelpModifyOutput( $module, $help,
$suboptions, $haveModules );
$out .= implode( "\n", $help );
}

View file

@ -114,7 +114,7 @@ class ApiImport extends ApiBase {
*/
public function getAllowedImportSources() {
$importSources = $this->getConfig()->get( 'ImportSources' );
Hooks::run( 'ImportSources', [ &$importSources ] );
$this->getHookRunner()->onImportSources( $importSources );
$result = [];
foreach ( $importSources as $key => $value ) {

View file

@ -197,7 +197,7 @@ class ApiLogin extends ApiBase {
// Deprecated hook
$injected_html = '';
Hooks::run( 'UserLoginComplete', [ &$user, &$injected_html, true ] );
$this->getHookRunner()->onUserLoginComplete( $user, $injected_html, true );
$result['lguserid'] = (int)$user->getId();
$result['lgusername'] = $user->getName();

View file

@ -56,7 +56,7 @@ class ApiLogout extends ApiBase {
// Give extensions to do something after user logout
$injected_html = '';
Hooks::run( 'UserLogoutComplete', [ &$user, &$injected_html, $oldName ] );
$this->getHookRunner()->onUserLogoutComplete( $user, $injected_html, $oldName );
}
public function mustBePosted() {

View file

@ -268,7 +268,7 @@ class ApiMain extends ApiBase {
$this->mModuleMgr->addModules( self::$Formats, 'format' );
$this->mModuleMgr->addModules( $config->get( 'APIFormatModules' ), 'format' );
Hooks::run( 'ApiMain::moduleManager', [ $this->mModuleMgr ] );
$this->getHookRunner()->onApiMain__moduleManager( $this->mModuleMgr );
$this->mContinuationManager = null;
$this->mEnableWrite = $enableWrite;
@ -324,7 +324,8 @@ class ApiMain extends ApiBase {
}
// Allow extensions to override.
$this->lacksSameOriginSecurity = !Hooks::run( 'RequestHasSameOriginSecurity', [ $request ] );
$this->lacksSameOriginSecurity = !$this->getHookRunner()
->onRequestHasSameOriginSecurity( $request );
return $this->lacksSameOriginSecurity;
}
@ -576,7 +577,7 @@ class ApiMain extends ApiBase {
}
// Allow extra cleanup and logging
Hooks::run( 'ApiMain::onException', [ $this, $e ] );
$this->getHookRunner()->onApiMain__onException( $this, $e );
// Handle any kind of exception by outputting properly formatted error message.
// If this fails, an unhandled exception should be thrown so that global error
@ -1234,7 +1235,7 @@ class ApiMain extends ApiBase {
}
}
Hooks::runWithoutAbort( 'ApiMaxLagInfo', [ &$lagInfo ] );
$this->getHookRunner()->onApiMaxLagInfo( $lagInfo );
return $lagInfo;
}
@ -1361,7 +1362,7 @@ class ApiMain extends ApiBase {
TS_MW, time() - $config->get( 'CdnMaxAge' )
);
}
Hooks::run( 'OutputPageCheckLastModified', [ &$modifiedTimes, $this->getOutput() ] );
$this->getHookRunner()->onOutputPageCheckLastModified( $modifiedTimes, $this->getOutput() );
$lastMod = max( $modifiedTimes );
$return304 = wfTimestamp( TS_MW, $lastMod ) <= $ts->getTimestamp( TS_MW );
}
@ -1413,7 +1414,7 @@ class ApiMain extends ApiBase {
// Allow extensions to stop execution for arbitrary reasons.
$message = 'hookaborted';
if ( !Hooks::run( 'ApiCheckCanExecute', [ $module, $user, &$message ] ) ) {
if ( !$this->getHookRunner()->onApiCheckCanExecute( $module, $user, $message ) ) {
$this->dieWithError( $message );
}
}
@ -1581,7 +1582,7 @@ class ApiMain extends ApiBase {
}
$module->execute();
Hooks::run( 'APIAfterExecute', [ &$module ] );
$this->getHookRunner()->onAPIAfterExecute( $module );
$this->reportUnusedParams();

View file

@ -91,12 +91,11 @@ class ApiOpenSearch extends ApiBase {
$results = $this->search( $search, $params );
// Allow hooks to populate extracts and images
Hooks::run( 'ApiOpenSearchSuggest', [ &$results ] );
$this->getHookRunner()->onApiOpenSearchSuggest( $results );
// Trim extracts, if necessary
$length = $this->getConfig()->get( 'OpenSearchDescriptionLength' );
foreach ( $results as &$r ) {
// @phan-suppress-next-line PhanTypeInvalidDimOffset
if ( is_string( $r['extract'] ) && !$r['extract trimmed'] ) {
$r['extract'] = self::trimExtract( $r['extract'], $length );
}

View file

@ -69,7 +69,7 @@ class ApiOptions extends ApiBase {
$changes[$params['optionname']] = $newValue;
}
Hooks::run( 'ApiOptions', [ $this, $user, $changes, $resetKinds ] );
$this->getHookRunner()->onApiOptions( $this, $user, $changes, $resetKinds );
if ( $resetKinds ) {
$this->resetPreferences( $resetKinds );

View file

@ -178,9 +178,7 @@ class ApiPageSet extends ApiBase {
if ( !$isDryRun ) {
$generator->executeGenerator( $this );
// Avoid PHP 7.1 warning of passing $this by reference
$apiModule = $this;
Hooks::run( 'APIQueryGeneratorAfterExecute', [ &$generator, &$apiModule ] );
$this->getHookRunner()->onAPIQueryGeneratorAfterExecute( $generator, $this );
} else {
// Prevent warnings from being reported on these parameters
$main = $this->getMain();

View file

@ -386,7 +386,7 @@ class ApiParse extends ApiBase {
$outputPage->loadSkinModules( $skin );
}
Hooks::run( 'ApiParseMakeOutputPage', [ $this, $outputPage ] );
$this->getHookRunner()->onApiParseMakeOutputPage( $this, $outputPage );
}
if ( $oldid !== null ) {
@ -425,7 +425,7 @@ class ApiParse extends ApiBase {
// one hook of OutputPage::addParserOutputMetadata here.
if ( $params['effectivelanglinks'] ) {
$linkFlags = [];
Hooks::run( 'LanguageLinks', [ $titleObj, &$langlinks, &$linkFlags ] );
$this->getHookRunner()->onLanguageLinks( $titleObj, $langlinks, $linkFlags );
}
}
@ -600,8 +600,8 @@ class ApiParse extends ApiBase {
$reset = null;
$suppressCache = false;
Hooks::run( 'ApiMakeParserOptions',
[ $popts, $pageObj->getTitle(), $params, $this, &$reset, &$suppressCache ] );
$this->getHookRunner()->onApiMakeParserOptions( $popts, $pageObj->getTitle(),
$params, $this, $reset, $suppressCache );
// Force cache suppression when $popts aren't cacheable.
$suppressCache = $suppressCache || !$popts->isSafeToCache();

View file

@ -157,7 +157,7 @@ class ApiQuery extends ApiBase {
$this->mModuleMgr->addModules( self::$QueryMetaModules, 'meta' );
$this->mModuleMgr->addModules( $config->get( 'APIMetaModules' ), 'meta' );
Hooks::run( 'ApiQuery::moduleManager', [ $this->mModuleMgr ] );
$this->getHookRunner()->onApiQuery__moduleManager( $this->mModuleMgr );
// Create PageSet that will process titles/pageids/revids/generator
$this->mPageSet = new ApiPageSet( $this );
@ -261,7 +261,7 @@ class ApiQuery extends ApiBase {
$cacheMode = $this->mergeCacheMode(
$cacheMode, $module->getCacheMode( $params ) );
$module->execute();
Hooks::run( 'APIQueryAfterExecute', [ &$module ] );
$this->getHookRunner()->onAPIQueryAfterExecute( $module );
}
// Set the cache mode

View file

@ -412,10 +412,10 @@ abstract class ApiQueryBase extends ApiBase {
if ( $hookData !== null && Hooks::isRegistered( 'ApiQueryBaseBeforeQuery' ) ) {
$info = $queryBuilder->getQueryInfo();
Hooks::run( 'ApiQueryBaseBeforeQuery', [
$this, &$info['tables'], &$info['fields'], &$info['conds'],
&$info['options'], &$info['join_conds'], &$hookData
] );
$this->getHookRunner()->onApiQueryBaseBeforeQuery(
$this, $info['tables'], $info['fields'], $info['conds'],
$info['options'], $info['join_conds'], $hookData
);
$queryBuilder = $this->getDB()->newSelectQueryBuilder()->queryInfo( $info );
}
@ -423,7 +423,7 @@ abstract class ApiQueryBase extends ApiBase {
$res = $queryBuilder->fetchResultSet();
if ( $hookData !== null ) {
Hooks::run( 'ApiQueryBaseAfterQuery', [ $this, $res, &$hookData ] );
$this->getHookRunner()->onApiQueryBaseAfterQuery( $this, $res, $hookData );
}
return $res;
@ -443,7 +443,7 @@ abstract class ApiQueryBase extends ApiBase {
* @return bool Return false if row processing should end with continuation
*/
protected function processRow( $row, array &$data, array &$hookData ) {
return Hooks::run( 'ApiQueryBaseProcessRow', [ $this, $row, &$data, &$hookData ] );
return $this->getHookRunner()->onApiQueryBaseProcessRow( $this, $row, $data, $hookData );
}
/** @} */

View file

@ -112,7 +112,7 @@ class ApiQueryInfo extends ApiQueryBase {
'import' => [ self::class, 'getImportToken' ],
'watch' => [ self::class, 'getWatchToken' ],
];
Hooks::run( 'APIQueryInfoTokens', [ &$this->tokenFunctions ], '1.24' );
$this->getHookRunner()->onAPIQueryInfoTokens( $this->tokenFunctions );
return $this->tokenFunctions;
}
@ -512,7 +512,7 @@ class ApiQueryInfo extends ApiQueryBase {
$pageInfo['preload'] = '';
} else {
$text = null;
Hooks::run( 'EditFormPreloadText', [ &$text, &$title ] );
$this->getHookRunner()->onEditFormPreloadText( $text, $title );
$pageInfo['preload'] = $text;
}

View file

@ -69,7 +69,7 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase {
$this->tokenFunctions = [
'patrol' => [ self::class, 'getPatrolToken' ]
];
Hooks::run( 'APIQueryRecentChangesTokens', [ &$this->tokenFunctions ], '1.24' );
$this->getHookRunner()->onAPIQueryRecentChangesTokens( $this->tokenFunctions );
return $this->tokenFunctions;
}

View file

@ -63,7 +63,7 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
$this->tokenFunctions = [
'rollback' => [ self::class, 'getRollbackToken' ]
];
Hooks::run( 'APIQueryRevisionsTokens', [ &$this->tokenFunctions ], '1.24' );
$this->getHookRunner()->onAPIQueryRevisionsTokens( $this->tokenFunctions );
return $this->tokenFunctions;
}

View file

@ -276,7 +276,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
$data['categorycollation'] = $config->get( 'CategoryCollation' );
Hooks::run( 'APIQuerySiteInfoGeneralInfo', [ $this, &$data ] );
$this->getHookRunner()->onAPIQuerySiteInfoGeneralInfo( $this, $data );
return $this->getResult()->addValue( 'query', $property, $data );
}
@ -503,7 +503,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
$data['admins'] = (int)SiteStats::numberingroup( 'sysop' );
$data['jobs'] = (int)SiteStats::jobs();
Hooks::run( 'APIQuerySiteInfoStatisticsInfo', [ &$data ] );
$this->getHookRunner()->onAPIQuerySiteInfoStatisticsInfo( $data );
return $this->getResult()->addValue( 'query', $property, $data );
}

View file

@ -23,6 +23,9 @@
* @since 1.24
*/
use MediaWiki\Api\ApiHookRunner;
use MediaWiki\MediaWikiServices;
/**
* Module to fetch tokens via action=query&meta=tokens
*
@ -72,7 +75,9 @@ class ApiQueryTokens extends ApiQueryBase {
'login' => [ '', 'login' ],
'createaccount' => [ '', 'createaccount' ],
];
Hooks::run( 'ApiQueryTokensRegisterTypes', [ &$salts ] );
$hookContainer = MediaWikiServices::getInstance()->getHookContainer();
$hookRunner = new ApiHookRunner( $hookContainer );
$hookRunner->onApiQueryTokensRegisterTypes( $salts );
ksort( $salts );
}

View file

@ -78,7 +78,7 @@ class ApiQueryUsers extends ApiQueryBase {
$this->tokenFunctions = [
'userrights' => [ self::class, 'getUserrightsToken' ],
];
Hooks::run( 'APIQueryUsersTokens', [ &$this->tokenFunctions ], '1.24' );
$this->getHookRunner()->onAPIQueryUsersTokens( $this->tokenFunctions );
return $this->tokenFunctions;
}

View file

@ -174,9 +174,8 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
$options['limit'] = $params['limit'];
Hooks::run( 'ApiQueryWatchlistPrepareWatchedItemQueryServiceOptions', [
$this, $params, &$options
] );
$this->getHookRunner()->onApiQueryWatchlistPrepareWatchedItemQueryServiceOptions(
$this, $params, $options );
$ids = [];
$services = MediaWikiServices::getInstance();
@ -427,9 +426,8 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
$vals['suppressed'] = true;
}
Hooks::run( 'ApiQueryWatchlistExtractOutputData', [
$this, $watchedItem, $recentChangeInfo, &$vals
] );
$this->getHookRunner()->onApiQueryWatchlistExtractOutputData(
$this, $watchedItem, $recentChangeInfo, $vals );
return $vals;
}

View file

@ -74,7 +74,7 @@ class ApiRemoveAuthenticationData extends ApiBase {
// Perform the removal
$status = $manager->allowsAuthenticationDataChange( $req, true );
Hooks::run( 'ChangeAuthenticationDataAudit', [ $req, $status ] );
$this->getHookRunner()->onChangeAuthenticationDataAudit( $req, $status );
if ( !$status->isGood() ) {
$this->dieStatus( $status );
}

View file

@ -100,7 +100,7 @@ class ApiRsd extends ApiBase {
]
],
];
Hooks::run( 'ApiRsdServiceApis', [ &$apis ] );
$this->getHookRunner()->onApiRsdServiceApis( $apis );
return $apis;
}

View file

@ -68,7 +68,7 @@ class ApiTokens extends ApiBase {
foreach ( $names as $name ) {
$types[$name] = [ ApiQueryInfo::class, 'get' . ucfirst( $name ) . 'Token' ];
}
Hooks::run( 'ApiTokensGetTokenTypes', [ &$types ], '1.24' );
$this->getHookRunner()->onApiTokensGetTokenTypes( $types );
// For forwards-compat, copy any token types from ApiQueryTokens that
// we don't already have something for.

View file

@ -78,8 +78,9 @@ class ApiUndelete extends ApiBase {
}
if ( $retval[1] ) {
Hooks::run( 'FileUndeleteComplete',
[ $titleObj, $params['fileids'], $this->getUser(), $params['reason'] ] );
$this->getHookRunner()->onFileUndeleteComplete(
$titleObj, $params['fileids'],
$this->getUser(), $params['reason'] );
}
$this->setWatch( $params['watchlist'], $titleObj );

View file

@ -45,7 +45,7 @@ class ApiValidatePassword extends ApiBase {
$r['validitymessages'] = $messages;
}
Hooks::run( 'ApiValidatePassword', [ $this, &$r ] );
$this->getHookRunner()->onApiValidatePassword( $this, $r );
$this->getResult()->addValue( null, $this->getModuleName(), $r );
}

View file

@ -22,6 +22,8 @@
namespace MediaWiki\Auth;
use Config;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
use Psr\Log\LoggerInterface;
/**
@ -36,6 +38,10 @@ abstract class AbstractAuthenticationProvider implements AuthenticationProvider
protected $manager;
/** @var Config */
protected $config;
/** @var HookContainer */
private $hookContainer;
/** @var HookRunner */
private $hookRunner;
public function setLogger( LoggerInterface $logger ) {
$this->logger = $logger;
@ -49,6 +55,11 @@ abstract class AbstractAuthenticationProvider implements AuthenticationProvider
$this->config = $config;
}
public function setHookContainer( HookContainer $hookContainer ) {
$this->hookContainer = $hookContainer;
$this->hookRunner = new HookRunner( $hookContainer );
}
/**
* @inheritDoc
* @note Override this if it makes sense to support more than one instance
@ -56,4 +67,22 @@ abstract class AbstractAuthenticationProvider implements AuthenticationProvider
public function getUniqueId() {
return static::class;
}
/**
* @since 1.35
* @return HookContainer
*/
protected function getHookContainer() : HookContainer {
return $this->hookContainer;
}
/**
* @internal This is for use by core only. Hook interfaces may be removed
* without notice.
* @since 1.35
* @return HookRunner
*/
protected function getHookRunner() : HookRunner {
return $this->hookRunner;
}
}

View file

@ -158,7 +158,8 @@ abstract class AbstractPasswordPrimaryAuthenticationProvider
$expires = $days ? wfTimestamp( TS_MW, time() + $days * 86400 ) : null;
// Give extensions a chance to force an expiration
\Hooks::run( 'ResetPasswordExpiration', [ \User::newFromName( $username ), &$expires ] );
$this->getHookRunner()->onResetPasswordExpiration(
\User::newFromName( $username ), $expires );
return $expires;
}

View file

@ -24,6 +24,8 @@
namespace MediaWiki\Auth;
use Config;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\MediaWikiServices;
use MediaWiki\Permissions\PermissionManager;
use Psr\Log\LoggerAwareInterface;
@ -155,6 +157,12 @@ class AuthManager implements LoggerAwareInterface {
/** @var CreatedAccountAuthenticationRequest[] */
private $createdAccountAuthenticationRequests = [];
/** @var HookContainer */
private $hookContainer;
/** @var HookRunner */
private $hookRunner;
/**
* Get the global AuthManager
* @return AuthManager
@ -169,17 +177,21 @@ class AuthManager implements LoggerAwareInterface {
* @param Config $config
* @param ObjectFactory $objectFactory
* @param PermissionManager $permManager
* @param HookContainer $hookContainer
*/
public function __construct(
WebRequest $request,
Config $config,
ObjectFactory $objectFactory,
PermissionManager $permManager
PermissionManager $permManager,
HookContainer $hookContainer
) {
$this->request = $request;
$this->config = $config;
$this->objectFactory = $objectFactory;
$this->permManager = $permManager;
$this->hookContainer = $hookContainer;
$this->hookRunner = new HookRunner( $hookContainer );
$this->setLogger( new NullLogger() );
}
@ -233,6 +245,7 @@ class AuthManager implements LoggerAwareInterface {
$provider->setLogger( $this->logger );
$provider->setManager( $this );
$provider->setConfig( $this->config );
$provider->setHookContainer( $this->hookContainer );
$id = $provider->getUniqueId();
if ( isset( $this->allAuthenticationProviders[$id] ) ) {
throw new \RuntimeException(
@ -336,7 +349,8 @@ class AuthManager implements LoggerAwareInterface {
$this->setSessionDataForUser( $user );
$this->callMethodOnProviders( 7, 'postAuthentication', [ $user, $ret ] );
$session->remove( 'AuthManager::authnState' );
\Hooks::run( 'AuthManagerLoginAuthenticateAudit', [ $ret, $user, $user->getName(), [] ] );
$this->getHookRunner()->onAuthManagerLoginAuthenticateAudit(
$ret, $user, $user->getName(), [] );
return $ret;
}
@ -352,7 +366,7 @@ class AuthManager implements LoggerAwareInterface {
$this->callMethodOnProviders( 7, 'postAuthentication',
[ User::newFromName( $guessUserName ) ?: null, $ret ]
);
\Hooks::run( 'AuthManagerLoginAuthenticateAudit', [ $ret, null, $guessUserName, [] ] );
$this->getHookRunner()->onAuthManagerLoginAuthenticateAudit( $ret, null, $guessUserName, [] );
return $ret;
}
}
@ -468,7 +482,8 @@ class AuthManager implements LoggerAwareInterface {
[ User::newFromName( $guessUserName ) ?: null, $res ]
);
$session->remove( 'AuthManager::authnState' );
\Hooks::run( 'AuthManagerLoginAuthenticateAudit', [ $res, null, $guessUserName, [] ] );
$this->getHookRunner()->onAuthManagerLoginAuthenticateAudit(
$res, null, $guessUserName, [] );
return $res;
case AuthenticationResponse::ABSTAIN;
// Continue loop
@ -534,7 +549,8 @@ class AuthManager implements LoggerAwareInterface {
[ User::newFromName( $guessUserName ) ?: null, $res ]
);
$session->remove( 'AuthManager::authnState' );
\Hooks::run( 'AuthManagerLoginAuthenticateAudit', [ $res, null, $guessUserName, [] ] );
$this->getHookRunner()->onAuthManagerLoginAuthenticateAudit(
$res, null, $guessUserName, [] );
return $res;
case AuthenticationResponse::REDIRECT;
case AuthenticationResponse::UI;
@ -625,7 +641,8 @@ class AuthManager implements LoggerAwareInterface {
);
$this->callMethodOnProviders( 7, 'postAuthentication', [ $user, $ret ] );
$session->remove( 'AuthManager::authnState' );
\Hooks::run( 'AuthManagerLoginAuthenticateAudit', [ $ret, $user, $user->getName(), [] ] );
$this->getHookRunner()->onAuthManagerLoginAuthenticateAudit(
$ret, $user, $user->getName(), [] );
return $ret;
}
}
@ -658,7 +675,8 @@ class AuthManager implements LoggerAwareInterface {
$this->logger->debug( "Login failed in secondary authentication by $id" );
$this->callMethodOnProviders( 7, 'postAuthentication', [ $user, $res ] );
$session->remove( 'AuthManager::authnState' );
\Hooks::run( 'AuthManagerLoginAuthenticateAudit', [ $res, $user, $user->getName(), [] ] );
$this->getHookRunner()->onAuthManagerLoginAuthenticateAudit(
$res, $user, $user->getName(), [] );
return $res;
case AuthenticationResponse::REDIRECT;
case AuthenticationResponse::UI;
@ -694,7 +712,8 @@ class AuthManager implements LoggerAwareInterface {
$this->callMethodOnProviders( 7, 'postAuthentication', [ $user, $ret ] );
$session->remove( 'AuthManager::authnState' );
$this->removeAuthenticationSessionData( null );
\Hooks::run( 'AuthManagerLoginAuthenticateAudit', [ $ret, $user, $user->getName(), [] ] );
$this->getHookRunner()->onAuthManagerLoginAuthenticateAudit(
$ret, $user, $user->getName(), [] );
return $ret;
} catch ( \Exception $ex ) {
$session->remove( 'AuthManager::authnState' );
@ -763,9 +782,8 @@ class AuthManager implements LoggerAwareInterface {
}
}
\Hooks::run( 'SecuritySensitiveOperationStatus', [
&$status, $operation, $session, $timeSinceLogin
] );
$this->getHookRunner()->onSecuritySensitiveOperationStatus(
$status, $operation, $session, $timeSinceLogin );
// If authentication is not possible, downgrade from "REAUTH" to "FAIL".
if ( !$this->canAuthenticateNow() && $status === self::SEC_REAUTH ) {
@ -1425,7 +1443,7 @@ class AuthManager implements LoggerAwareInterface {
// @codeCoverageIgnoreEnd
}
$this->setDefaultUserOptions( $user, $creator->isAnon() );
\Hooks::runWithoutAbort( 'LocalUserCreated', [ $user, false ] );
$this->getHookRunner()->onLocalUserCreated( $user, false );
$user->saveSettings();
$state['userid'] = $user->getId();
@ -1745,7 +1763,7 @@ class AuthManager implements LoggerAwareInterface {
// Inform the providers
$this->callMethodOnProviders( 6, 'autoCreatedAccount', [ $user, $source ] );
\Hooks::run( 'LocalUserCreated', [ $user, true ] );
$this->getHookRunner()->onLocalUserCreated( $user, true );
$user->saveSettings();
// Update user count
@ -2322,6 +2340,7 @@ class AuthManager implements LoggerAwareInterface {
$provider->setLogger( $this->logger );
$provider->setManager( $this );
$provider->setConfig( $this->config );
$provider->setHookContainer( $this->getHookContainer() );
$id = $provider->getUniqueId();
if ( isset( $this->allAuthenticationProviders[$id] ) ) {
throw new \RuntimeException(
@ -2409,7 +2428,7 @@ class AuthManager implements LoggerAwareInterface {
\Wikimedia\ScopedCallback::consume( $delay );
\Hooks::run( 'UserLoggedIn', [ $user ] );
$this->getHookRunner()->onUserLoggedIn( $user );
}
/**
@ -2466,6 +2485,20 @@ class AuthManager implements LoggerAwareInterface {
self::$instance = null;
}
/**
* @return HookContainer
*/
private function getHookContainer() {
return $this->hookContainer;
}
/**
* @return HookRunner
*/
private function getHookRunner() {
return $this->hookRunner;
}
/** @} */
}

View file

@ -24,6 +24,7 @@
namespace MediaWiki\Auth;
use Config;
use MediaWiki\HookContainer\HookContainer;
use Psr\Log\LoggerAwareInterface;
/**
@ -50,6 +51,12 @@ interface AuthenticationProvider extends LoggerAwareInterface {
*/
public function setConfig( Config $config );
/**
* Set the HookContainer
* @param HookContainer $hookContainer
*/
public function setHookContainer( HookContainer $hookContainer );
/**
* Return a unique identifier for this instance
*

View file

@ -439,7 +439,7 @@ class TemporaryPasswordPrimaryAuthenticationProvider
}
// @codeCoverageIgnoreEnd
\Hooks::run( 'User::mailPasswordInternal', [ &$creatingUser, &$ip, &$user ] );
$this->getHookRunner()->onUser__mailPasswordInternal( $creatingUser, $ip, $user );
$mainPageUrl = \Title::newMainPage()->getCanonicalURL();
$userLanguage = $user->getOption( 'language' );

View file

@ -105,7 +105,7 @@ class ThrottlePreAuthenticationProvider extends AbstractPreAuthenticationProvide
$ip = $this->manager->getRequest()->getIP();
if ( !\Hooks::run( 'ExemptFromAccountCreationThrottle', [ $ip ] ) ) {
if ( !$this->getHookRunner()->onExemptFromAccountCreationThrottle( $ip ) ) {
$this->logger->debug( __METHOD__ . ": a hook allowed account creation w/o throttle\n" );
return \StatusValue::newGood();
}

View file

@ -22,9 +22,10 @@ namespace MediaWiki\Block;
use DateTime;
use DateTimeZone;
use Hooks;
use LogicException;
use MediaWiki\Config\ServiceOptions;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\Permissions\PermissionManager;
use MediaWiki\User\UserIdentity;
use Message;
@ -68,20 +69,26 @@ class BlockManager {
/** @var LoggerInterface */
private $logger;
/** @var HookRunner */
private $hookRunner;
/**
* @param ServiceOptions $options
* @param PermissionManager $permissionManager
* @param LoggerInterface $logger
* @param HookContainer $hookContainer
*/
public function __construct(
ServiceOptions $options,
PermissionManager $permissionManager,
LoggerInterface $logger
LoggerInterface $logger,
HookContainer $hookContainer
) {
$options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
$this->options = $options;
$this->permissionManager = $permissionManager;
$this->logger = $logger;
$this->hookRunner = new HookRunner( $hookContainer );
}
/**
@ -159,7 +166,7 @@ class BlockManager {
}
}
Hooks::run( 'GetUserBlock', [ clone $user, $ip, &$block ] );
$this->hookRunner->onGetUserBlock( clone $user, $ip, $block );
return $block;
}

View file

@ -710,8 +710,7 @@ class DatabaseBlock extends AbstractBlock {
if ( $this->isAutoblocking() && $this->getType() == self::TYPE_USER ) {
wfDebug( "Doing retroactive autoblocks for " . $this->getTarget() . "\n" );
$continue = Hooks::run(
'PerformRetroactiveAutoblock', [ $this, &$blockIds ] );
$continue = Hooks::runner()->onPerformRetroactiveAutoblock( $this, $blockIds );
if ( $continue ) {
self::defaultRetroactiveAutoblock( $this, $blockIds );
@ -837,10 +836,8 @@ class DatabaseBlock extends AbstractBlock {
return false;
}
// Avoid PHP 7.1 warning of passing $this by reference
$block = $this;
# Allow hooks to cancel the autoblock.
if ( !Hooks::run( 'AbortAutoblock', [ $autoblockIP, &$block ] ) ) {
if ( !Hooks::runner()->onAbortAutoblock( $autoblockIP, $this ) ) {
wfDebug( "Autoblock aborted by hook.\n" );
return false;
}

View file

@ -25,6 +25,7 @@
* @copyright © 2011, Antoine Musso
*/
use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
use MediaWiki\MediaWikiServices;
use Wikimedia\Rdbms\FakeResultWrapper;
use Wikimedia\Rdbms\IDatabase;
@ -44,6 +45,8 @@ use Wikimedia\Rdbms\IResultWrapper;
* Introduced by r47317
*/
class BacklinkCache {
use ProtectedHookAccessorTrait;
/** @var BacklinkCache */
protected static $instance;
@ -256,7 +259,7 @@ class BacklinkCache {
return $prefixes[$table];
} else {
$prefix = null;
Hooks::run( 'BacklinkCacheGetPrefix', [ $table, &$prefix ] );
$this->getHookRunner()->onBacklinkCacheGetPrefix( $table, $prefix );
if ( $prefix ) {
return $prefix;
} else {
@ -304,7 +307,7 @@ class BacklinkCache {
break;
default:
$conds = null;
Hooks::run( 'BacklinkCacheGetConditions', [ $table, $this->title, &$conds ] );
$this->getHookRunner()->onBacklinkCacheGetConditions( $table, $this->title, $conds );
if ( !$conds ) {
throw new MWException( "Invalid table \"$table\" in " . __CLASS__ );
}

View file

@ -131,7 +131,7 @@ class HTMLFileCache extends FileCacheBase {
}
// Allow extensions to disable caching
return Hooks::run( 'HTMLFileCache::useFileCache', [ $context ] );
return Hooks::runner()->onHTMLFileCache__useFileCache( $context );
}
/**

View file

@ -18,6 +18,9 @@
* @file
*/
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
/**
* Class to invalidate the CDN and HTMLFileCache entries associated with URLs/titles
*
@ -32,6 +35,9 @@ class HtmlCacheUpdater {
/** @var int Max seconds for CDN to served cached objects without revalidation */
private $cdnMaxAge;
/** @var HookRunner */
private $hookRunner;
/** @var int Issue purge immediately and do not schedule a rebound purge */
public const PURGE_NAIVE = 0;
/**
@ -75,12 +81,16 @@ class HtmlCacheUpdater {
public const UNLESS_CACHE_MTIME_AFTER = 'unless-timestamp-exceeds';
/**
* @param HookContainer $hookContainer
* @param int $reboundDelay $wgCdnReboundPurgeDelay
* @param bool $useFileCache $wgUseFileCache
* @param int $cdnMaxAge $wgCdnMaxAge
* @internal For use with MediaWikiServices->getHtmlCacheUpdater()
*/
public function __construct( $reboundDelay, $useFileCache, $cdnMaxAge ) {
public function __construct( HookContainer $hookContainer, $reboundDelay,
$useFileCache, $cdnMaxAge
) {
$this->hookRunner = new HookRunner( $hookContainer );
$this->reboundDelay = $reboundDelay;
$this->useFileCache = $useFileCache;
$this->cdnMaxAge = $cdnMaxAge;
@ -192,16 +202,16 @@ class HtmlCacheUpdater {
// Extensions may add novel ways to access this content
$append = [];
$mode = $flags & self::PURGE_URLS_LINKSUPDATE_ONLY;
Hooks::run( 'HtmlCacheUpdaterAppendUrls', [ $title, $mode, &$append ] );
$this->hookRunner->onHtmlCacheUpdaterAppendUrls( $title, $mode, $append );
$urls = array_merge( $urls, $append );
// Extensions may add novel ways to access the site overall
$append = [];
Hooks::run( 'HtmlCacheUpdaterVaryUrls', [ $urls, &$append ] );
$this->hookRunner->onHtmlCacheUpdaterVaryUrls( $urls, $append );
$urls = array_merge( $urls, $append );
// Legacy. TODO: Deprecate this
Hooks::run( 'TitleSquidURLs', [ $title, &$urls ] );
$this->hookRunner->onTitleSquidURLs( $title, $urls );
return $urls;
}

View file

@ -20,6 +20,9 @@
* @file
* @ingroup Cache
*/
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\Languages\LanguageFactory;
use MediaWiki\Languages\LanguageFallback;
use MediaWiki\Languages\LanguageNameUtils;
@ -117,6 +120,8 @@ class MessageCache implements LoggerAwareInterface {
protected $languageNameUtils;
/** @var LanguageFallback */
protected $languageFallback;
/** @var HookRunner */
private $hookRunner;
/**
* Get the singleton instance of this class
@ -161,6 +166,7 @@ class MessageCache implements LoggerAwareInterface {
* @param LocalisationCache $localisationCache
* @param LanguageNameUtils $languageNameUtils
* @param LanguageFallback $languageFallback
* @param HookContainer $hookContainer
*/
public function __construct(
WANObjectCache $wanCache,
@ -173,7 +179,8 @@ class MessageCache implements LoggerAwareInterface {
LanguageFactory $langFactory,
LocalisationCache $localisationCache,
LanguageNameUtils $languageNameUtils,
LanguageFallback $languageFallback
LanguageFallback $languageFallback,
HookContainer $hookContainer
) {
$this->wanCache = $wanCache;
$this->clusterCache = $clusterCache;
@ -185,6 +192,7 @@ class MessageCache implements LoggerAwareInterface {
$this->localisationCache = $localisationCache;
$this->languageNameUtils = $languageNameUtils;
$this->languageFallback = $languageFallback;
$this->hookRunner = new HookRunner( $hookContainer );
$this->cache = new MapCacheLRU( 5 ); // limit size for sanity
@ -754,7 +762,7 @@ class MessageCache implements LoggerAwareInterface {
$blobStore = MediaWikiServices::getInstance()->getResourceLoader()->getMessageBlobStore();
foreach ( $replacements as list( $title, $msg ) ) {
$blobStore->updateMessage( $this->contLang->lcfirst( $msg ) );
Hooks::run( 'MessageCacheReplace', [ $title, $newTextByTitle[$title] ] );
$this->hookRunner->onMessageCacheReplace( $title, $newTextByTitle[$title] );
}
}
@ -913,7 +921,7 @@ class MessageCache implements LoggerAwareInterface {
// Normalise title-case input (with some inlining)
$lckey = self::normalizeKey( $key );
Hooks::run( 'MessageCache::get', [ &$lckey ] );
$this->hookRunner->onMessageCache__get( $lckey );
// Loop through each language in the fallback list until we find something useful
$message = $this->getMessageFromFallbackChain(
@ -1115,7 +1123,7 @@ class MessageCache implements LoggerAwareInterface {
if ( $entry === null || substr( $entry, 0, 1 ) !== ' ' ) {
// Message does not have a MediaWiki page definition; try hook handlers
$message = false;
Hooks::run( 'MessagesPreLoad', [ $title, &$message, $code ] );
$this->hookRunner->onMessagesPreLoad( $title, $message, $code );
if ( $message !== false ) {
$this->cache->setField( $code, $title, ' ' . $message );
} else {

View file

@ -23,6 +23,8 @@
use CLDRPluralRuleParser\Error as CLDRPluralRuleError;
use CLDRPluralRuleParser\Evaluator;
use MediaWiki\Config\ServiceOptions;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\Languages\LanguageNameUtils;
use Psr\Log\LoggerInterface;
@ -71,6 +73,9 @@ class LocalisationCache {
*/
private $logger;
/** @var HookRunner */
private $hookRunner;
/** @var callable[] See comment for parameter in constructor */
private $clearStoreCallbacks;
@ -249,6 +254,7 @@ class LocalisationCache {
* used to clear other caches that depend on this one, such as ResourceLoader's
* MessageBlobStore.
* @param LanguageNameUtils $langNameUtils
* @param HookContainer $hookContainer
* @throws MWException
*/
public function __construct(
@ -256,7 +262,8 @@ class LocalisationCache {
LCStore $store,
LoggerInterface $logger,
array $clearStoreCallbacks,
LanguageNameUtils $langNameUtils
LanguageNameUtils $langNameUtils,
HookContainer $hookContainer
) {
$options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
@ -265,6 +272,7 @@ class LocalisationCache {
$this->logger = $logger;
$this->clearStoreCallbacks = $clearStoreCallbacks;
$this->langNameUtils = $langNameUtils;
$this->hookRunner = new HookRunner( $hookContainer );
// Keep this separate from $this->options so it can be mutable
$this->manualRecache = $options->get( 'manualRecache' );
@ -957,7 +965,7 @@ class LocalisationCache {
# Allow extensions an opportunity to adjust the data for this
# fallback
Hooks::run( 'LocalisationCacheRecacheFallback', [ $this, $csCode, &$csData ] );
$this->hookRunner->onLocalisationCacheRecacheFallback( $this, $csCode, $csData );
# Merge the data for this fallback into the final array
if ( $csCode === $code ) {
@ -1014,7 +1022,7 @@ class LocalisationCache {
}
# Run hooks
$unused = true; // Used to be $purgeBlobs, removed in 1.34
Hooks::run( 'LocalisationCacheRecache', [ $this, $code, &$allData, &$unused ] );
$this->hookRunner->onLocalisationCacheRecache( $this, $code, $allData, $unused );
if ( $allData['namespaceNames'] === null ) {
throw new MWException( __METHOD__ . ': Localisation data failed sanity check! ' .

View file

@ -387,9 +387,7 @@ class RecentChange implements Taggable {
$this->mAttribs['rc_id'] = $dbw->insertId();
# Notify extensions
// Avoid PHP 7.1 warning from passing $this by reference
$rc = $this;
Hooks::run( 'RecentChange_save', [ &$rc ] );
Hooks::runner()->onRecentChange_save( $this );
if ( count( $this->tags ) ) {
ChangeTags::addTags( $this->tags, $this->mAttribs['rc_id'],
@ -408,7 +406,7 @@ class RecentChange implements Taggable {
// Never send an RC notification email about categorization changes
if (
Hooks::run( 'AbortEmailNotification', [ $editor, $title, $this ] ) &&
Hooks::runner()->onAbortEmailNotification( $editor, $title, $this ) &&
$this->mAttribs['rc_type'] != RC_CATEGORIZE
) {
// @FIXME: This would be better as an extension hook
@ -564,8 +562,8 @@ class RecentChange implements Taggable {
$errors,
$permManager->getPermissionErrors( $right, $user, $this->getTitle() )
);
if ( !Hooks::run( 'MarkPatrolled',
[ $this->getAttribute( 'rc_id' ), &$user, false, $auto, &$tags ] )
if ( !Hooks::runner()->onMarkPatrolled(
$this->getAttribute( 'rc_id' ), $user, false, $auto, $tags )
) {
$errors[] = [ 'hookaborted' ];
}
@ -588,10 +586,8 @@ class RecentChange implements Taggable {
// Log this patrol event
PatrolLog::record( $this, $auto, $user, $tags );
Hooks::run(
'MarkPatrolledComplete',
[ $this->getAttribute( 'rc_id' ), &$user, false, $auto ]
);
Hooks::runner()->onMarkPatrolledComplete(
$this->getAttribute( 'rc_id' ), $user, false, $auto );
return [];
}

View file

@ -21,6 +21,7 @@
* @ingroup Change tagging
*/
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\MediaWikiServices;
use MediaWiki\Storage\NameTableAccessException;
use Wikimedia\Rdbms\Database;
@ -451,8 +452,8 @@ class ChangeTags {
}
}
Hooks::run( 'ChangeTagsAfterUpdateTags', [ $tagsToAdd, $tagsToRemove, $prevTags,
$rc_id, $rev_id, $log_id, $params, $rc, $user ] );
Hooks::runner()->onChangeTagsAfterUpdateTags( $tagsToAdd, $tagsToRemove, $prevTags,
$rc_id, $rev_id, $log_id, $params, $rc, $user );
return [ $tagsToAdd, $tagsToRemove, $prevTags ];
}
@ -538,7 +539,7 @@ class ChangeTags {
// to be applied, a tag has to be explicitly defined
$allowedTags = self::listExplicitlyDefinedTags();
Hooks::run( 'ChangeTagsAllowedAdd', [ &$allowedTags, $tags, $user ] );
Hooks::runner()->onChangeTagsAllowedAdd( $allowedTags, $tags, $user );
$disallowedTags = array_diff( $tags, $allowedTags );
if ( $disallowedTags ) {
return self::restrictedTagError( 'tags-apply-not-allowed-one',
@ -1219,7 +1220,7 @@ class ChangeTags {
// check with hooks
$canCreateResult = Status::newGood();
Hooks::run( 'ChangeTagCanCreate', [ $tag, $user, &$canCreateResult ] );
Hooks::runner()->onChangeTagCanCreate( $tag, $user, $canCreateResult );
return $canCreateResult;
}
@ -1291,7 +1292,7 @@ class ChangeTags {
// give extensions a chance
$status = Status::newGood();
Hooks::run( 'ChangeTagAfterDelete', [ $tag, &$status ] );
Hooks::runner()->onChangeTagAfterDelete( $tag, $status );
// let's not allow error results, as the actual tag deletion succeeded
if ( !$status->isOK() ) {
wfDebug( 'ChangeTagAfterDelete error condition downgraded to warning' );
@ -1350,7 +1351,7 @@ class ChangeTags {
$status = Status::newGood();
}
Hooks::run( 'ChangeTagCanDelete', [ $tag, $user, &$status ] );
Hooks::runner()->onChangeTagCanDelete( $tag, $user, $status );
return $status;
}
@ -1408,18 +1409,20 @@ class ChangeTags {
public static function listSoftwareActivatedTags() {
// core active tags
$tags = self::getSoftwareTags();
if ( !Hooks::isRegistered( 'ChangeTagsListActive' ) ) {
$hookContainer = MediaWikiServices::getInstance()->getHookContainer();
if ( !$hookContainer->isRegistered( 'ChangeTagsListActive' ) ) {
return $tags;
}
$hookRunner = new HookRunner( $hookContainer );
$cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
return $cache->getWithSetCallback(
$cache->makeKey( 'active-tags' ),
WANObjectCache::TTL_MINUTE * 5,
function ( $oldValue, &$ttl, array &$setOpts ) use ( $tags ) {
function ( $oldValue, &$ttl, array &$setOpts ) use ( $tags, $hookRunner ) {
$setOpts += Database::getCacheSetOptions( wfGetDB( DB_REPLICA ) );
// Ask extensions which tags they consider active
Hooks::run( 'ChangeTagsListActive', [ &$tags ] );
$hookRunner->onChangeTagsListActive( $tags );
return $tags;
},
[
@ -1491,17 +1494,19 @@ class ChangeTags {
public static function listSoftwareDefinedTags() {
// core defined tags
$tags = self::getSoftwareTags( true );
if ( !Hooks::isRegistered( 'ListDefinedTags' ) ) {
$hookContainer = MediaWikiServices::getInstance()->getHookContainer();
if ( !$hookContainer->isRegistered( 'ListDefinedTags' ) ) {
return $tags;
}
$hookRunner = new HookRunner( $hookContainer );
$cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
return $cache->getWithSetCallback(
$cache->makeKey( 'valid-tags-hook' ),
WANObjectCache::TTL_MINUTE * 5,
function ( $oldValue, &$ttl, array &$setOpts ) use ( $tags ) {
function ( $oldValue, &$ttl, array &$setOpts ) use ( $tags, $hookRunner ) {
$setOpts += Database::getCacheSetOptions( wfGetDB( DB_REPLICA ) );
Hooks::run( 'ListDefinedTags', [ &$tags ] );
$hookRunner->onListDefinedTags( $tags );
return array_filter( array_unique( $tags ) );
},
[

View file

@ -74,7 +74,7 @@ abstract class Collation {
# Provide a mechanism for extensions to hook in.
$collationObject = null;
Hooks::run( 'Collation::factory', [ $collationName, &$collationObject ] );
Hooks::runner()->onCollation__factory( $collationName, $collationObject );
if ( $collationObject instanceof self ) {
return $collationObject;

View file

@ -286,7 +286,7 @@ abstract class AbstractContent implements Content {
new LinksUpdate( $title, $parserOutput, $recursive )
];
Hooks::run( 'SecondaryDataUpdates', [ $title, $old, $recursive, $parserOutput, &$updates ] );
Hooks::runner()->onSecondaryDataUpdates( $title, $old, $recursive, $parserOutput, $updates );
return $updates;
}
@ -520,7 +520,7 @@ abstract class AbstractContent implements Content {
$lossy = ( $lossy === 'lossy' ); // string flag, convert to boolean for convenience
$result = false;
Hooks::run( 'ConvertContent', [ $this, $toModel, $lossy, &$result ] );
Hooks::runner()->onConvertContent( $this, $toModel, $lossy, $result );
return $result;
}
@ -555,8 +555,8 @@ abstract class AbstractContent implements Content {
$po = new ParserOutput();
$options->registerWatcher( [ $po, 'recordOption' ] );
if ( Hooks::run( 'ContentGetParserOutput',
[ $this, $title, $revId, $options, $generateHtml, &$po ] )
if ( Hooks::runner()->onContentGetParserOutput(
$this, $title, $revId, $options, $generateHtml, $po )
) {
// Save and restore the old value, just in case something is reusing
// the ParserOptions object in some weird way.
@ -566,7 +566,7 @@ abstract class AbstractContent implements Content {
$options->setRedirectTarget( $oldRedir );
}
Hooks::run( 'ContentAlterParserOutput', [ $this, $title, $po ] );
Hooks::runner()->onContentAlterParserOutput( $this, $title, $po );
$options->registerWatcher( null );
return $po;

View file

@ -26,6 +26,7 @@
* @author Daniel Kinzler
*/
use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
use MediaWiki\Logger\LoggerFactory;
use MediaWiki\MediaWikiServices;
use MediaWiki\Revision\RevisionRecord;
@ -54,6 +55,8 @@ use Wikimedia\Assert\Assert;
* @ingroup Content
*/
abstract class ContentHandler {
use ProtectedHookAccessorTrait;
/**
* Convenience function for getting flat text from a Content object. This
* should only be used in the context of backwards compatibility with code
@ -584,8 +587,8 @@ abstract class ContentHandler {
) {
$diffEngineClass = $this->getDiffEngineClass();
$differenceEngine = new $diffEngineClass( $context, $old, $new, $rcid, $refreshCache, $unhide );
Hooks::run( 'GetDifferenceEngine', [ $context, $old, $new, $refreshCache, $unhide,
&$differenceEngine ] );
$this->getHookRunner()->onGetDifferenceEngine(
$context, $old, $new, $refreshCache, $unhide, $differenceEngine );
return $differenceEngine;
}
@ -612,7 +615,7 @@ abstract class ContentHandler {
$slotDiffRenderer = new DifferenceEngineSlotDiffRenderer( $differenceEngine );
}
}
Hooks::run( 'GetSlotDiffRenderer', [ $this, &$slotDiffRenderer, $context ] );
$this->getHookRunner()->onGetSlotDiffRenderer( $this, $slotDiffRenderer, $context );
return $slotDiffRenderer;
}
@ -700,7 +703,7 @@ abstract class ContentHandler {
// else has unstubbed the StubUserLang object by now.
StubObject::unstub( $wgLang );
Hooks::run( 'PageContentLanguage', [ $title, &$pageLang, $wgLang ] );
$this->getHookRunner()->onPageContentLanguage( $title, $pageLang, $wgLang );
return wfGetLangObj( $pageLang );
}
@ -762,7 +765,7 @@ abstract class ContentHandler {
public function canBeUsedOn( Title $title ) {
$ok = true;
Hooks::run( 'ContentModelCanBeUsedOn', [ $this->getModelID(), $title, &$ok ] );
$this->getHookRunner()->onContentModelCanBeUsedOn( $this->getModelID(), $title, $ok );
return $ok;
}
@ -1341,7 +1344,7 @@ abstract class ContentHandler {
$fieldData['content_model'] = $content->getModel();
}
Hooks::run( 'SearchDataForIndex', [ &$fieldData, $this, $page, $output, $engine ] );
$this->getHookRunner()->onSearchDataForIndex( $fieldData, $this, $page, $output, $engine );
return $fieldData;
}

View file

@ -26,8 +26,9 @@ namespace MediaWiki\Content;
use ContentHandler;
use FatalError;
use Hooks;
use InvalidArgumentException;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
use MWException;
use MWUnknownContentModelException;
use UnexpectedValueException;
@ -56,6 +57,11 @@ final class ContentHandlerFactory implements IContentHandlerFactory {
*/
private $objectFactory;
/**
* @var HookRunner
*/
private $hookRunner;
/**
* @since 1.35
* @internal Use @see MediaWikiServices::getContentHandlerFactory
@ -64,10 +70,14 @@ final class ContentHandlerFactory implements IContentHandlerFactory {
* content model to the ObjectFactory spec used to construct its ContentHandler.
* This array typically comes from $wgContentHandlers.
* @param ObjectFactory $objectFactory
* @param HookContainer $hookContainer
*/
public function __construct( array $handlerSpecs, ObjectFactory $objectFactory ) {
public function __construct( array $handlerSpecs, ObjectFactory $objectFactory,
HookContainer $hookContainer
) {
$this->handlerSpecs = $handlerSpecs;
$this->objectFactory = $objectFactory;
$this->hookRunner = new HookRunner( $hookContainer );
}
/**
@ -117,7 +127,7 @@ final class ContentHandlerFactory implements IContentHandlerFactory {
*/
public function getContentModels(): array {
$modelsFromHook = [];
Hooks::run( 'GetContentModels', [ &$modelsFromHook ] );
$this->hookRunner->onGetContentModels( $modelsFromHook );
$models = array_merge( // auto-registered from config and MediaServiceWiki or manual
array_keys( $this->handlerSpecs ),
@ -246,7 +256,7 @@ final class ContentHandlerFactory implements IContentHandlerFactory {
*/
private function createContentHandlerFromHook( string $modelID ): ContentHandler {
$contentHandler = null;
Hooks::run( 'ContentHandlerForModelID', [ $modelID, &$contentHandler ] );
$this->hookRunner->onContentHandlerForModelID( $modelID, $contentHandler );
$this->validateContentHandler( $modelID, $contentHandler );
'@phan-var ContentHandler $contentHandler';

View file

@ -256,9 +256,8 @@ class ContentModelChange {
$newContent = $this->newContent;
if ( !Hooks::run( 'EditFilterMergedContent',
[ $derivativeContext, $newContent, $status, $reason,
$user, false ] )
if ( !Hooks::runner()->onEditFilterMergedContent( $derivativeContext, $newContent,
$status, $reason, $user, false )
) {
if ( $status->isGood() ) {
// TODO: extensions should really specify an error message

View file

@ -103,7 +103,7 @@ class WikitextContent extends TextContent {
# Inserting a new section
$subject = $sectionTitle ? wfMessage( 'newsectionheaderdefaultlevel' )
->plaintextParams( $sectionTitle )->inContentLanguage()->text() . "\n\n" : '';
if ( Hooks::run( 'PlaceNewSection', [ $this, $oldtext, $subject, &$text ] ) ) {
if ( Hooks::runner()->onPlaceNewSection( $this, $oldtext, $subject, $text ) ) {
$text = strlen( trim( $oldtext ) ) > 0
? "{$oldtext}\n\n{$subject}{$text}"
: "{$subject}{$text}";

View file

@ -364,7 +364,7 @@ class RequestContext implements IContextSource, MutableContext {
// NFC form given this will not convert to normalised form.
$code = self::sanitizeLangCode( $code );
Hooks::run( 'UserGetLanguageObject', [ $user, &$code, $this ] );
Hooks::runner()->onUserGetLanguageObject( $user, $code, $this );
if ( $code === $this->getConfig()->get( 'LanguageCode' ) ) {
$this->lang = MediaWikiServices::getInstance()->getContentLanguage();
@ -395,7 +395,7 @@ class RequestContext implements IContextSource, MutableContext {
public function getSkin() {
if ( $this->skin === null ) {
$skin = null;
Hooks::run( 'RequestContextCreateSkin', [ $this, &$skin ] );
Hooks::runner()->onRequestContextCreateSkin( $this, $skin );
$factory = MediaWikiServices::getInstance()->getSkinFactory();
if ( $skin instanceof Skin ) {

View file

@ -20,6 +20,7 @@
* @file
*/
use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
use MediaWiki\Logger\LoggerFactory;
use MediaWiki\MediaWikiServices;
use MediaWiki\Revision\RevisionRecord;
@ -34,6 +35,8 @@ use Wikimedia\ScopedCallback;
* See docs/deferred.txt
*/
class LinksUpdate extends DataUpdate {
use ProtectedHookAccessorTrait;
// @todo make members protected, but make sure extensions don't break
/** @var int Page ID of the article linked from */
@ -169,9 +172,7 @@ class LinksUpdate extends DataUpdate {
$this->mRecursive = $recursive;
// Avoid PHP 7.1 warning from passing $this by reference
$linksUpdate = $this;
Hooks::run( 'LinksUpdateConstructed', [ &$linksUpdate ] );
$this->getHookRunner()->onLinksUpdateConstructed( $this );
}
/**
@ -189,9 +190,7 @@ class LinksUpdate extends DataUpdate {
}
}
// Avoid PHP 7.1 warning from passing $this by reference
$linksUpdate = $this;
Hooks::run( 'LinksUpdate', [ &$linksUpdate ] );
$this->getHookRunner()->onLinksUpdate( $this );
$this->doIncrementalUpdate();
// Commit and release the lock (if set)
@ -201,9 +200,7 @@ class LinksUpdate extends DataUpdate {
$this->getDB(),
__METHOD__,
function () {
// Avoid PHP 7.1 warning from passing $this by reference
$linksUpdate = $this;
Hooks::run( 'LinksUpdateComplete', [ &$linksUpdate, $this->ticket ] );
$this->getHookRunner()->onLinksUpdateComplete( $this, $this->ticket );
}
) );
}
@ -517,7 +514,7 @@ class LinksUpdate extends DataUpdate {
}
if ( count( $insertions ) ) {
Hooks::run( 'LinksUpdateAfterInsert', [ $this, $table, $insertions ] );
$this->getHookRunner()->onLinksUpdateAfterInsert( $this, $table, $insertions );
}
}

View file

@ -22,6 +22,7 @@
*/
use MediaWiki\Content\IContentHandlerFactory;
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\Linker\LinkRenderer;
use MediaWiki\MediaWikiServices;
use MediaWiki\Revision\RevisionRecord;
@ -218,6 +219,9 @@ class DifferenceEngine extends ContextSource {
*/
private $revisionStore;
/** @var HookRunner */
private $hookRunner;
/** #@- */
/**
@ -256,6 +260,7 @@ class DifferenceEngine extends ContextSource {
$this->linkRenderer = $services->getLinkRenderer();
$this->contentHandlerFactory = $services->getContentHandlerFactory();
$this->revisionStore = $services->getRevisionStore();
$this->hookRunner = new HookRunner( $services->getHookContainer() );
}
/**
@ -597,10 +602,10 @@ class DifferenceEngine extends ContextSource {
$out->setRobotPolicy( 'noindex,nofollow' );
// Allow extensions to add any extra output here
Hooks::run( 'DifferenceEngineShowDiffPage', [ $out ] );
$this->hookRunner->onDifferenceEngineShowDiffPage( $out );
if ( !$this->loadRevisionData() ) {
if ( Hooks::run( 'DifferenceEngineShowDiffPageMaybeShowMissingRevision', [ $this ] ) ) {
if ( $this->hookRunner->onDifferenceEngineShowDiffPageMaybeShowMissingRevision( $this ) ) {
$this->showMissingRevision();
}
return;
@ -641,7 +646,7 @@ class DifferenceEngine extends ContextSource {
$samePage = true;
$oldHeader = '';
// Allow extensions to change the $oldHeader variable
Hooks::run( 'DifferenceEngineOldHeaderNoOldRev', [ &$oldHeader ] );
$this->hookRunner->onDifferenceEngineOldHeaderNoOldRev( $oldHeader );
} else {
// TODO replace hook with one that uses RevisionRecords
// If old or new are falsey, keeps those values
@ -651,7 +656,7 @@ class DifferenceEngine extends ContextSource {
$legacyNewRev = $this->mNewRevisionRecord ?
new Revision( $this->mNewRevisionRecord ) :
null;
Hooks::run( 'DiffViewHeader', [ $this, $legacyOldRev, $legacyNewRev ] );
$this->hookRunner->onDiffViewHeader( $this, $legacyOldRev, $legacyNewRev );
if ( !$this->mOldPage || !$this->mNewPage ) {
// XXX say something to the user?
@ -736,8 +741,8 @@ class DifferenceEngine extends ContextSource {
'<div id="mw-diff-otitle4">' . $prevlink . '</div>';
// Allow extensions to change the $oldHeader variable
Hooks::run( 'DifferenceEngineOldHeader', [ $this, &$oldHeader, $prevlink, $oldminor,
$diffOnly, $ldel, $this->unhide ] );
$this->hookRunner->onDifferenceEngineOldHeader(
$this, $oldHeader, $prevlink, $oldminor, $diffOnly, $ldel, $this->unhide );
}
$out->addJsConfigVars( [
@ -775,8 +780,8 @@ class DifferenceEngine extends ContextSource {
$legacyNewRev = $this->mNewRevisionRecord ?
new Revision( $this->mNewRevisionRecord ) :
null;
Hooks::run( 'DiffRevisionTools',
[ $legacyNewRev, &$revisionTools, $legacyOldRev, $user ] );
$this->hookRunner->onDiffRevisionTools(
$legacyNewRev, $revisionTools, $legacyOldRev, $user );
$formattedRevisionTools = [];
// Put each one in parentheses (poor man's button)
@ -805,8 +810,9 @@ class DifferenceEngine extends ContextSource {
'<div id="mw-diff-ntitle4">' . $nextlink . $this->markPatrolledLink() . '</div>';
// Allow extensions to change the $newHeader variable
Hooks::run( 'DifferenceEngineNewHeader', [ $this, &$newHeader, $formattedRevisionTools,
$nextlink, $rollback, $newminor, $diffOnly, $rdel, $this->unhide ] );
$this->hookRunner->onDifferenceEngineNewHeader( $this, $newHeader,
$formattedRevisionTools, $nextlink, $rollback, $newminor, $diffOnly,
$rdel, $this->unhide );
# If the diff cannot be shown due to a deleted revision, then output
# the diff header and links to unhide (if available)...
@ -874,8 +880,8 @@ class DifferenceEngine extends ContextSource {
]
) . ']</span>';
// Allow extensions to change the markpatrolled link
Hooks::run( 'DifferenceEngineMarkPatrolledLink', [ $this,
&$this->mMarkPatrolledLink, $linkInfo['rcid'] ] );
$this->hookRunner->onDifferenceEngineMarkPatrolledLink( $this,
$this->mMarkPatrolledLink, $linkInfo['rcid'] );
}
}
return $this->mMarkPatrolledLink;
@ -924,7 +930,7 @@ class DifferenceEngine extends ContextSource {
// For example the rcid might be set to zero due to the user
// being the same as the performer of the change but an extension
// might still want to show it under certain conditions
Hooks::run( 'DifferenceEngineMarkPatrolledRCID', [ &$rcid, $this, $change, $user ] );
$this->hookRunner->onDifferenceEngineMarkPatrolledRCID( $rcid, $this, $change, $user );
// Build the link
if ( $rcid ) {
@ -983,7 +989,7 @@ class DifferenceEngine extends ContextSource {
$out->addHTML( "<hr class='diff-hr' id='mw-oldid' />
<h2 class='diff-currentversion-title'>{$revHeader}</h2>\n" );
# Page content may be handled by a hooked call instead...
if ( Hooks::run( 'ArticleContentOnDiff', [ $this, $out ] ) ) {
if ( $this->hookRunner->onArticleContentOnDiff( $this, $out ) ) {
$this->loadNewText();
if ( !$this->mNewPage ) {
// New revision is unsaved; bail out.
@ -996,8 +1002,8 @@ class DifferenceEngine extends ContextSource {
$out->setRevisionTimestamp( $this->mNewRevisionRecord->getTimestamp() );
$out->setArticleFlag( true );
if ( !Hooks::run( 'ArticleRevisionViewCustom',
[ $this->mNewRevisionRecord, $this->mNewPage, $this->mOldid, $out ] )
if ( !$this->hookRunner->onArticleRevisionViewCustom(
$this->mNewRevisionRecord, $this->mNewPage, $this->mOldid, $out )
) {
// Handled by extension
// NOTE: sync with hooks called in Article::view()
@ -1018,8 +1024,8 @@ class DifferenceEngine extends ContextSource {
# WikiPage::getParserOutput() should not return false, but just in case
if ( $parserOutput ) {
// Allow extensions to change parser output here
if ( Hooks::run( 'DifferenceEngineRenderRevisionAddParserOutput',
[ $this, $out, $parserOutput, $wikiPage ] )
if ( $this->hookRunner->onDifferenceEngineRenderRevisionAddParserOutput(
$this, $out, $parserOutput, $wikiPage )
) {
$out->addParserOutput( $parserOutput, [
'enableSectionEditLinks' => $this->mNewRevisionRecord->isCurrent()
@ -1035,7 +1041,7 @@ class DifferenceEngine extends ContextSource {
}
// Allow extensions to optionally not show the final patrolled link
if ( Hooks::run( 'DifferenceEngineRenderRevisionShowFinalPatrolLink' ) ) {
if ( $this->hookRunner->onDifferenceEngineRenderRevisionShowFinalPatrolLink() ) {
# Add redundant patrol link on bottom...
$out->addHTML( $this->markPatrolledLink() );
}
@ -1073,7 +1079,7 @@ class DifferenceEngine extends ContextSource {
*/
public function showDiff( $otitle, $ntitle, $notice = '' ) {
// Allow extensions to affect the output here
Hooks::run( 'DifferenceEngineShowDiff', [ $this ] );
$this->hookRunner->onDifferenceEngineShowDiff( $this );
$diff = $this->getDiff( $otitle, $ntitle, $notice );
if ( $diff === false ) {
@ -1164,7 +1170,7 @@ class DifferenceEngine extends ContextSource {
$this->mOldRevisionRecord->getId() &&
$this->mOldRevisionRecord->getId() == $this->mNewRevisionRecord->getId()
) ) {
if ( Hooks::run( 'DifferenceEngineShowEmptyOldContent', [ $this ] ) ) {
if ( $this->hookRunner->onDifferenceEngineShowEmptyOldContent( $this ) ) {
return '';
}
}
@ -1217,11 +1223,8 @@ class DifferenceEngine extends ContextSource {
$difftext .= $slotDiff;
}
// Avoid PHP 7.1 warning from passing $this by reference
$diffEngine = $this;
// Save to cache for 7 days
if ( !Hooks::run( 'AbortDiffCache', [ &$diffEngine ] ) ) {
if ( !$this->hookRunner->onAbortDiffCache( $this ) ) {
$stats->updateCount( 'diff_cache.uncacheable', 1 );
} elseif ( $key !== false && $difftext !== false ) {
$stats->updateCount( 'diff_cache.miss', 1 );
@ -1915,6 +1918,7 @@ class DifferenceEngine extends ContextSource {
* @return array List of two revision ids, older first, later second.
* Zero signifies invalid argument passed.
* false signifies that there is no previous/next revision ($old is the oldest/newest one).
* @phan-return (int|false)[]
*/
public function mapDiffPrevNext( $old, $new ) {
$rl = MediaWikiServices::getInstance()->getRevisionLookup();
@ -1968,10 +1972,8 @@ class DifferenceEngine extends ContextSource {
$this->mNewid = 0;
}
Hooks::run(
'NewDifferenceEngine',
[ $this->getTitle(), &$this->mOldid, &$this->mNewid, $old, $new ]
);
$this->hookRunner->onNewDifferenceEngine(
$this->getTitle(), $this->mOldid, $this->mNewid, $old, $new );
}
/**
@ -2127,7 +2129,7 @@ class DifferenceEngine extends ContextSource {
RevisionRecord::FOR_THIS_USER,
$this->getUser()
);
Hooks::run( 'DifferenceEngineLoadTextAfterNewContentIsLoaded', [ $this ] );
$this->hookRunner->onDifferenceEngineLoadTextAfterNewContentIsLoaded( $this );
if ( $this->mNewContent === null ) {
return false;
}
@ -2157,7 +2159,7 @@ class DifferenceEngine extends ContextSource {
$this->getUser()
);
Hooks::run( 'DifferenceEngineAfterLoadNewText', [ $this ] );
$this->hookRunner->onDifferenceEngineAfterLoadNewText( $this );
return true;
}

View file

@ -664,7 +664,7 @@ TXT;
$logger->error( $json, [ 'private' => true ] );
}
Hooks::run( 'LogException', [ $e, false ] );
Hooks::runner()->onLogException( $e, false );
}
}
@ -709,6 +709,6 @@ TXT;
$logger->log( $unfilteredLevel, $json, [ 'private' => true ] );
}
Hooks::run( 'LogException', [ $e, $suppressed ] );
Hooks::runner()->onLogException( $e, $suppressed );
}
}

Some files were not shown because too many files have changed in this diff Show more