MediaWiki REL1_40
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 ( $existingError ) use ( $newError ) {
204 if ( $existingError['message'] instanceof MessageSpecifier ) {
205 // compare attributes of both MessageSpecifiers
206 return $newError['message'] == $existingError['message'];
207 } else {
208 return $newError['message']->getKey() === $existingError['message'] &&
209 $newError['message']->getParams() === $existingError['params'];
210 }
211 };
212 } else {
213 $isEqual = static function ( $existingError ) use ( $newError ) {
214 if ( $existingError['message'] instanceof MessageSpecifier ) {
215 return $newError['message'] === $existingError['message']->getKey() &&
216 $newError['params'] === $existingError['message']->getParams();
217 } else {
218 return $newError['message'] === $existingError['message'] &&
219 $newError['params'] === $existingError['params'];
220 }
221 };
222 }
223 foreach ( $this->errors as $index => $existingError ) {
224 if ( $isEqual( $existingError ) ) {
225 if ( $newError[ 'type' ] === 'error' && $existingError[ 'type' ] === 'warning' ) {
226 $this->errors[ $index ][ 'type' ] = 'error';
227 }
228 return $this;
229 }
230 }
231 $this->errors[] = $newError;
232 return $this;
233 }
234
242 public function warning( $message, ...$parameters ) {
243 $message = $this->normalizeMessage( $message );
244
245 return $this->addError( [
246 'type' => 'warning',
247 'message' => $message,
248 'params' => $parameters
249 ] );
250 }
251
260 public function error( $message, ...$parameters ) {
261 $message = $this->normalizeMessage( $message );
262
263 return $this->addError( [
264 'type' => 'error',
265 'message' => $message,
266 'params' => $parameters
267 ] );
268 }
269
278 public function fatal( $message, ...$parameters ) {
279 $this->ok = false;
280 return $this->error( $message, ...$parameters );
281 }
282
290 public function merge( $other, $overwriteValue = false ) {
291 if ( $this->statusData !== null && $other->statusData !== null ) {
292 throw new RuntimeException( "Status cannot be merged, because they both have \$statusData" );
293 } else {
294 $this->statusData ??= $other->statusData;
295 }
296
297 foreach ( $other->errors as $error ) {
298 $this->addError( $error );
299 }
300 $this->ok = $this->ok && $other->ok;
301 if ( $overwriteValue ) {
302 $this->value = $other->value;
303 }
304 $this->successCount += $other->successCount;
305 $this->failCount += $other->failCount;
306
307 return $this;
308 }
309
321 public function getErrorsByType( $type ) {
322 $result = [];
323 foreach ( $this->errors as $error ) {
324 if ( $error['type'] === $type ) {
325 $result[] = $error;
326 }
327 }
328
329 return $result;
330 }
331
339 public function hasMessage( $message ) {
340 if ( $message instanceof MessageSpecifier ) {
341 $message = $message->getKey();
342 } elseif ( $message instanceof MessageValue ) {
343 $message = $message->getKey();
344 }
345
346 foreach ( $this->errors as $error ) {
347 if ( $error['message'] instanceof MessageSpecifier
348 && $error['message']->getKey() === $message
349 ) {
350 return true;
351 } elseif ( $error['message'] === $message ) {
352 return true;
353 }
354 }
355
356 return false;
357 }
358
366 public function hasMessagesExcept( ...$messages ) {
367 $exceptedKeys = [];
368 foreach ( $messages as $message ) {
369 if ( $message instanceof MessageSpecifier ) {
370 $message = $message->getKey();
371 } elseif ( $message instanceof MessageValue ) {
372 $message = $message->getKey();
373 }
374 $exceptedKeys[] = $message;
375 }
376
377 foreach ( $this->errors as $error ) {
378 if ( $error['message'] instanceof MessageSpecifier ) {
379 $actualKey = $error['message']->getKey();
380 } else {
381 $actualKey = $error['message'];
382 }
383 if ( !in_array( $actualKey, $exceptedKeys, true ) ) {
384 return true;
385 }
386 }
387
388 return false;
389 }
390
402 public function replaceMessage( $source, $dest ) {
403 $replaced = false;
404
405 $source = $this->normalizeMessage( $source );
406 $dest = $this->normalizeMessage( $dest );
407
408 foreach ( $this->errors as $index => $error ) {
409 if ( $error['message'] === $source ) {
410 $this->errors[$index]['message'] = $dest;
411 $replaced = true;
412 } elseif ( $error['message'] instanceof MessageSpecifier
413 && $error['message']->getKey() === $source ) {
414 $this->errors[$index]['message'] = $dest;
415 $replaced = true;
416 }
417 }
418
419 return $replaced;
420 }
421
428 public function __toString() {
429 $status = $this->isOK() ? "OK" : "Error";
430 if ( count( $this->errors ) ) {
431 $errorcount = "collected " . ( count( $this->errors ) ) . " message(s) on the way";
432 } else {
433 $errorcount = "no errors detected";
434 }
435 if ( isset( $this->value ) ) {
436 $valstr = gettype( $this->value ) . " value set";
437 if ( is_object( $this->value ) ) {
438 $valstr .= "\"" . get_class( $this->value ) . "\" instance";
439 }
440 } else {
441 $valstr = "no value set";
442 }
443 $out = sprintf( "<%s, %s, %s>",
444 $status,
445 $errorcount,
446 $valstr
447 );
448 if ( count( $this->errors ) > 0 ) {
449 $hdr = sprintf( "+-%'-8s-+-%'-25s-+-%'-36s-+\n", "", "", "" );
450 $out .= "\n";
451 $out .= $hdr;
452 foreach ( $this->errors as $error ) {
453 if ( $error['message'] instanceof MessageSpecifier ) {
454 $key = $error['message']->getKey();
455 $params = $error['message']->getParams();
456 } elseif ( $error['params'] ) {
457 $key = $error['message'];
458 $params = $error['params'];
459 } else {
460 $key = $error['message'];
461 $params = [];
462 }
463
464 $type = $error['type'];
465 $keyChunks = mb_str_split( $key, 25 );
466 $paramsChunks = mb_str_split( $this->flattenParams( $params, " | " ), 36 );
467
468 // array_map(null,...) is like Python's zip()
469 foreach ( array_map( null, [ $type ], $keyChunks, $paramsChunks )
470 as [ $typeChunk, $keyChunk, $paramsChunk ]
471 ) {
472 $out .= sprintf( "| %-8s | %-25s | %-36s |\n",
473 $typeChunk,
474 $keyChunk,
475 $paramsChunk
476 );
477 }
478 }
479 $out .= $hdr;
480 }
481
482 return $out;
483 }
484
491 private function flattenParams( array $params, string $joiner = ', ' ): string {
492 $ret = [];
493 foreach ( $params as $p ) {
494 if ( is_array( $p ) ) {
495 $r = '[ ' . self::flattenParams( $p ) . ' ]';
496 } elseif ( $p instanceof MessageSpecifier ) {
497 $r = '{ ' . $p->getKey() . ': ' . self::flattenParams( $p->getParams() ) . ' }';
498 } else {
499 $r = (string)$p;
500 }
501
502 $ret[] = mb_strlen( $r ) > 100 ? mb_substr( $r, 0, 99 ) . "..." : $r;
503 }
504 return implode( $joiner, $ret );
505 }
506
515 protected function getStatusArray( $type = false ) {
516 $result = [];
517
518 foreach ( $this->getErrors() as $error ) {
519 if ( $type === false || $error['type'] === $type ) {
520 if ( $error['message'] instanceof MessageSpecifier ) {
521 $result[] = array_merge(
522 [ $error['message']->getKey() ],
523 $error['message']->getParams()
524 );
525 } elseif ( $error['params'] ) {
526 $result[] = array_merge( [ $error['message'] ], $error['params'] );
527 } else {
528 $result[] = [ $error['message'] ];
529 }
530 }
531 }
532
533 return $result;
534 }
535
541 private function normalizeMessage( $message ) {
542 if ( $message instanceof MessageValue ) {
543 $converter = new Converter();
544 return $converter->convertMessageValue( $message );
545 }
546
547 return $message;
548 }
549}
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.
$source