MediaWiki master
StatusValue.php
Go to the documentation of this file.
1<?php
23
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
68
76 public static function newFatal( $message, ...$parameters ) {
77 $result = new static();
78 $result->fatal( $message, ...$parameters );
79 return $result;
80 }
81
88 public static function newGood( $value = null ) {
89 $result = new static();
90 $result->value = $value;
91 return $result;
92 }
93
105 public function splitByErrorType() {
106 $errorsOnlyStatusValue = static::newGood();
107 $warningsOnlyStatusValue = static::newGood();
108 $warningsOnlyStatusValue->setResult( true, $this->getValue() );
109 $errorsOnlyStatusValue->setResult( $this->isOK(), $this->getValue() );
110
111 foreach ( $this->errors as $item ) {
112 if ( $item['type'] === 'warning' ) {
113 $warningsOnlyStatusValue->errors[] = $item;
114 } else {
115 $errorsOnlyStatusValue->errors[] = $item;
116 }
117 }
118
119 return [ $errorsOnlyStatusValue, $warningsOnlyStatusValue ];
120 }
121
128 public function isGood() {
129 return $this->ok && !$this->errors;
130 }
131
137 public function isOK() {
138 return $this->ok;
139 }
140
144 public function getValue() {
145 return $this->value;
146 }
147
156 public function getErrors() {
157 return $this->errors;
158 }
159
166 public function setOK( $ok ) {
167 $this->ok = $ok;
168 return $this;
169 }
170
178 public function setResult( $ok, $value = null ) {
179 $this->ok = (bool)$ok;
180 $this->value = $value;
181 return $this;
182 }
183
201 private function addError( array $newError ) {
202 if ( $newError[ 'message' ] instanceof MessageSpecifier ) {
203 $isEqual = static function ( $key, $params ) use ( $newError ) {
204 if ( $key instanceof MessageSpecifier ) {
205 // compare attributes of both MessageSpecifiers
206 return $newError['message'] == $key;
207 } else {
208 return $newError['message']->getKey() === $key &&
209 $newError['message']->getParams() === $params;
210 }
211 };
212 } else {
213 $isEqual = static function ( $key, $params ) use ( $newError ) {
214 if ( $key instanceof MessageSpecifier ) {
215 $params = $key->getParams();
216 $key = $key->getKey();
217 }
218 return $newError['message'] === $key && $newError['params'] === $params;
219 };
220 }
221 foreach ( $this->errors as [ 'type' => &$type, 'message' => $key, 'params' => $params ] ) {
222 if ( $isEqual( $key, $params ) ) {
223 if ( $type === 'warning' && $newError['type'] === 'error' ) {
224 $type = 'error';
225 }
226 return $this;
227 }
228 }
229 $this->errors[] = $newError;
230 return $this;
231 }
232
240 public function warning( $message, ...$parameters ) {
241 $message = $this->normalizeMessage( $message );
242
243 return $this->addError( [
244 'type' => 'warning',
245 'message' => $message,
246 'params' => $parameters
247 ] );
248 }
249
258 public function error( $message, ...$parameters ) {
259 $message = $this->normalizeMessage( $message );
260
261 return $this->addError( [
262 'type' => 'error',
263 'message' => $message,
264 'params' => $parameters
265 ] );
266 }
267
276 public function fatal( $message, ...$parameters ) {
277 $this->ok = false;
278 return $this->error( $message, ...$parameters );
279 }
280
288 public function merge( $other, $overwriteValue = false ) {
289 if ( $this->statusData !== null && $other->statusData !== null ) {
290 throw new RuntimeException( "Status cannot be merged, because they both have \$statusData" );
291 } else {
292 $this->statusData ??= $other->statusData;
293 }
294
295 foreach ( $other->errors as $error ) {
296 $this->addError( $error );
297 }
298 $this->ok = $this->ok && $other->ok;
299 if ( $overwriteValue ) {
300 $this->value = $other->value;
301 }
302 $this->successCount += $other->successCount;
303 $this->failCount += $other->failCount;
304
305 return $this;
306 }
307
319 public function getErrorsByType( $type ) {
320 $result = [];
321 foreach ( $this->errors as $error ) {
322 if ( $error['type'] === $type ) {
323 $result[] = $error;
324 }
325 }
326
327 return $result;
328 }
329
337 public function hasMessage( $message ) {
338 if ( $message instanceof MessageSpecifier || $message instanceof MessageValue ) {
339 $message = $message->getKey();
340 }
341
342 foreach ( $this->errors as [ 'message' => $key ] ) {
343 if ( $key instanceof MessageSpecifier && $key->getKey() === $message ||
344 $key === $message
345 ) {
346 return true;
347 }
348 }
349
350 return false;
351 }
352
360 public function hasMessagesExcept( ...$messages ) {
361 $exceptedKeys = [];
362 foreach ( $messages as $message ) {
363 if ( $message instanceof MessageSpecifier || $message instanceof MessageValue ) {
364 $message = $message->getKey();
365 }
366 $exceptedKeys[] = $message;
367 }
368
369 foreach ( $this->errors as [ 'message' => $key ] ) {
370 if ( $key instanceof MessageSpecifier ) {
371 $key = $key->getKey();
372 }
373 if ( !in_array( $key, $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 [ 'message' => &$message ] ) {
399 if ( $message === $source ||
400 $message instanceof MessageSpecifier && $message->getKey() === $source
401 ) {
402 $message = $dest;
403 $replaced = true;
404 }
405 }
406
407 return $replaced;
408 }
409
416 public function __toString() {
417 $status = $this->isOK() ? "OK" : "Error";
418 if ( count( $this->errors ) ) {
419 $errorcount = "collected " . ( count( $this->errors ) ) . " message(s) on the way";
420 } else {
421 $errorcount = "no errors detected";
422 }
423 if ( isset( $this->value ) ) {
424 $valstr = gettype( $this->value ) . " value set";
425 if ( is_object( $this->value ) ) {
426 $valstr .= "\"" . get_class( $this->value ) . "\" instance";
427 }
428 } else {
429 $valstr = "no value set";
430 }
431 $out = sprintf( "<%s, %s, %s>",
432 $status,
433 $errorcount,
434 $valstr
435 );
436 if ( count( $this->errors ) > 0 ) {
437 $hdr = sprintf( "+-%'-8s-+-%'-25s-+-%'-36s-+\n", "", "", "" );
438 $out .= "\n" . $hdr;
439 foreach ( $this->errors as [ 'type' => $type, 'message' => $key, 'params' => $params ] ) {
440 if ( $key instanceof MessageSpecifier ) {
441 $params = $key->getParams();
442 $key = $key->getKey();
443 }
444
445 $keyChunks = mb_str_split( $key, 25 );
446 $paramsChunks = mb_str_split( $this->flattenParams( $params, " | " ), 36 );
447
448 // array_map(null,...) is like Python's zip()
449 foreach ( array_map( null, [ $type ], $keyChunks, $paramsChunks )
450 as [ $typeChunk, $keyChunk, $paramsChunk ]
451 ) {
452 $out .= sprintf( "| %-8s | %-25s | %-36s |\n",
453 $typeChunk,
454 $keyChunk,
455 $paramsChunk
456 );
457 }
458 }
459 $out .= $hdr;
460 }
461
462 return $out;
463 }
464
471 private function flattenParams( array $params, string $joiner = ', ' ): string {
472 $ret = [];
473 foreach ( $params as $p ) {
474 if ( is_array( $p ) ) {
475 $r = '[ ' . self::flattenParams( $p ) . ' ]';
476 } elseif ( $p instanceof MessageSpecifier ) {
477 $r = '{ ' . $p->getKey() . ': ' . self::flattenParams( $p->getParams() ) . ' }';
478 } else {
479 $r = (string)$p;
480 }
481
482 $ret[] = mb_strlen( $r ) > 100 ? mb_substr( $r, 0, 99 ) . "..." : $r;
483 }
484 return implode( $joiner, $ret );
485 }
486
495 protected function getStatusArray( $type = false ) {
496 $result = [];
497
498 foreach ( $this->getErrors() as $error ) {
499 if ( !$type || $error['type'] === $type ) {
500 if ( $error['message'] instanceof MessageSpecifier ) {
501 $result[] = [ $error['message']->getKey(), ...$error['message']->getParams() ];
502 } else {
503 $result[] = [ $error['message'], ...$error['params'] ];
504 }
505 }
506 }
507
508 return $result;
509 }
510
516 private function normalizeMessage( $message ) {
517 if ( $message instanceof MessageValue ) {
518 $converter = new Converter();
519 return $converter->convertMessageValue( $message );
520 }
521
522 return $message;
523 }
524}
Converter between Message and MessageValue.
Definition Converter.php:18
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.
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 for i18n.
getKey()
Returns the message key.
$source