MediaWiki 1.43.1
StatusValue.php
Go to the documentation of this file.
1<?php
21use Wikimedia\Assert\Assert;
25
52class StatusValue implements Stringable {
53
58 protected $ok = true;
59
66 protected $errors = [];
67
69 public $value;
70
72 public $success = [];
73
75 public $successCount = 0;
76
78 public $failCount = 0;
79
82
90 public static function newFatal( $message, ...$parameters ) {
91 $result = new static();
92 $result->fatal( $message, ...$parameters );
93 return $result;
94 }
95
102 public static function newGood( $value = null ) {
103 $result = new static();
104 $result->value = $value;
105 return $result;
106 }
107
119 public function splitByErrorType() {
120 $errorsOnlyStatusValue = static::newGood();
121 $warningsOnlyStatusValue = static::newGood();
122 $warningsOnlyStatusValue->setResult( true, $this->getValue() );
123 $errorsOnlyStatusValue->setResult( $this->isOK(), $this->getValue() );
124
125 foreach ( $this->errors as $item ) {
126 if ( $item['type'] === 'warning' ) {
127 $warningsOnlyStatusValue->errors[] = $item;
128 } else {
129 $errorsOnlyStatusValue->errors[] = $item;
130 }
131 }
132
133 return [ $errorsOnlyStatusValue, $warningsOnlyStatusValue ];
134 }
135
142 public function isGood() {
143 return $this->ok && !$this->errors;
144 }
145
151 public function isOK() {
152 return $this->ok;
153 }
154
158 public function getValue() {
159 return $this->value;
160 }
161
171 public function getErrors() {
172 return $this->errors;
173 }
174
181 public function setOK( $ok ) {
182 $this->ok = $ok;
183 return $this;
184 }
185
193 public function setResult( $ok, $value = null ) {
194 $this->ok = (bool)$ok;
195 $this->value = $value;
196 return $this;
197 }
198
216 private function addError( array $newError ) {
217 [ 'type' => $newType, 'message' => $newKey, 'params' => $newParams ] = $newError;
218 if ( $newKey instanceof MessageSpecifier ) {
219 if ( $newParams ) {
220 // Deprecate code like `Status::newFatal( wfMessage( 'foo' ), 'param' )`
221 // - the parameters have always been ignored, so this is usually a mistake.
222 wfDeprecatedMsg( 'Combining MessageSpecifier and parameters array' .
223 ' was deprecated in MediaWiki 1.43', '1.43' );
224 }
225 $newParams = $newKey->getParams();
226 $newKey = $newKey->getKey();
227 }
228
229 foreach ( $this->errors as [ 'type' => &$type, 'message' => $key, 'params' => $params ] ) {
230 if ( $key instanceof MessageSpecifier ) {
231 $params = $key->getParams();
232 $key = $key->getKey();
233 }
234
235 // This uses loose equality as we must support equality between MessageParam objects
236 // (e.g. ScalarParam), including when they are created separate and not by-ref equal.
237 if ( $newKey === $key && $newParams == $params ) {
238 if ( $type === 'warning' && $newType === 'error' ) {
239 $type = 'error';
240 }
241 return $this;
242 }
243 }
244
245 $this->errors[] = $newError;
246
247 return $this;
248 }
249
257 public function warning( $message, ...$parameters ) {
258 return $this->addError( [
259 'type' => 'warning',
260 'message' => $message,
261 'params' => $parameters
262 ] );
263 }
264
273 public function error( $message, ...$parameters ) {
274 return $this->addError( [
275 'type' => 'error',
276 'message' => $message,
277 'params' => $parameters
278 ] );
279 }
280
289 public function fatal( $message, ...$parameters ) {
290 $this->ok = false;
291 return $this->error( $message, ...$parameters );
292 }
293
301 public function merge( $other, $overwriteValue = false ) {
302 if ( $this->statusData !== null && $other->statusData !== null ) {
303 throw new RuntimeException( "Status cannot be merged, because they both have \$statusData" );
304 } else {
305 $this->statusData ??= $other->statusData;
306 }
307
308 foreach ( $other->errors as $error ) {
309 $this->addError( $error );
310 }
311 $this->ok = $this->ok && $other->ok;
312 if ( $overwriteValue ) {
313 $this->value = $other->value;
314 }
315 $this->successCount += $other->successCount;
316 $this->failCount += $other->failCount;
317
318 return $this;
319 }
320
333 public function getErrorsByType( $type ) {
334 $result = [];
335 foreach ( $this->errors as $error ) {
336 if ( $error['type'] === $type ) {
337 $result[] = $error;
338 }
339 }
340
341 return $result;
342 }
343
355 public function getMessages( ?string $type = null ): array {
356 Assert::parameter( $type === null || $type === 'warning' || $type === 'error',
357 '$type', "must be null, 'warning', or 'error'" );
358 $result = [];
359 foreach ( $this->errors as $error ) {
360 if ( $type === null || $error['type'] === $type ) {
361 [ 'message' => $key, 'params' => $params ] = $error;
362 if ( $key instanceof MessageSpecifier ) {
363 $result[] = $key;
364 } else {
365 $result[] = new MessageValue( $key, $params );
366 }
367 }
368 }
369
370 return $result;
371 }
372
381 public function hasMessage( $message ) {
382 if ( $message instanceof MessageSpecifier ) {
383 wfDeprecatedMsg( 'Passing MessageSpecifier to hasMessage()' .
384 ' was deprecated in MediaWiki 1.43', '1.43' );
385 $message = $message->getKey();
386 }
387
388 foreach ( $this->errors as [ 'message' => $key ] ) {
389 if ( ( $key instanceof MessageSpecifier && $key->getKey() === $message ) ||
390 $key === $message
391 ) {
392 return true;
393 }
394 }
395
396 return false;
397 }
398
407 public function hasMessagesExcept( ...$messages ) {
408 $exceptedKeys = [];
409 foreach ( $messages as $message ) {
410 if ( $message instanceof MessageSpecifier ) {
411 wfDeprecatedMsg( 'Passing MessageSpecifier to hasMessagesExcept()' .
412 ' was deprecated in MediaWiki 1.43', '1.43' );
413 $message = $message->getKey();
414 }
415 $exceptedKeys[] = $message;
416 }
417
418 foreach ( $this->errors as [ 'message' => $key ] ) {
419 if ( $key instanceof MessageSpecifier ) {
420 $key = $key->getKey();
421 }
422 if ( !in_array( $key, $exceptedKeys, true ) ) {
423 return true;
424 }
425 }
426
427 return false;
428 }
429
448 public function replaceMessage( $source, $dest ) {
449 $replaced = false;
450
451 if ( $source instanceof MessageSpecifier ) {
452 wfDeprecatedMsg( 'Passing MessageSpecifier as $source to replaceMessage()' .
453 ' was deprecated in MediaWiki 1.43', '1.43' );
454 }
455
456 foreach ( $this->errors as [ 'message' => &$message, 'params' => &$params ] ) {
457 if ( $message === $source ||
458 ( $message instanceof MessageSpecifier && $message->getKey() === $source )
459 ) {
460 $message = $dest;
461 if ( $dest instanceof MessageSpecifier ) {
462 // 'params' will be ignored now, so remove them from the internal array
463 $params = [];
464 }
465 $replaced = true;
466 }
467 }
468
469 return $replaced;
470 }
471
478 public function __toString() {
479 $status = $this->isOK() ? "OK" : "Error";
480 if ( count( $this->errors ) ) {
481 $errorcount = "collected " . ( count( $this->errors ) ) . " message(s) on the way";
482 } else {
483 $errorcount = "no errors detected";
484 }
485 if ( isset( $this->value ) ) {
486 $valstr = get_debug_type( $this->value ) . " value set";
487 } else {
488 $valstr = "no value set";
489 }
490 $out = sprintf( "<%s, %s, %s>",
491 $status,
492 $errorcount,
493 $valstr
494 );
495 if ( count( $this->errors ) > 0 ) {
496 $hdr = sprintf( "+-%'-8s-+-%'-25s-+-%'-36s-+\n", "", "", "" );
497 $out .= "\n" . $hdr;
498 foreach ( $this->errors as [ 'type' => $type, 'message' => $key, 'params' => $params ] ) {
499 if ( $key instanceof MessageSpecifier ) {
500 $params = $key->getParams();
501 $key = $key->getKey();
502 }
503
504 $keyChunks = mb_str_split( $key, 25 );
505 $paramsChunks = mb_str_split( $this->flattenParams( $params, " | " ), 36 );
506
507 // array_map(null,...) is like Python's zip()
508 foreach ( array_map( null, [ $type ], $keyChunks, $paramsChunks )
509 as [ $typeChunk, $keyChunk, $paramsChunk ]
510 ) {
511 $out .= sprintf( "| %-8s | %-25s | %-36s |\n",
512 $typeChunk,
513 $keyChunk,
514 $paramsChunk
515 );
516 }
517 }
518 $out .= $hdr;
519 }
520
521 return $out;
522 }
523
530 private function flattenParams( array $params, string $joiner = ', ' ): string {
531 $ret = [];
532 foreach ( $params as $p ) {
533 if ( is_array( $p ) ) {
534 $r = '[ ' . self::flattenParams( $p ) . ' ]';
535 } elseif ( $p instanceof MessageSpecifier ) {
536 $r = '{ ' . $p->getKey() . ': ' . self::flattenParams( $p->getParams() ) . ' }';
537 } elseif ( $p instanceof MessageParam ) {
538 $r = $p->dump();
539 } else {
540 $r = (string)$p;
541 }
542
543 $ret[] = mb_strlen( $r ) > 100 ? mb_substr( $r, 0, 99 ) . "..." : $r;
544 }
545 return implode( $joiner, $ret );
546 }
547
556 protected function getStatusArray( $type = false ) {
557 $result = [];
558
559 foreach ( $this->getErrors() as $error ) {
560 if ( !$type || $error['type'] === $type ) {
561 if ( $error['message'] instanceof MessageSpecifier ) {
562 $result[] = [ $error['message']->getKey(), ...$error['message']->getParams() ];
563 } else {
564 $result[] = [ $error['message'], ...$error['params'] ];
565 }
566 }
567 }
568
569 return $result;
570 }
571}
wfDeprecatedMsg( $msg, $version=false, $component=false, $callerOffset=2)
Log a deprecation warning with arbitrary message text.
array $params
The job parameters.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
hasMessage( $message)
Returns true if the specified message is present as a warning or error.
static newFatal( $message,... $parameters)
Factory function for fatal errors.
int $failCount
Counter for batch operations.
array[] $errors
getErrors()
Get the list of errors.
getMessages(?string $type=null)
Returns a list of error messages, optionally only those of the given type.
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.
mixed $statusData
arbitrary extra data about the operation
__toString()
Returns a string representation of the status for debugging.
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.
int $successCount
Counter for batch operations.
Value object representing a message parameter that consists of a list of values.
Value object representing a message for i18n.
getKey()
Returns the message key.
$source