MediaWiki  master
ApiErrorFormatter.php
Go to the documentation of this file.
1 <?php
33  private static $dummyTitle = null;
34 
36  protected $result;
37 
39  protected $lang;
40  protected $useDB = false;
41  protected $format = 'none';
42 
55  public function __construct( ApiResult $result, Language $lang, $format, $useDB = false ) {
56  $this->result = $result;
57  $this->lang = $lang;
58  $this->useDB = $useDB;
59  $this->format = $format;
60  }
61 
74  public static function isValidApiCode( $code ) {
75  return is_string( $code ) && (
76  preg_match( '/^[a-zA-Z0-9_-]+$/', $code ) ||
77  // TODO: Deprecate this
78  preg_match( '/^internal_api_error_[^\0\r\n]+$/', $code )
79  );
80  }
81 
89  public function newWithFormat( $format ) {
90  return new self( $this->result, $this->lang, $format, $this->useDB );
91  }
92 
98  public function getFormat() {
99  return $this->format;
100  }
101 
107  public function getLanguage() {
108  return $this->lang;
109  }
110 
115  protected function getDummyTitle() {
116  if ( self::$dummyTitle === null ) {
117  self::$dummyTitle = Title::makeTitle( NS_SPECIAL, 'Badtitle/' . __METHOD__ );
118  }
119  return self::$dummyTitle;
120  }
121 
129  public function addWarning( $modulePath, $msg, $code = null, $data = null ) {
130  $msg = ApiMessage::create( $msg, $code, $data )
131  ->inLanguage( $this->lang )
132  ->title( $this->getDummyTitle() )
133  ->useDatabase( $this->useDB );
134  $this->addWarningOrError( 'warning', $modulePath, $msg );
135  }
136 
144  public function addError( $modulePath, $msg, $code = null, $data = null ) {
145  $msg = ApiMessage::create( $msg, $code, $data )
146  ->inLanguage( $this->lang )
147  ->title( $this->getDummyTitle() )
148  ->useDatabase( $this->useDB );
149  $this->addWarningOrError( 'error', $modulePath, $msg );
150  }
151 
159  public function addMessagesFromStatus(
160  $modulePath, StatusValue $status, $types = [ 'warning', 'error' ], array $filter = []
161  ) {
162  if ( $status->isGood() || !$status->getErrors() ) {
163  return;
164  }
165 
166  $types = (array)$types;
167  foreach ( $status->getErrors() as $error ) {
168  if ( !in_array( $error['type'], $types, true ) ) {
169  continue;
170  }
171 
172  if ( $error['type'] === 'error' ) {
173  $tag = 'error';
174  } else {
175  // Assume any unknown type is a warning
176  $tag = 'warning';
177  }
178 
179  $msg = ApiMessage::create( $error )
180  ->inLanguage( $this->lang )
181  ->title( $this->getDummyTitle() )
182  ->useDatabase( $this->useDB );
183  if ( !in_array( $msg->getKey(), $filter, true ) ) {
184  $this->addWarningOrError( $tag, $modulePath, $msg );
185  }
186  }
187  }
188 
201  public function getMessageFromException( Throwable $exception, array $options = [] ) {
202  $options += [ 'code' => null, 'data' => [] ];
203 
204  if ( $exception instanceof ILocalizedException ) {
205  $msg = $exception->getMessageObject();
206  $params = [];
207  } elseif ( $exception instanceof MessageSpecifier ) {
208  $msg = Message::newFromSpecifier( $exception );
209  $params = [];
210  } else {
211  if ( isset( $options['wrap'] ) ) {
212  $msg = $options['wrap'];
213  } else {
214  $msg = new RawMessage( '$1' );
215  if ( !isset( $options['code'] ) ) {
216  $class = preg_replace( '#^Wikimedia\\\Rdbms\\\#', '', get_class( $exception ) );
217  $options['code'] = 'internal_api_error_' . $class;
218  $options['data']['errorclass'] = get_class( $exception );
219  }
220  }
221  $params = [ wfEscapeWikiText( $exception->getMessage() ) ];
222  }
223  return ApiMessage::create( $msg, $options['code'], $options['data'] )
224  ->params( $params )
225  ->inLanguage( $this->lang )
226  ->title( $this->getDummyTitle() )
227  ->useDatabase( $this->useDB );
228  }
229 
238  public function formatException( Throwable $exception, array $options = [] ) {
239  return $this->formatMessage(
240  // @phan-suppress-next-line PhanTypeMismatchArgument
241  $this->getMessageFromException( $exception, $options ),
242  $options['format'] ?? null
243  );
244  }
245 
252  public function formatMessage( $msg, $format = null ) {
253  $msg = ApiMessage::create( $msg )
254  ->inLanguage( $this->lang )
255  ->title( $this->getDummyTitle() )
256  ->useDatabase( $this->useDB );
257  return $this->formatMessageInternal( $msg, $format ?: $this->format );
258  }
259 
267  public function arrayFromStatus( StatusValue $status, $type = 'error', $format = null ) {
268  if ( $status->isGood() || !$status->getErrors() ) {
269  return [];
270  }
271 
272  $result = new ApiResult( 1e6 );
273  $formatter = new ApiErrorFormatter(
274  $result, $this->lang, $format ?: $this->format, $this->useDB
275  );
276  $formatter->addMessagesFromStatus( null, $status, [ $type ] );
277  switch ( $type ) {
278  case 'error':
279  return (array)$result->getResultData( [ 'errors' ] );
280  case 'warning':
281  return (array)$result->getResultData( [ 'warnings' ] );
282  }
283  }
284 
291  public static function stripMarkup( $text ) {
292  // Turn semantic quoting tags to quotes
293  $ret = preg_replace( '!</?(var|kbd|samp|code)>!', '"', $text );
294 
295  // Strip tags and decode.
296  $ret = Sanitizer::stripAllTags( $ret );
297 
298  return $ret;
299  }
300 
306  private function formatRawMessage( MessageSpecifier $msg ) {
307  $ret = [
308  'key' => $msg->getKey(),
309  'params' => $msg->getParams(),
310  ];
311  ApiResult::setIndexedTagName( $ret['params'], 'param' );
312 
313  // Transform Messages as parameters in the style of Message::fooParam().
314  foreach ( $ret['params'] as $i => $param ) {
315  if ( $param instanceof MessageSpecifier ) {
316  $ret['params'][$i] = [ 'message' => $this->formatRawMessage( $param ) ];
317  }
318  }
319  return $ret;
320  }
321 
329  protected function formatMessageInternal( $msg, $format ) {
330  $value = [ 'code' => $msg->getApiCode() ];
331  switch ( $format ) {
332  case 'plaintext':
333  $value += [
334  'text' => self::stripMarkup( $msg->text() ),
335  ApiResult::META_CONTENT => 'text',
336  ];
337  break;
338 
339  case 'wikitext':
340  $value += [
341  'text' => $msg->text(),
342  ApiResult::META_CONTENT => 'text',
343  ];
344  break;
345 
346  case 'html':
347  $value += [
348  'html' => $msg->parse(),
349  ApiResult::META_CONTENT => 'html',
350  ];
351  break;
352 
353  case 'raw':
354  $value += $this->formatRawMessage( $msg );
355  break;
356 
357  case 'none':
358  break;
359  }
360  $data = $msg->getApiData();
361  if ( $data ) {
362  $value['data'] = $msg->getApiData() + [
363  ApiResult::META_TYPE => 'assoc',
364  ];
365  }
366  return $value;
367  }
368 
375  protected function addWarningOrError( $tag, $modulePath, $msg ) {
376  $value = $this->formatMessageInternal( $msg, $this->format );
377  if ( $modulePath !== null ) {
378  $value += [ 'module' => $modulePath ];
379  }
380 
381  $path = [ $tag . 's' ];
382  $existing = $this->result->getResultData( $path );
383  if ( $existing === null || !in_array( $value, $existing ) ) {
384  $flags = ApiResult::NO_SIZE_CHECK;
385  if ( $existing === null ) {
386  $flags |= ApiResult::ADD_ON_TOP;
387  }
388  $this->result->addValue( $path, null, $value, $flags );
389  $this->result->addIndexedTagName( $path, $tag );
390  }
391  }
392 }
Message\newFromSpecifier
static newFromSpecifier( $value)
Transform a MessageSpecifier or a primitive value used interchangeably with specifiers (a message key...
Definition: Message.php:434
ApiErrorFormatter\getLanguage
getLanguage()
Fetch the Language for this formatter.
Definition: ApiErrorFormatter.php:107
StatusValue
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition: StatusValue.php:42
ApiErrorFormatter\getFormat
getFormat()
Fetch the format for this formatter.
Definition: ApiErrorFormatter.php:98
ApiErrorFormatter\addError
addError( $modulePath, $msg, $code=null, $data=null)
Add an error to the result.
Definition: ApiErrorFormatter.php:144
ApiErrorFormatter\isValidApiCode
static isValidApiCode( $code)
Test whether a code is a valid API error code.
Definition: ApiErrorFormatter.php:74
Sanitizer\stripAllTags
static stripAllTags( $html)
Take a fragment of (potentially invalid) HTML and return a version with any tags removed,...
Definition: Sanitizer.php:1860
ApiResult\META_TYPE
const META_TYPE
Key for the 'type' metadata item.
Definition: ApiResult.php:110
MessageSpecifier\getKey
getKey()
Returns the message key.
MessageSpecifier
Definition: MessageSpecifier.php:21
ApiResult\NO_SIZE_CHECK
const NO_SIZE_CHECK
For addValue() and similar functions, do not check size while adding a value Don't use this unless yo...
Definition: ApiResult.php:58
ApiErrorFormatter\addWarning
addWarning( $modulePath, $msg, $code=null, $data=null)
Add a warning to the result.
Definition: ApiErrorFormatter.php:129
MessageSpecifier\getParams
getParams()
Returns the message parameters.
NS_SPECIAL
const NS_SPECIAL
Definition: Defines.php:58
ApiErrorFormatter\formatMessageInternal
formatMessageInternal( $msg, $format)
Format a message as an array.
Definition: ApiErrorFormatter.php:329
StatusValue\isGood
isGood()
Returns whether the operation completed and didn't have any error or warnings.
Definition: StatusValue.php:121
ApiErrorFormatter\$lang
Language $lang
Definition: ApiErrorFormatter.php:39
ApiErrorFormatter\$result
ApiResult $result
Definition: ApiErrorFormatter.php:36
ApiErrorFormatter\stripMarkup
static stripMarkup( $text)
Turn wikitext into something resembling plaintext.
Definition: ApiErrorFormatter.php:291
ApiResult
This class represents the result of the API operations.
Definition: ApiResult.php:35
ApiErrorFormatter\addWarningOrError
addWarningOrError( $tag, $modulePath, $msg)
Actually add the warning or error to the result.
Definition: ApiErrorFormatter.php:375
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:592
ApiMessage\create
static create( $msg, $code=null, array $data=null)
Create an IApiMessage for the message.
Definition: ApiMessage.php:40
ApiErrorFormatter\formatRawMessage
formatRawMessage(MessageSpecifier $msg)
Format a Message object for raw format.
Definition: ApiErrorFormatter.php:306
ILocalizedException
Interface for MediaWiki-localized exceptions.
Definition: ILocalizedException.php:27
ApiErrorFormatter\__construct
__construct(ApiResult $result, Language $lang, $format, $useDB=false)
Definition: ApiErrorFormatter.php:55
ApiErrorFormatter\$dummyTitle
static Title $dummyTitle
Dummy title to silence warnings from MessageCache::parse()
Definition: ApiErrorFormatter.php:33
ApiErrorFormatter\$format
$format
Definition: ApiErrorFormatter.php:41
ApiErrorFormatter\newWithFormat
newWithFormat( $format)
Return a formatter like this one but with a different format.
Definition: ApiErrorFormatter.php:89
ApiResult\setIndexedTagName
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
Definition: ApiResult.php:604
ApiErrorFormatter\formatMessage
formatMessage( $msg, $format=null)
Format a message as an array.
Definition: ApiErrorFormatter.php:252
StatusValue\getErrors
getErrors()
Get the list of errors.
Definition: StatusValue.php:148
ApiErrorFormatter\formatException
formatException(Throwable $exception, array $options=[])
Format a throwable as an array.
Definition: ApiErrorFormatter.php:238
wfEscapeWikiText
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
Definition: GlobalFunctions.php:1490
ApiErrorFormatter
Formats errors and warnings for the API, and add them to the associated ApiResult.
Definition: ApiErrorFormatter.php:31
Title
Represents a title within MediaWiki.
Definition: Title.php:42
ApiResult\ADD_ON_TOP
const ADD_ON_TOP
For addValue(), setValue() and similar functions, if the value does not exist, add it as the first el...
Definition: ApiResult.php:49
ApiErrorFormatter\getMessageFromException
getMessageFromException(Throwable $exception, array $options=[])
Get an ApiMessage from a throwable.
Definition: ApiErrorFormatter.php:201
ApiResult\getResultData
getResultData( $path=[], $transforms=[])
Get the result data array.
Definition: ApiResult.php:242
ApiErrorFormatter\addMessagesFromStatus
addMessagesFromStatus( $modulePath, StatusValue $status, $types=[ 'warning', 'error'], array $filter=[])
Add warnings and errors from a StatusValue object to the result.
Definition: ApiErrorFormatter.php:159
$path
$path
Definition: NoLocalSettings.php:25
ApiErrorFormatter\arrayFromStatus
arrayFromStatus(StatusValue $status, $type='error', $format=null)
Format messages from a StatusValue as an array.
Definition: ApiErrorFormatter.php:267
RawMessage
Variant of the Message class.
Definition: RawMessage.php:34
ApiResult\META_CONTENT
const META_CONTENT
Key for the 'content' metadata item.
Definition: ApiResult.php:90
ApiErrorFormatter\getDummyTitle
getDummyTitle()
Fetch a dummy title to set on Messages.
Definition: ApiErrorFormatter.php:115
Language
Internationalisation code See https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation for more...
Definition: Language.php:41
ApiErrorFormatter\$useDB
$useDB
Definition: ApiErrorFormatter.php:40
$type
$type
Definition: testCompression.php:52