MediaWiki master
ActionModuleBasedHandler.php
Go to the documentation of this file.
1<?php
2
4
5use ApiBase;
6use ApiMain;
7use ApiMessage;
14use MediaWiki\Rest\Handler\Helper\RestStatusTrait;
19
25abstract class ActionModuleBasedHandler extends Handler {
26 use RestStatusTrait;
27
31 private $apiMain = null;
32
33 protected function getUser() {
34 return $this->getApiMain()->getUser();
35 }
36
42 public function setApiMain( ApiMain $apiMain ) {
43 $this->apiMain = $apiMain;
44 }
45
49 public function getApiMain() {
50 if ( $this->apiMain ) {
51 return $this->apiMain;
52 }
53
54 $context = RequestContext::getMain();
55 $session = $context->getRequest()->getSession();
56
57 // NOTE: This being a MediaWiki\Request\FauxRequest instance triggers special case behavior
58 // in ApiMain, causing ApiMain::isInternalMode() to return true. Among other things,
59 // this causes ApiMain to throw errors rather than encode them in the result data.
60 $fauxRequest = new FauxRequest( [], true, $session );
61 $fauxRequest->setSessionId( $session->getSessionId() );
62
63 $fauxContext = new RequestContext();
64 $fauxContext->setRequest( $fauxRequest );
65 $fauxContext->setUser( $context->getUser() );
66 $fauxContext->setLanguage( $context->getLanguage() );
67
68 $this->apiMain = new ApiMain( $fauxContext, true );
69 return $this->apiMain;
70 }
71
79 public function overrideActionModule( string $name, string $group, ApiBase $module ) {
80 $this->getApiMain()->getModuleManager()->addModule(
81 $name,
82 $group,
83 [
84 'class' => get_class( $module ),
85 'factory' => static function () use ( $module ) {
86 return $module;
87 }
88 ]
89 );
90 }
91
101 public function execute() {
102 $apiMain = $this->getApiMain();
103
105 $request = $apiMain->getRequest();
106
107 foreach ( $params as $key => $value ) {
108 $request->setVal( $key, $value );
109 }
110
111 try {
112 // NOTE: ApiMain detects this to be an internal call, so it will throw
113 // ApiUsageException rather than putting error messages into the result.
114 $apiMain->execute();
115 } catch ( ApiUsageException $ex ) {
116 // use a fake loop to throw the first error
117 foreach ( $ex->getStatusValue()->getErrorsByType( 'error' ) as $error ) {
118 $msg = ApiMessage::create( $error );
119 $this->throwHttpExceptionForActionModuleError( $msg, $ex->getCode() ?: 400 );
120 }
121
122 // This should never happen, since ApiUsageExceptions should always
123 // have errors in their Status object.
124 throw new HttpException(
125 'Unmapped action module error: ' . $ex->getMessage(),
126 $ex->getCode()
127 );
128 }
129
130 $actionModuleResult = $apiMain->getResult()->getResultData( null, [ 'Strip' => 'all' ] );
131
132 // construct result
133 $resultData = $this->mapActionModuleResult( $actionModuleResult );
134
135 $response = $this->getResponseFactory()->createFromReturnValue( $resultData );
136
138 $apiMain->getRequest()->response(),
139 $actionModuleResult,
140 $response
141 );
142
143 return $response;
144 }
145
155 abstract protected function getActionModuleParameters();
156
165 abstract protected function mapActionModuleResult( array $data );
166
183 protected function mapActionModuleResponse(
184 WebResponse $actionModuleResponse,
185 array $actionModuleResult,
186 Response $response
187 ) {
188 // TODO: map status, headers, cookies, etc
189 }
190
209 protected function throwHttpExceptionForActionModuleError( IApiMessage $msg, $statusCode = 400 ) {
210 // override to supply mappings
211
212 throw new LocalizedHttpException(
213 $this->makeMessageValue( $msg ),
214 $statusCode,
215 // Include the original error code in the response.
216 // This makes it easier to track down the original cause of the error,
217 // and allows more specific mappings to be added to
218 // implementations of throwHttpExceptionForActionModuleError() provided by
219 // subclasses
220 [ 'actionModuleErrorCode' => $msg->getApiCode() ]
221 );
222 }
223
231 protected function makeMessageValue( IApiMessage $msg ) {
232 return $this->getMessageValueConverter()->convertMessage( $msg );
233 }
234
235}
array $params
The job parameters.
This abstract class implements many basic API functions, and is the base of all API classes.
Definition ApiBase.php:64
This is the main API class, used for both external and internal processing.
Definition ApiMain.php:65
getResult()
Get the ApiResult object associated with current request.
Definition ApiMain.php:696
execute()
Execute api request.
Definition ApiMain.php:891
Extension of Message implementing IApiMessage.
Exception used to abort API execution with an error.
getStatusValue()
Fetch the error status.
Group all the pieces relevant to the context of a request into one instance.
WebRequest clone which takes values from a provided array.
Allow programs to request this object from WebRequest::response() and handle all outputting (or lack ...
Base class for REST handlers that are implemented by mapping to an existing ApiModule.
setApiMain(ApiMain $apiMain)
Set main action API entry point for testing.
overrideActionModule(string $name, string $group, ApiBase $module)
Overrides an action API module.
throwHttpExceptionForActionModuleError(IApiMessage $msg, $statusCode=400)
Throws a HttpException for a given IApiMessage that represents an error.
mapActionModuleResponse(WebResponse $actionModuleResponse, array $actionModuleResult, Response $response)
Transfers relevant information, such as header values, from the WebResponse constructed by the action...
execute()
Main execution method, implemented to delegate execution to ApiMain.
makeMessageValue(IApiMessage $msg)
Constructs a MessageValue from an IApiMessage.
mapActionModuleResult(array $data)
Maps an action API result to a REST API result.
getActionModuleParameters()
Maps a REST API request to an action API request.
Base class for REST route handlers.
Definition Handler.php:21
getResponseFactory()
Get the ResponseFactory which can be used to generate Response objects.
Definition Handler.php:195
This is the base exception class for non-fatal exceptions thrown from REST handlers.
Value object representing a message for i18n.
Interface for messages with machine-readable data for use by the API.
getApiCode()
Returns a machine-readable code for use by the API.
Copyright (C) 2011-2020 Wikimedia Foundation and others.