2019-05-09 01:36:18 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace MediaWiki\Rest;
|
|
|
|
|
|
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
2020-03-19 02:42:09 +00:00
|
|
|
use MediaWiki\HookContainer\HookContainer;
|
|
|
|
|
use MediaWiki\HookContainer\HookRunner;
|
2019-06-12 19:51:59 +00:00
|
|
|
use MediaWiki\Rest\Validator\BodyValidator;
|
|
|
|
|
use MediaWiki\Rest\Validator\NullBodyValidator;
|
|
|
|
|
use MediaWiki\Rest\Validator\Validator;
|
|
|
|
|
|
2019-05-09 01:36:18 +00:00
|
|
|
abstract class Handler {
|
2019-06-12 19:51:59 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* (string) ParamValidator constant to specify the source of the parameter.
|
|
|
|
|
* Value must be 'path', 'query', or 'post'.
|
|
|
|
|
*/
|
2020-05-15 21:36:51 +00:00
|
|
|
public const PARAM_SOURCE = 'rest-param-source';
|
2019-06-12 19:51:59 +00:00
|
|
|
|
2019-06-22 23:08:07 +00:00
|
|
|
/** @var Router */
|
|
|
|
|
private $router;
|
|
|
|
|
|
2019-05-09 01:36:18 +00:00
|
|
|
/** @var RequestInterface */
|
|
|
|
|
private $request;
|
|
|
|
|
|
|
|
|
|
/** @var array */
|
|
|
|
|
private $config;
|
|
|
|
|
|
|
|
|
|
/** @var ResponseFactory */
|
|
|
|
|
private $responseFactory;
|
|
|
|
|
|
2019-06-12 19:51:59 +00:00
|
|
|
/** @var array|null */
|
|
|
|
|
private $validatedParams;
|
|
|
|
|
|
|
|
|
|
/** @var mixed */
|
|
|
|
|
private $validatedBody;
|
|
|
|
|
|
2019-09-30 06:15:30 +00:00
|
|
|
/** @var ConditionalHeaderUtil */
|
|
|
|
|
private $conditionalHeaderUtil;
|
|
|
|
|
|
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
2020-03-19 02:42:09 +00:00
|
|
|
/** @var HookContainer */
|
|
|
|
|
private $hookContainer;
|
|
|
|
|
|
|
|
|
|
/** @var HookRunner */
|
|
|
|
|
private $hookRunner;
|
|
|
|
|
|
2019-05-09 01:36:18 +00:00
|
|
|
/**
|
|
|
|
|
* Initialise with dependencies from the Router. This is called after construction.
|
2019-06-22 23:08:07 +00:00
|
|
|
* @internal
|
2019-11-08 19:58:41 +00:00
|
|
|
* @param Router $router
|
|
|
|
|
* @param RequestInterface $request
|
|
|
|
|
* @param array $config
|
|
|
|
|
* @param ResponseFactory $responseFactory
|
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
2020-03-19 02:42:09 +00:00
|
|
|
* @param HookContainer $hookContainer
|
2019-05-09 01:36:18 +00:00
|
|
|
*/
|
2020-05-12 01:41:54 +00:00
|
|
|
final public function init( Router $router, RequestInterface $request, array $config,
|
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
2020-03-19 02:42:09 +00:00
|
|
|
ResponseFactory $responseFactory, HookContainer $hookContainer
|
2019-05-09 01:36:18 +00:00
|
|
|
) {
|
2019-06-22 23:08:07 +00:00
|
|
|
$this->router = $router;
|
2019-05-09 01:36:18 +00:00
|
|
|
$this->request = $request;
|
|
|
|
|
$this->config = $config;
|
|
|
|
|
$this->responseFactory = $responseFactory;
|
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
2020-03-19 02:42:09 +00:00
|
|
|
$this->hookContainer = $hookContainer;
|
|
|
|
|
$this->hookRunner = new HookRunner( $hookContainer );
|
2020-05-12 01:41:54 +00:00
|
|
|
$this->postInitSetup();
|
2019-05-09 01:36:18 +00:00
|
|
|
}
|
|
|
|
|
|
2019-06-22 23:08:07 +00:00
|
|
|
/**
|
|
|
|
|
* Get the Router. The return type declaration causes it to raise
|
|
|
|
|
* a fatal error if init() has not yet been called.
|
2019-11-08 19:58:41 +00:00
|
|
|
* @return Router
|
2019-06-22 23:08:07 +00:00
|
|
|
*/
|
|
|
|
|
protected function getRouter(): Router {
|
|
|
|
|
return $this->router;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-25 18:12:33 +00:00
|
|
|
/**
|
|
|
|
|
* Get the URL of this handler's endpoint.
|
|
|
|
|
* Supports the substitution of path parameters, and additions of query parameters.
|
|
|
|
|
*
|
|
|
|
|
* @see Router::getRouteUrl()
|
|
|
|
|
*
|
|
|
|
|
* @param string[] $pathParams Path parameters to be injected into the path
|
|
|
|
|
* @param string[] $queryParams Query parameters to be attached to the URL
|
|
|
|
|
*
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
protected function getRouteUrl( $pathParams = [], $queryParams = [] ): string {
|
|
|
|
|
$path = $this->getConfig()['path'];
|
|
|
|
|
|
|
|
|
|
foreach ( $pathParams as $param => $value ) {
|
|
|
|
|
$path = str_replace( '{' . $param . '}', urlencode( $value ), $path );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->router->getRouteUrl( $path, $queryParams );
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-09 01:36:18 +00:00
|
|
|
/**
|
|
|
|
|
* Get the current request. The return type declaration causes it to raise
|
|
|
|
|
* a fatal error if init() has not yet been called.
|
|
|
|
|
*
|
|
|
|
|
* @return RequestInterface
|
|
|
|
|
*/
|
|
|
|
|
public function getRequest(): RequestInterface {
|
|
|
|
|
return $this->request;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the configuration array for the current route. The return type
|
|
|
|
|
* declaration causes it to raise a fatal error if init() has not
|
|
|
|
|
* been called.
|
|
|
|
|
*
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
|
|
|
|
public function getConfig(): array {
|
|
|
|
|
return $this->config;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the ResponseFactory which can be used to generate Response objects.
|
|
|
|
|
* This will raise a fatal error if init() has not been
|
|
|
|
|
* called.
|
|
|
|
|
*
|
|
|
|
|
* @return ResponseFactory
|
|
|
|
|
*/
|
|
|
|
|
public function getResponseFactory(): ResponseFactory {
|
|
|
|
|
return $this->responseFactory;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-12 19:51:59 +00:00
|
|
|
/**
|
|
|
|
|
* Validate the request parameters/attributes and body. If there is a validation
|
|
|
|
|
* failure, a response with an error message should be returned or an
|
|
|
|
|
* HttpException should be thrown.
|
|
|
|
|
*
|
|
|
|
|
* @param Validator $restValidator
|
|
|
|
|
* @throws HttpException On validation failure.
|
|
|
|
|
*/
|
|
|
|
|
public function validate( Validator $restValidator ) {
|
|
|
|
|
$validatedParams = $restValidator->validateParams( $this->getParamSettings() );
|
|
|
|
|
$validatedBody = $restValidator->validateBody( $this->request, $this );
|
|
|
|
|
$this->validatedParams = $validatedParams;
|
|
|
|
|
$this->validatedBody = $validatedBody;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-21 23:35:05 +00:00
|
|
|
/**
|
|
|
|
|
* Get a ConditionalHeaderUtil object.
|
|
|
|
|
*
|
|
|
|
|
* On the first call to this method, the object will be initialized with
|
|
|
|
|
* validator values by calling getETag(), getLastModified() and
|
|
|
|
|
* hasRepresentation().
|
|
|
|
|
*
|
|
|
|
|
* @return ConditionalHeaderUtil
|
|
|
|
|
*/
|
|
|
|
|
protected function getConditionalHeaderUtil() {
|
|
|
|
|
if ( $this->conditionalHeaderUtil === null ) {
|
|
|
|
|
$this->conditionalHeaderUtil = new ConditionalHeaderUtil;
|
|
|
|
|
$this->conditionalHeaderUtil->setValidators(
|
|
|
|
|
$this->getETag(),
|
|
|
|
|
$this->getLastModified(),
|
|
|
|
|
$this->hasRepresentation() );
|
|
|
|
|
}
|
|
|
|
|
return $this->conditionalHeaderUtil;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-30 06:15:30 +00:00
|
|
|
/**
|
|
|
|
|
* Check the conditional request headers and generate a response if appropriate.
|
|
|
|
|
* This is called by the Router before execute() and may be overridden.
|
|
|
|
|
*
|
|
|
|
|
* @return ResponseInterface|null
|
|
|
|
|
*/
|
|
|
|
|
public function checkPreconditions() {
|
2019-11-21 23:35:05 +00:00
|
|
|
$status = $this->getConditionalHeaderUtil()->checkPreconditions( $this->getRequest() );
|
2019-09-30 06:15:30 +00:00
|
|
|
if ( $status ) {
|
|
|
|
|
$response = $this->getResponseFactory()->create();
|
|
|
|
|
$response->setStatus( $status );
|
|
|
|
|
return $response;
|
|
|
|
|
} else {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Modify the response, adding Last-Modified and ETag headers as indicated
|
|
|
|
|
* the values previously returned by ETag and getLastModified(). This is
|
|
|
|
|
* called after execute() returns, and may be overridden.
|
|
|
|
|
*
|
|
|
|
|
* @param ResponseInterface $response
|
|
|
|
|
*/
|
|
|
|
|
public function applyConditionalResponseHeaders( ResponseInterface $response ) {
|
2019-11-21 23:35:05 +00:00
|
|
|
$this->getConditionalHeaderUtil()->applyResponseHeaders( $response );
|
2019-09-30 06:15:30 +00:00
|
|
|
}
|
|
|
|
|
|
2019-06-12 19:51:59 +00:00
|
|
|
/**
|
|
|
|
|
* Fetch ParamValidator settings for parameters
|
|
|
|
|
*
|
|
|
|
|
* Every setting must include self::PARAM_SOURCE to specify which part of
|
|
|
|
|
* the request is to contain the parameter.
|
|
|
|
|
*
|
|
|
|
|
* @return array[] Associative array mapping parameter names to
|
|
|
|
|
* ParamValidator settings arrays
|
|
|
|
|
*/
|
|
|
|
|
public function getParamSettings() {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Fetch the BodyValidator
|
|
|
|
|
* @param string $contentType Content type of the request.
|
|
|
|
|
* @return BodyValidator
|
|
|
|
|
*/
|
|
|
|
|
public function getBodyValidator( $contentType ) {
|
|
|
|
|
return new NullBodyValidator();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2019-11-15 01:26:32 +00:00
|
|
|
* Fetch the validated parameters. This must be called after validate() is
|
|
|
|
|
* called. During execute() is fine.
|
2019-06-12 19:51:59 +00:00
|
|
|
*
|
2019-11-15 01:26:32 +00:00
|
|
|
* @return array Array mapping parameter names to validated values
|
|
|
|
|
* @throws \RuntimeException If validate() has not been called
|
2019-06-12 19:51:59 +00:00
|
|
|
*/
|
|
|
|
|
public function getValidatedParams() {
|
2019-11-15 01:26:32 +00:00
|
|
|
if ( $this->validatedParams === null ) {
|
|
|
|
|
throw new \RuntimeException( 'getValidatedParams() called before validate()' );
|
|
|
|
|
}
|
2019-06-12 19:51:59 +00:00
|
|
|
return $this->validatedParams;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Fetch the validated body
|
2019-10-12 12:30:37 +00:00
|
|
|
* @return mixed Value returned by the body validator, or null if validate() was
|
2019-06-12 19:51:59 +00:00
|
|
|
* not called yet, validation failed, there was no body, or the body was form data.
|
|
|
|
|
*/
|
|
|
|
|
public function getValidatedBody() {
|
|
|
|
|
return $this->validatedBody;
|
|
|
|
|
}
|
|
|
|
|
|
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
2020-03-19 02:42:09 +00:00
|
|
|
/**
|
|
|
|
|
* 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;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-09 01:36:18 +00:00
|
|
|
/**
|
|
|
|
|
* The subclass should override this to provide the maximum last modified
|
|
|
|
|
* timestamp for the current request. This is called before execute() in
|
|
|
|
|
* order to decide whether to send a 304.
|
|
|
|
|
*
|
|
|
|
|
* The timestamp can be in any format accepted by ConvertibleTimestamp, or
|
|
|
|
|
* null to indicate that the timestamp is unknown.
|
|
|
|
|
*
|
|
|
|
|
* @return bool|string|int|float|\DateTime|null
|
|
|
|
|
*/
|
|
|
|
|
protected function getLastModified() {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The subclass should override this to provide an ETag for the current
|
|
|
|
|
* request. This is called before execute() in order to decide whether to
|
|
|
|
|
* send a 304.
|
|
|
|
|
*
|
2019-09-30 06:15:30 +00:00
|
|
|
* This must be a complete ETag, including double quotes.
|
|
|
|
|
*
|
2019-05-09 01:36:18 +00:00
|
|
|
* See RFC 7232 § 2.3 for semantics.
|
|
|
|
|
*
|
|
|
|
|
* @return string|null
|
|
|
|
|
*/
|
|
|
|
|
protected function getETag() {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-30 06:15:30 +00:00
|
|
|
/**
|
|
|
|
|
* The subclass should override this to indicate whether the resource
|
|
|
|
|
* exists. This is used for wildcard validators, for example "If-Match: *"
|
|
|
|
|
* fails if the resource does not exist.
|
|
|
|
|
*
|
|
|
|
|
* @return bool|null
|
|
|
|
|
*/
|
|
|
|
|
protected function hasRepresentation() {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-26 02:33:35 +00:00
|
|
|
/**
|
|
|
|
|
* Indicates whether this route requires read rights.
|
|
|
|
|
*
|
|
|
|
|
* The handler should override this if it does not need to read from the
|
|
|
|
|
* wiki. This is uncommon, but may be useful for login and other account
|
|
|
|
|
* management APIs.
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
public function needsReadAccess() {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Indicates whether this route requires write access.
|
|
|
|
|
*
|
|
|
|
|
* The handler should override this if the route does not need to write to
|
|
|
|
|
* the database.
|
|
|
|
|
*
|
|
|
|
|
* This should return true for routes that may require synchronous database writes.
|
|
|
|
|
* Modules that do not need such writes should also not rely on master database access,
|
|
|
|
|
* since only read queries are needed and each master DB is a single point of failure.
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
public function needsWriteAccess() {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-12 01:41:54 +00:00
|
|
|
/**
|
|
|
|
|
* The handler can override this to do any necessary setup after init()
|
|
|
|
|
* is called to inject the dependencies.
|
|
|
|
|
*/
|
|
|
|
|
protected function postInitSetup() {
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-09 01:36:18 +00:00
|
|
|
/**
|
|
|
|
|
* Execute the handler. This is called after parameter validation. The
|
|
|
|
|
* return value can either be a Response or any type accepted by
|
|
|
|
|
* ResponseFactory::createFromReturnValue().
|
|
|
|
|
*
|
|
|
|
|
* To automatically construct an error response, execute() should throw a
|
|
|
|
|
* RestException. Such exceptions will not be logged like a normal exception.
|
|
|
|
|
*
|
|
|
|
|
* If execute() throws any other kind of exception, the exception will be
|
|
|
|
|
* logged and a generic 500 error page will be shown.
|
|
|
|
|
*
|
|
|
|
|
* @return mixed
|
|
|
|
|
*/
|
|
|
|
|
abstract public function execute();
|
|
|
|
|
}
|