MediaWiki  master
ResponseFactory.php
Go to the documentation of this file.
1 <?php
2 
3 namespace MediaWiki\Rest;
4 
5 use Exception;
6 use HttpStatus;
7 use InvalidArgumentException;
8 use LanguageCode;
10 use stdClass;
11 use 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 
24  private $textFormatters;
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 
188  public function createLocalizedHttpError( $errorCode, MessageValue $messageValue ) {
189  return $this->createHttpError( $errorCode, $this->formatMessage( $messageValue ) );
190  }
191 
197  public function createFromException( $exception ) {
198  if ( $exception instanceof LocalizedHttpException ) {
199  $response = $this->createLocalizedHttpError( $exception->getCode(),
200  $exception->getMessageValue() );
201  } elseif ( $exception instanceof HttpException ) {
202  // FIXME can HttpException represent 2xx or 3xx responses?
203  $response = $this->createHttpError(
204  $exception->getCode(),
205  array_merge(
206  [ 'message' => $exception->getMessage() ],
207  (array)$exception->getErrorData()
208  )
209  );
210  } else {
211  $response = $this->createHttpError( 500, [
212  'message' => 'Error: exception of type ' . get_class( $exception ),
213  'exception' => MWExceptionHandler::getStructuredExceptionData( $exception )
214  ] );
215  // FIXME should we try to do something useful with ILocalizedException?
216  // FIXME should we try to do something useful with common MediaWiki errors like ReadOnlyError?
217  }
218  return $response;
219  }
220 
228  public function createFromReturnValue( $value ) {
229  $originalValue = $value;
230  if ( is_scalar( $value ) ) {
231  $data = [ 'value' => $value ];
232  } elseif ( is_array( $value ) || $value instanceof stdClass ) {
233  $data = $value;
234  } else {
235  $type = gettype( $originalValue );
236  if ( $type === 'object' ) {
237  $type = get_class( $originalValue );
238  }
239  throw new InvalidArgumentException( __METHOD__ . ": Invalid return value type $type" );
240  }
241  $response = $this->createJson( $data );
242  return $response;
243  }
244 
250  protected function createRedirectBase( $target ) {
251  $response = new Response( $this->getHyperLink( $target ) );
252  $response->setHeader( 'Content-Type', self::CT_HTML );
253  $response->setHeader( 'Location', $target );
254  return $response;
255  }
256 
263  protected function getHyperLink( $url ) {
264  $url = htmlspecialchars( $url );
265  return "<!doctype html><title>Redirect</title><a href=\"$url\">$url</a>";
266  }
267 
268  public function formatMessage( MessageValue $messageValue ) {
269  if ( !$this->textFormatters ) {
270  // For unit tests
271  return [];
272  }
273  $translations = [];
274  foreach ( $this->textFormatters as $formatter ) {
275  $lang = LanguageCode::bcp47( $formatter->getLangCode() );
276  $messageText = $formatter->format( $messageValue );
277  $translations[$lang] = $messageText;
278  }
279  return [ 'messageTranslations' => $translations ];
280  }
281 
282 }
MediaWiki\Rest\ResponseFactory
Generates standardized response objects.
Definition: ResponseFactory.php:18
Wikimedia\Message\ITextFormatter
Definition: ITextFormatter.php:18
$response
$response
Definition: opensearch_desc.php:38
$lang
if(!isset( $args[0])) $lang
Definition: testCompression.php:35
HttpStatus
Definition: HttpStatus.php:26
MWExceptionHandler\getStructuredExceptionData
static getStructuredExceptionData( $e, $catcher=self::CAUGHT_BY_OTHER)
Get a structured representation of an Exception.
Definition: MWExceptionHandler.php:521
MediaWiki\Rest\ResponseFactory\createRedirectBase
createRedirectBase( $target)
Create a redirect response with type / response code unspecified.
Definition: ResponseFactory.php:250
MWExceptionHandler
Handler class for MWExceptions.
Definition: MWExceptionHandler.php:30
MediaWiki\Rest\ResponseFactory\getHyperLink
getHyperLink( $url)
Returns a minimal HTML document that links to the given URL, as suggested by RFC 7231 for 3xx respons...
Definition: ResponseFactory.php:263
MediaWiki\Rest\ResponseFactory\createNotModified
createNotModified()
Create a 304 (Not Modified) response, used when the client has an up-to-date cached response.
Definition: ResponseFactory.php:156
MediaWiki\Rest\ResponseFactory\createLegacyTemporaryRedirect
createLegacyTemporaryRedirect( $target)
Creates a temporary (302) redirect.
Definition: ResponseFactory.php:112
MediaWiki\Rest\ResponseFactory\createJson
createJson( $value, $contentType=null)
Create a successful JSON response.
Definition: ResponseFactory.php:64
MediaWiki\Rest\ResponseFactory\formatMessage
formatMessage(MessageValue $messageValue)
Definition: ResponseFactory.php:268
MediaWiki\Rest\ResponseFactory\createFromReturnValue
createFromReturnValue( $value)
Create a JSON response from an arbitrary value.
Definition: ResponseFactory.php:228
Wikimedia\Message\MessageValue
Value object representing a message for i18n.
Definition: MessageValue.php:14
MediaWiki\Rest\ResponseFactory\createNoContent
createNoContent()
Create a 204 (No Content) response, used to indicate that an operation which does not return anything...
Definition: ResponseFactory.php:81
MediaWiki\Rest\ResponseFactory\createFromException
createFromException( $exception)
Turn an exception into a JSON error response.
Definition: ResponseFactory.php:197
MediaWiki\Rest\ResponseFactory\createTemporaryRedirect
createTemporaryRedirect( $target)
Creates a temporary (307) redirect.
Definition: ResponseFactory.php:126
MediaWiki\Rest\Response
Definition: Response.php:8
MediaWiki\Rest
MediaWiki\Rest\ResponseFactory\createHttpError
createHttpError( $errorCode, array $bodyData=[])
Create a HTTP 4xx or 5xx response.
Definition: ResponseFactory.php:169
MediaWiki\Rest\ResponseFactory\CT_HTML
const CT_HTML
Definition: ResponseFactory.php:20
MediaWiki\Rest\HttpException
This is the base exception class for non-fatal exceptions thrown from REST handlers.
Definition: HttpException.php:10
MediaWiki\Rest\ResponseFactory\createPermanentRedirect
createPermanentRedirect( $target)
Creates a permanent (301) redirect.
Definition: ResponseFactory.php:96
HttpStatus\getMessage
static getMessage( $code)
Get the message associated with an HTTP response status code.
Definition: HttpStatus.php:34
MediaWiki\Rest\ResponseFactory\CT_JSON
const CT_JSON
Definition: ResponseFactory.php:21
MediaWiki\Rest\ResponseFactory\__construct
__construct( $textFormatters)
Definition: ResponseFactory.php:29
MediaWiki\Rest\ResponseFactory\createSeeOther
createSeeOther( $target)
Creates a See Other (303) redirect.
Definition: ResponseFactory.php:140
MediaWiki\Rest\ResponseFactory\create
create()
Create an unspecified response.
Definition: ResponseFactory.php:53
LanguageCode\bcp47
static bcp47( $code)
Get the normalised IETF language tag See unit test for examples.
Definition: LanguageCode.php:176
LanguageCode
Methods for dealing with language codes.
Definition: LanguageCode.php:28
MediaWiki\Rest\JsonEncodingException
Definition: JsonEncodingException.php:5
MediaWiki\Rest\ResponseFactory\CT_PLAIN
const CT_PLAIN
Definition: ResponseFactory.php:19
MediaWiki\Rest\ResponseFactory\encodeJson
encodeJson( $value)
Encode a stdClass object or array to a JSON string.
Definition: ResponseFactory.php:40
MediaWiki\Rest\ResponseFactory\$textFormatters
ITextFormatter[] $textFormatters
Definition: ResponseFactory.php:24
MediaWiki\Rest\ResponseFactory\createLocalizedHttpError
createLocalizedHttpError( $errorCode, MessageValue $messageValue)
Create an HTTP 4xx or 5xx response with error message localisation.
Definition: ResponseFactory.php:188
MediaWiki\Rest\LocalizedHttpException
Definition: LocalizedHttpException.php:7
$type
$type
Definition: testCompression.php:50