MediaWiki REL1_34
ResponseFactory.php
Go to the documentation of this file.
1<?php
2
3namespace MediaWiki\Rest;
4
5use Exception;
6use HttpStatus;
7use InvalidArgumentException;
10use stdClass;
11use Throwable;
14
19 const CT_PLAIN = 'text/plain; charset=utf-8';
20 const CT_HTML = 'text/html; charset=utf-8';
21 const CT_JSON = 'application/json';
22
25
29 public function __construct( $textFormatters ) {
30 $this->textFormatters = $textFormatters;
31 }
32
40 public function encodeJson( $value ) {
41 $json = json_encode( $value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );
42 if ( $json === false ) {
43 throw new JsonEncodingException( json_last_error_msg(), json_last_error() );
44 }
45 return $json;
46 }
47
53 public function create() {
54 return new Response();
55 }
56
64 public function createJson( $value, $contentType = null ) {
65 $contentType = $contentType ?? self::CT_JSON;
66 $response = new Response( $this->encodeJson( $value ) );
67 $response->setHeader( 'Content-Type', $contentType );
68 return $response;
69 }
70
81 public function createNoContent() {
82 $response = new Response();
83 $response->setStatus( 204 );
84 return $response;
85 }
86
96 public function createPermanentRedirect( $target ) {
97 $response = $this->createRedirectBase( $target );
98 $response->setStatus( 301 );
99 return $response;
100 }
101
112 public function createLegacyTemporaryRedirect( $target ) {
113 $response = $this->createRedirectBase( $target );
114 $response->setStatus( 302 );
115 return $response;
116 }
117
126 public function createTemporaryRedirect( $target ) {
127 $response = $this->createRedirectBase( $target );
128 $response->setStatus( 307 );
129 return $response;
130 }
131
140 public function createSeeOther( $target ) {
141 $response = $this->createRedirectBase( $target );
142 $response->setStatus( 303 );
143 return $response;
144 }
145
156 public function createNotModified() {
157 $response = new Response();
158 $response->setStatus( 304 );
159 return $response;
160 }
161
169 public function createHttpError( $errorCode, array $bodyData = [] ) {
170 if ( $errorCode < 400 || $errorCode >= 600 ) {
171 throw new InvalidArgumentException( 'error code must be 4xx or 5xx' );
172 }
173 $response = $this->createJson( $bodyData + [
174 'httpCode' => $errorCode,
175 'httpReason' => HttpStatus::getMessage( $errorCode )
176 ] );
177 // TODO add link to error code documentation
178 $response->setStatus( $errorCode );
179 return $response;
180 }
181
185 public function createLocalizedHttpError( $errorCode, MessageValue $messageValue ) {
186 return $this->createHttpError( $errorCode, $this->formatMessage( $messageValue ) );
187 }
188
194 public function createFromException( $exception ) {
195 if ( $exception instanceof LocalizedHttpException ) {
196 $response = $this->createLocalizedHttpError( $exception->getCode(),
197 $exception->getMessageValue() );
198 } elseif ( $exception instanceof HttpException ) {
199 // FIXME can HttpException represent 2xx or 3xx responses?
200 $response = $this->createHttpError(
201 $exception->getCode(),
202 array_merge(
203 [ 'message' => $exception->getMessage() ],
204 (array)$exception->getErrorData()
205 )
206 );
207 } else {
208 $response = $this->createHttpError( 500, [
209 'message' => 'Error: exception of type ' . get_class( $exception ),
210 'exception' => MWExceptionHandler::getStructuredExceptionData( $exception )
211 ] );
212 // FIXME should we try to do something useful with ILocalizedException?
213 // FIXME should we try to do something useful with common MediaWiki errors like ReadOnlyError?
214 }
215 return $response;
216 }
217
225 public function createFromReturnValue( $value ) {
226 $originalValue = $value;
227 if ( is_scalar( $value ) ) {
228 $data = [ 'value' => $value ];
229 } elseif ( is_array( $value ) || $value instanceof stdClass ) {
230 $data = $value;
231 } else {
232 $type = gettype( $originalValue );
233 if ( $type === 'object' ) {
234 $type = get_class( $originalValue );
235 }
236 throw new InvalidArgumentException( __METHOD__ . ": Invalid return value type $type" );
237 }
238 $response = $this->createJson( $data );
239 return $response;
240 }
241
247 protected function createRedirectBase( $target ) {
248 $response = new Response( $this->getHyperLink( $target ) );
249 $response->setHeader( 'Content-Type', self::CT_HTML );
250 $response->setHeader( 'Location', $target );
251 return $response;
252 }
253
260 protected function getHyperLink( $url ) {
261 $url = htmlspecialchars( $url );
262 return "<!doctype html><title>Redirect</title><a href=\"$url\">$url</a>";
263 }
264
265 public function formatMessage( MessageValue $messageValue ) {
266 if ( !$this->textFormatters ) {
267 // For unit tests
268 return [];
269 }
270 $translations = [];
271 foreach ( $this->textFormatters as $formatter ) {
272 $lang = LanguageCode::bcp47( $formatter->getLangCode() );
273 $messageText = $formatter->format( $messageValue );
274 $translations[$lang] = $messageText;
275 }
276 return [ 'messageTranslations' => $translations ];
277 }
278
279}
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( $exception)
Turn an exception into a JSON error response.
formatMessage(MessageValue $messageValue)
createJson( $value, $contentType=null)
Create a successful JSON response.
createTemporaryRedirect( $target)
Creates a temporary (307) redirect.
createLocalizedHttpError( $errorCode, MessageValue $messageValue)
Create an HTTP 4xx or 5xx response with error message localisation.
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.
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