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 
153  public function getErrors() {
154  return $this->errors;
155  }
156 
163  public function setOK( $ok ) {
164  $this->ok = $ok;
165  return $this;
166  }
167 
175  public function setResult( $ok, $value = null ) {
176  $this->ok = (bool)$ok;
177  $this->value = $value;
178  return $this;
179  }
180 
198  private function addError( array $newError ) {
199  if ( $newError[ 'message' ] instanceof MessageSpecifier ) {
200  $isEqual = static function ( $existingError ) use ( $newError ) {
201  if ( $existingError['message'] instanceof MessageSpecifier ) {
202  // compare attributes of both MessageSpecifiers
203  return $newError['message'] == $existingError['message'];
204  } else {
205  return $newError['message']->getKey() === $existingError['message'] &&
206  $newError['message']->getParams() === $existingError['params'];
207  }
208  };
209  } else {
210  $isEqual = static function ( $existingError ) use ( $newError ) {
211  if ( $existingError['message'] instanceof MessageSpecifier ) {
212  return $newError['message'] === $existingError['message']->getKey() &&
213  $newError['params'] === $existingError['message']->getParams();
214  } else {
215  return $newError['message'] === $existingError['message'] &&
216  $newError['params'] === $existingError['params'];
217  }
218  };
219  }
220  foreach ( $this->errors as $index => $existingError ) {
221  if ( $isEqual( $existingError ) ) {
222  if ( $newError[ 'type' ] === 'error' && $existingError[ 'type' ] === 'warning' ) {
223  $this->errors[ $index ][ 'type' ] = 'error';
224  }
225  return $this;
226  }
227  }
228  $this->errors[] = $newError;
229  return $this;
230  }
231 
239  public function warning( $message, ...$parameters ) {
240  $message = $this->normalizeMessage( $message );
241 
242  return $this->addError( [
243  'type' => 'warning',
244  'message' => $message,
245  'params' => $parameters
246  ] );
247  }
248 
257  public function error( $message, ...$parameters ) {
258  $message = $this->normalizeMessage( $message );
259 
260  return $this->addError( [
261  'type' => 'error',
262  'message' => $message,
263  'params' => $parameters
264  ] );
265  }
266 
275  public function fatal( $message, ...$parameters ) {
276  $this->ok = false;
277  return $this->error( $message, ...$parameters );
278  }
279 
287  public function merge( $other, $overwriteValue = false ) {
288  foreach ( $other->errors as $error ) {
289  $this->addError( $error );
290  }
291  $this->ok = $this->ok && $other->ok;
292  if ( $overwriteValue ) {
293  $this->value = $other->value;
294  }
295  $this->successCount += $other->successCount;
296  $this->failCount += $other->failCount;
297  return $this;
298  }
299 
311  public function getErrorsByType( $type ) {
312  $result = [];
313  foreach ( $this->errors as $error ) {
314  if ( $error['type'] === $type ) {
315  $result[] = $error;
316  }
317  }
318 
319  return $result;
320  }
321 
329  public function hasMessage( $message ) {
330  if ( $message instanceof MessageSpecifier ) {
331  $message = $message->getKey();
332  } elseif ( $message instanceof MessageValue ) {
333  $message = $message->getKey();
334  }
335 
336  foreach ( $this->errors as $error ) {
337  if ( $error['message'] instanceof MessageSpecifier
338  && $error['message']->getKey() === $message
339  ) {
340  return true;
341  } elseif ( $error['message'] === $message ) {
342  return true;
343  }
344  }
345 
346  return false;
347  }
348 
356  public function hasMessagesExcept( ...$messages ) {
357  $exceptedKeys = [];
358  foreach ( $messages as $message ) {
359  if ( $message instanceof MessageSpecifier ) {
360  $message = $message->getKey();
361  } elseif ( $message instanceof MessageValue ) {
362  $message = $message->getKey();
363  }
364  $exceptedKeys[] = $message;
365  }
366 
367  foreach ( $this->errors as $error ) {
368  if ( $error['message'] instanceof MessageSpecifier ) {
369  $actualKey = $error['message']->getKey();
370  } else {
371  $actualKey = $error['message'];
372  }
373  if ( !in_array( $actualKey, $exceptedKeys, true ) ) {
374  return true;
375  }
376  }
377 
378  return false;
379  }
380 
392  public function replaceMessage( $source, $dest ) {
393  $replaced = false;
394 
395  $source = $this->normalizeMessage( $source );
396  $dest = $this->normalizeMessage( $dest );
397 
398  foreach ( $this->errors as $index => $error ) {
399  if ( $error['message'] === $source ) {
400  $this->errors[$index]['message'] = $dest;
401  $replaced = true;
402  } elseif ( $error['message'] instanceof MessageSpecifier
403  && $error['message']->getKey() === $source ) {
404  $this->errors[$index]['message'] = $dest;
405  $replaced = true;
406  }
407  }
408 
409  return $replaced;
410  }
411 
418  public function __toString() {
419  $status = $this->isOK() ? "OK" : "Error";
420  if ( count( $this->errors ) ) {
421  $errorcount = "collected " . ( count( $this->errors ) ) . " message(s) on the way";
422  } else {
423  $errorcount = "no errors detected";
424  }
425  if ( isset( $this->value ) ) {
426  $valstr = gettype( $this->value ) . " value set";
427  if ( is_object( $this->value ) ) {
428  $valstr .= "\"" . get_class( $this->value ) . "\" instance";
429  }
430  } else {
431  $valstr = "no value set";
432  }
433  $out = sprintf( "<%s, %s, %s>",
434  $status,
435  $errorcount,
436  $valstr
437  );
438  if ( count( $this->errors ) > 0 ) {
439  $hdr = sprintf( "+-%'-8s-+-%'-25s-+-%'-36s-+\n", "", "", "" );
440  $out .= "\n";
441  $out .= $hdr;
442  foreach ( $this->errors as $error ) {
443  if ( $error['message'] instanceof MessageSpecifier ) {
444  $key = $error['message']->getKey();
445  $params = $error['message']->getParams();
446  } elseif ( $error['params'] ) {
447  $key = $error['message'];
448  $params = $error['params'];
449  } else {
450  $key = $error['message'];
451  $params = [];
452  }
453 
454  $type = $error['type'];
455  $keyChunks = str_split( $key, 25 );
456  $paramsChunks = str_split( $this->flattenParams( $params, " | " ), 36 );
457 
458  // array_map(null,...) is like Python's zip()
459  foreach ( array_map( null, [ $type ], $keyChunks, $paramsChunks )
460  as [ $typeChunk, $keyChunk, $paramsChunk ]
461  ) {
462  $out .= sprintf( "| %-8s | %-25.25s | %-36.36s |\n",
463  $typeChunk,
464  $keyChunk,
465  $paramsChunk
466  );
467  }
468  }
469  $out .= $hdr;
470  }
471 
472  return $out;
473  }
474 
481  private function flattenParams( array $params, string $joiner = ', ' ): string {
482  $ret = [];
483  foreach ( $params as $p ) {
484  if ( is_array( $p ) ) {
485  $r = '[ ' . self::flattenParams( $p ) . ' ]';
486  } elseif ( $p instanceof MessageSpecifier ) {
487  $r = '{ ' . $p->getKey() . ': ' . self::flattenParams( $p->getParams() ) . ' }';
488  } else {
489  $r = (string)$p;
490  }
491 
492  $ret[] = strlen( $r ) > 100 ? substr( $r, 0, 99 ) . "..." : $r;
493  }
494  return implode( $joiner, $ret );
495  }
496 
505  protected function getStatusArray( $type = false ) {
506  $result = [];
507 
508  foreach ( $this->getErrors() as $error ) {
509  if ( $type === false || $error['type'] === $type ) {
510  if ( $error['message'] instanceof MessageSpecifier ) {
511  $result[] = array_merge(
512  [ $error['message']->getKey() ],
513  $error['message']->getParams()
514  );
515  } elseif ( $error['params'] ) {
516  $result[] = array_merge( [ $error['message'] ], $error['params'] );
517  } else {
518  $result[] = [ $error['message'] ];
519  }
520  }
521  }
522 
523  return $result;
524  }
525 
531  private function normalizeMessage( $message ) {
532  if ( $message instanceof MessageValue ) {
533  $converter = new Converter();
534  return $converter->convertMessageValue( $message );
535  }
536 
537  return $message;
538  }
539 }
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.
hasMessagesExcept(... $messages)
Returns true if any other message than the specified ones is present as a warning or error.
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