MediaWiki  master
StatusValue.php
Go to the documentation of this file.
1 <?php
23 
46 class StatusValue {
47 
49  protected $ok = true;
50 
52  protected $errors = [];
53 
55  public $value;
56 
58  public $success = [];
59 
61  public $successCount = 0;
62 
64  public $failCount = 0;
65 
73  public static function newFatal( $message, ...$parameters ) {
74  $result = new static();
75  $result->fatal( $message, ...$parameters );
76  return $result;
77  }
78 
85  public static function newGood( $value = null ) {
86  $result = new static();
87  $result->value = $value;
88  return $result;
89  }
90 
102  public function splitByErrorType() {
103  $errorsOnlyStatusValue = static::newGood();
104  $warningsOnlyStatusValue = static::newGood();
105  $warningsOnlyStatusValue->setResult( true, $this->getValue() );
106  $errorsOnlyStatusValue->setResult( $this->isOK(), $this->getValue() );
107 
108  foreach ( $this->errors as $item ) {
109  if ( $item['type'] === 'warning' ) {
110  $warningsOnlyStatusValue->errors[] = $item;
111  } else {
112  $errorsOnlyStatusValue->errors[] = $item;
113  }
114  }
115 
116  return [ $errorsOnlyStatusValue, $warningsOnlyStatusValue ];
117  }
118 
125  public function isGood() {
126  return $this->ok && !$this->errors;
127  }
128 
134  public function isOK() {
135  return $this->ok;
136  }
137 
141  public function getValue() {
142  return $this->value;
143  }
144 
152  public function getErrors() {
153  return $this->errors;
154  }
155 
162  public function setOK( $ok ) {
163  $this->ok = $ok;
164  return $this;
165  }
166 
174  public function setResult( $ok, $value = null ) {
175  $this->ok = (bool)$ok;
176  $this->value = $value;
177  return $this;
178  }
179 
196  private function addError( array $newError ) {
197  if ( $newError[ 'message' ] instanceof MessageSpecifier ) {
198  $isEqual = static function ( $existingError ) use ( $newError ) {
199  if ( $existingError['message'] instanceof MessageSpecifier ) {
200  // compare attributes of both MessageSpecifiers
201  return $newError['message'] == $existingError['message'];
202  } else {
203  return $newError['message']->getKey() === $existingError['message'] &&
204  $newError['message']->getParams() === $existingError['params'];
205  }
206  };
207  } else {
208  $isEqual = static function ( $existingError ) use ( $newError ) {
209  if ( $existingError['message'] instanceof MessageSpecifier ) {
210  return $newError['message'] === $existingError['message']->getKey() &&
211  $newError['params'] === $existingError['message']->getParams();
212  } else {
213  return $newError['message'] === $existingError['message'] &&
214  $newError['params'] === $existingError['params'];
215  }
216  };
217  }
218  foreach ( $this->errors as $index => $existingError ) {
219  if ( $isEqual( $existingError ) ) {
220  if ( $newError[ 'type' ] === 'error' && $existingError[ 'type' ] === 'warning' ) {
221  $this->errors[ $index ][ 'type' ] = 'error';
222  }
223  return $this;
224  }
225  }
226  $this->errors[] = $newError;
227  return $this;
228  }
229 
237  public function warning( $message, ...$parameters ) {
238  $message = $this->normalizeMessage( $message, $parameters );
239 
240  return $this->addError( [
241  'type' => 'warning',
242  'message' => $message,
243  'params' => $parameters
244  ] );
245  }
246 
255  public function error( $message, ...$parameters ) {
256  $message = $this->normalizeMessage( $message, $parameters );
257 
258  return $this->addError( [
259  'type' => 'error',
260  'message' => $message,
261  'params' => $parameters
262  ] );
263  }
264 
273  public function fatal( $message, ...$parameters ) {
274  $this->ok = false;
275  return $this->error( $message, ...$parameters );
276  }
277 
285  public function merge( $other, $overwriteValue = false ) {
286  foreach ( $other->errors as $error ) {
287  $this->addError( $error );
288  }
289  $this->ok = $this->ok && $other->ok;
290  if ( $overwriteValue ) {
291  $this->value = $other->value;
292  }
293  $this->successCount += $other->successCount;
294  $this->failCount += $other->failCount;
295  return $this;
296  }
297 
308  public function getErrorsByType( $type ) {
309  $result = [];
310  foreach ( $this->errors as $error ) {
311  if ( $error['type'] === $type ) {
312  $result[] = $error;
313  }
314  }
315 
316  return $result;
317  }
318 
326  public function hasMessage( $message ) {
327  if ( $message instanceof MessageSpecifier ) {
328  $message = $message->getKey();
329  } elseif ( $message instanceof MessageValue ) {
330  $message = $message->getKey();
331  }
332 
333  foreach ( $this->errors as $error ) {
334  if ( $error['message'] instanceof MessageSpecifier
335  && $error['message']->getKey() === $message
336  ) {
337  return true;
338  } elseif ( $error['message'] === $message ) {
339  return true;
340  }
341  }
342 
343  return false;
344  }
345 
357  public function replaceMessage( $source, $dest ) {
358  $replaced = false;
359 
360  $source = $this->normalizeMessage( $source );
361  $dest = $this->normalizeMessage( $dest );
362 
363  foreach ( $this->errors as $index => $error ) {
364  if ( $error['message'] === $source ) {
365  $this->errors[$index]['message'] = $dest;
366  $replaced = true;
367  } elseif ( $error['message'] instanceof MessageSpecifier
368  && $error['message']->getKey() === $source ) {
369  $this->errors[$index]['message'] = $dest;
370  $replaced = true;
371  }
372  }
373 
374  return $replaced;
375  }
376 
383  public function __toString() {
384  $status = $this->isOK() ? "OK" : "Error";
385  if ( count( $this->errors ) ) {
386  $errorcount = "collected " . ( count( $this->errors ) ) . " message(s) on the way";
387  } else {
388  $errorcount = "no errors detected";
389  }
390  if ( isset( $this->value ) ) {
391  $valstr = gettype( $this->value ) . " value set";
392  if ( is_object( $this->value ) ) {
393  $valstr .= "\"" . get_class( $this->value ) . "\" instance";
394  }
395  } else {
396  $valstr = "no value set";
397  }
398  $out = sprintf( "<%s, %s, %s>",
399  $status,
400  $errorcount,
401  $valstr
402  );
403  if ( count( $this->errors ) > 0 ) {
404  $hdr = sprintf( "+-%'-8s-+-%'-25s-+-%'-36s-+\n", "", "", "" );
405  $out .= "\n";
406  $out .= $hdr;
407  foreach ( $this->errors as $error ) {
408  if ( $error['message'] instanceof MessageSpecifier ) {
409  $key = $error['message']->getKey();
410  $params = $error['message']->getParams();
411  } elseif ( $error['params'] ) {
412  $key = $error['message'];
413  $params = $error['params'];
414  } else {
415  $key = $error['message'];
416  $params = [];
417  }
418 
419  $type = $error['type'];
420  $keyChunks = str_split( $key, 25 );
421  $paramsChunks = str_split( $this->flattenParams( $params, " | " ), 36 );
422 
423  // array_map(null,...) is like Python's zip()
424  foreach ( array_map( null, [ $type ], $keyChunks, $paramsChunks )
425  as [ $typeChunk, $keyChunk, $paramsChunk ]
426  ) {
427  $out .= sprintf( "| %-8s | %-25.25s | %-36.36s |\n",
428  $typeChunk,
429  $keyChunk,
430  $paramsChunk
431  );
432  }
433  }
434  $out .= $hdr;
435  }
436 
437  return $out;
438  }
439 
446  private function flattenParams( array $params, string $joiner = ', ' ): string {
447  $ret = [];
448  foreach ( $params as $p ) {
449  if ( is_array( $p ) ) {
450  $r = '[ ' . self::flattenParams( $p ) . ' ]';
451  } elseif ( $p instanceof MessageSpecifier ) {
452  $r = '{ ' . $p->getKey() . ': ' . self::flattenParams( $p->getParams() ) . ' }';
453  } else {
454  $r = (string)$p;
455  }
456 
457  $ret[] = strlen( $r ) > 100 ? substr( $r, 0, 99 ) . "..." : $r;
458  }
459  return implode( $joiner, $ret );
460  }
461 
470  protected function getStatusArray( $type = false ) {
471  $result = [];
472 
473  foreach ( $this->getErrors() as $error ) {
474  if ( $type === false || $error['type'] === $type ) {
475  if ( $error['message'] instanceof MessageSpecifier ) {
476  $result[] = array_merge(
477  [ $error['message']->getKey() ],
478  $error['message']->getParams()
479  );
480  } elseif ( $error['params'] ) {
481  $result[] = array_merge( [ $error['message'] ], $error['params'] );
482  } else {
483  $result[] = [ $error['message'] ];
484  }
485  }
486  }
487 
488  return $result;
489  }
490 
497  private function normalizeMessage( $message, array $parameters = [] ) {
498  if ( $message instanceof MessageValue ) {
499  $converter = new Converter();
500  return $converter->convertMessageValue( $message );
501  }
502 
503  return $message;
504  }
505 }
Converter between Message and MessageValue.
Definition: Converter.php:18
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition: StatusValue.php:46
hasMessage( $message)
Returns true if the specified message is present as a warning or error.
static newFatal( $message,... $parameters)
Factory function for fatal errors.
Definition: StatusValue.php:73
int $failCount
Counter for batch operations.
Definition: StatusValue.php:64
array[] $errors
Definition: StatusValue.php:52
getErrors()
Get the list of errors.
replaceMessage( $source, $dest)
If the specified source message exists, replace it with the specified destination message,...
splitByErrorType()
Splits this StatusValue object into two new StatusValue objects, one which contains only the error me...
setOK( $ok)
Change operation status.
getStatusArray( $type=false)
Returns a list of status messages of the given type (or all if false)
isOK()
Returns whether the operation completed.
fatal( $message,... $parameters)
Add an error and set OK to false, indicating that the operation as a whole was fatal.
setResult( $ok, $value=null)
Change operation result.
merge( $other, $overwriteValue=false)
Merge another status object into this one.
__toString()
Returns a string representation of the status for debugging.
bool[] $success
Map of (key => bool) to indicate success of each part of batch operations.
Definition: StatusValue.php:58
mixed $value
Definition: StatusValue.php:55
error( $message,... $parameters)
Add an error, do not set fatal flag This can be used for non-fatal errors.
getErrorsByType( $type)
Returns a list of status messages of the given type.
warning( $message,... $parameters)
Add a new warning.
isGood()
Returns whether the operation completed and didn't have any error or warnings.
static newGood( $value=null)
Factory function for good results.
Definition: StatusValue.php:85
int $successCount
Counter for batch operations.
Definition: StatusValue.php:61
Value object representing a message for i18n.
$source