MediaWiki REL1_35
ResponseFactory.php
Go to the documentation of this file.
1<?php
2
3namespace MediaWiki\Rest;
4
5use HttpStatus;
6use InvalidArgumentException;
9use stdClass;
10use Throwable;
13
18 private const CT_PLAIN = 'text/plain; charset=utf-8';
19 private const CT_HTML = 'text/html; charset=utf-8';
20 private const CT_JSON = 'application/json';
21
24
28 public function __construct( $textFormatters ) {
29 $this->textFormatters = $textFormatters;
30 }
31
39 public function encodeJson( $value ) {
40 $json = json_encode( $value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );
41 if ( $json === false ) {
42 throw new JsonEncodingException( json_last_error_msg(), json_last_error() );
43 }
44 return $json;
45 }
46
52 public function create() {
53 return new Response();
54 }
55
63 public function createJson( $value, $contentType = null ) {
64 $contentType = $contentType ?? self::CT_JSON;
65 $response = new Response( $this->encodeJson( $value ) );
66 $response->setHeader( 'Content-Type', $contentType );
67 return $response;
68 }
69
80 public function createNoContent() {
81 $response = new Response();
82 $response->setStatus( 204 );
83 return $response;
84 }
85
95 public function createPermanentRedirect( $target ) {
96 $response = $this->createRedirectBase( $target );
97 $response->setStatus( 301 );
98 return $response;
99 }
100
111 public function createLegacyTemporaryRedirect( $target ) {
112 $response = $this->createRedirectBase( $target );
113 $response->setStatus( 302 );
114 return $response;
115 }
116
125 public function createTemporaryRedirect( $target ) {
126 $response = $this->createRedirectBase( $target );
127 $response->setStatus( 307 );
128 return $response;
129 }
130
139 public function createSeeOther( $target ) {
140 $response = $this->createRedirectBase( $target );
141 $response->setStatus( 303 );
142 return $response;
143 }
144
155 public function createNotModified() {
156 $response = new Response();
157 $response->setStatus( 304 );
158 return $response;
159 }
160
168 public function createHttpError( $errorCode, array $bodyData = [] ) {
169 if ( $errorCode < 400 || $errorCode >= 600 ) {
170 throw new InvalidArgumentException( 'error code must be 4xx or 5xx' );
171 }
172 $response = $this->createJson( $bodyData + [
173 'httpCode' => $errorCode,
174 'httpReason' => HttpStatus::getMessage( $errorCode )
175 ] );
176 // TODO add link to error code documentation
177 $response->setStatus( $errorCode );
178 return $response;
179 }
180
191 $errorCode,
192 MessageValue $messageValue,
193 array $extraData = []
194 ) {
195 return $this->createHttpError(
196 $errorCode,
197 array_merge( $extraData, $this->formatMessage( $messageValue ) )
198 );
199 }
200
206 public function createFromException( Throwable $exception ) {
207 if ( $exception instanceof LocalizedHttpException ) {
208 $response = $this->createLocalizedHttpError(
209 $exception->getCode(),
210 $exception->getMessageValue(),
211 (array)$exception->getErrorData()
212 );
213 } elseif ( $exception instanceof HttpException ) {
214 // FIXME can HttpException represent 2xx or 3xx responses?
215 $response = $this->createHttpError(
216 $exception->getCode(),
217 array_merge(
218 [ 'message' => $exception->getMessage() ],
219 (array)$exception->getErrorData()
220 )
221 );
222 } else {
223 $response = $this->createHttpError( 500, [
224 'message' => 'Error: exception of type ' . get_class( $exception ),
225 'exception' => MWExceptionHandler::getStructuredExceptionData( $exception )
226 ] );
227 // FIXME should we try to do something useful with ILocalizedException?
228 // FIXME should we try to do something useful with common MediaWiki errors like ReadOnlyError?
229 }
230 return $response;
231 }
232
240 public function createFromReturnValue( $value ) {
241 $originalValue = $value;
242 if ( is_scalar( $value ) ) {
243 $data = [ 'value' => $value ];
244 } elseif ( is_array( $value ) || $value instanceof stdClass ) {
245 $data = $value;
246 } else {
247 $type = gettype( $originalValue );
248 if ( $type === 'object' ) {
249 $type = get_class( $originalValue );
250 }
251 throw new InvalidArgumentException( __METHOD__ . ": Invalid return value type $type" );
252 }
253 $response = $this->createJson( $data );
254 return $response;
255 }
256
262 protected function createRedirectBase( $target ) {
263 $response = new Response( $this->getHyperLink( $target ) );
264 $response->setHeader( 'Content-Type', self::CT_HTML );
265 $response->setHeader( 'Location', $target );
266 return $response;
267 }
268
275 protected function getHyperLink( $url ) {
276 $url = htmlspecialchars( $url );
277 return "<!doctype html><title>Redirect</title><a href=\"$url\">$url</a>";
278 }
279
280 public function formatMessage( MessageValue $messageValue ) {
281 if ( !$this->textFormatters ) {
282 // For unit tests
283 return [];
284 }
285 $translations = [];
286 foreach ( $this->textFormatters as $formatter ) {
287 $lang = LanguageCode::bcp47( $formatter->getLangCode() );
288 $messageText = $formatter->format( $messageValue );
289 $translations[$lang] = $messageText;
290 }
291 return [ 'messageTranslations' => $translations ];
292 }
293
294}
Methods for dealing with language codes.
Handler class for MWExceptions.
This is the base exception class for non-fatal exceptions thrown from REST handlers.
Generates standardized response objects.
encodeJson( $value)
Encode a stdClass object or array to a JSON string.
create()
Create an unspecified response.
createFromException(Throwable $exception)
Turn a throwable into a JSON error response.
formatMessage(MessageValue $messageValue)
createJson( $value, $contentType=null)
Create a successful JSON response.
createTemporaryRedirect( $target)
Creates a temporary (307) redirect.
createHttpError( $errorCode, array $bodyData=[])
Create a HTTP 4xx or 5xx response.
createPermanentRedirect( $target)
Creates a permanent (301) redirect.
createLegacyTemporaryRedirect( $target)
Creates a temporary (302) redirect.
createRedirectBase( $target)
Create a redirect response with type / response code unspecified.
createLocalizedHttpError( $errorCode, MessageValue $messageValue, array $extraData=[])
Create an HTTP 4xx or 5xx response with error message localisation.
createNoContent()
Create a 204 (No Content) response, used to indicate that an operation which does not return anything...
createFromReturnValue( $value)
Create a JSON response from an arbitrary value.
getHyperLink( $url)
Returns a minimal HTML document that links to the given URL, as suggested by RFC 7231 for 3xx respons...
createSeeOther( $target)
Creates a See Other (303) redirect.
createNotModified()
Create a 304 (Not Modified) response, used when the client has an up-to-date cached response.
Value object representing a message for i18n.
if(!isset( $args[0])) $lang