MediaWiki REL1_39
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
155 public function getErrors() {
156 return $this->errors;
157 }
158
165 public function setOK( $ok ) {
166 $this->ok = $ok;
167 return $this;
168 }
169
177 public function setResult( $ok, $value = null ) {
178 $this->ok = (bool)$ok;
179 $this->value = $value;
180 return $this;
181 }
182
199 private function addError( array $newError ) {
200 if ( $newError[ 'message' ] instanceof MessageSpecifier ) {
201 $isEqual = static function ( $existingError ) use ( $newError ) {
202 if ( $existingError['message'] instanceof MessageSpecifier ) {
203 // compare attributes of both MessageSpecifiers
204 return $newError['message'] == $existingError['message'];
205 } else {
206 return $newError['message']->getKey() === $existingError['message'] &&
207 $newError['message']->getParams() === $existingError['params'];
208 }
209 };
210 } else {
211 $isEqual = static function ( $existingError ) use ( $newError ) {
212 if ( $existingError['message'] instanceof MessageSpecifier ) {
213 return $newError['message'] === $existingError['message']->getKey() &&
214 $newError['params'] === $existingError['message']->getParams();
215 } else {
216 return $newError['message'] === $existingError['message'] &&
217 $newError['params'] === $existingError['params'];
218 }
219 };
220 }
221 foreach ( $this->errors as $index => $existingError ) {
222 if ( $isEqual( $existingError ) ) {
223 if ( $newError[ 'type' ] === 'error' && $existingError[ 'type' ] === 'warning' ) {
224 $this->errors[ $index ][ '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, $parameters );
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, $parameters );
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
318 public function getErrorsByType( $type ) {
319 $result = [];
320 foreach ( $this->errors as $error ) {
321 if ( $error['type'] === $type ) {
322 $result[] = $error;
323 }
324 }
325
326 return $result;
327 }
328
336 public function hasMessage( $message ) {
337 if ( $message instanceof MessageSpecifier ) {
338 $message = $message->getKey();
339 } elseif ( $message instanceof MessageValue ) {
340 $message = $message->getKey();
341 }
342
343 foreach ( $this->errors as $error ) {
344 if ( $error['message'] instanceof MessageSpecifier
345 && $error['message']->getKey() === $message
346 ) {
347 return true;
348 } elseif ( $error['message'] === $message ) {
349 return true;
350 }
351 }
352
353 return false;
354 }
355
367 public function replaceMessage( $source, $dest ) {
368 $replaced = false;
369
370 $source = $this->normalizeMessage( $source );
371 $dest = $this->normalizeMessage( $dest );
372
373 foreach ( $this->errors as $index => $error ) {
374 if ( $error['message'] === $source ) {
375 $this->errors[$index]['message'] = $dest;
376 $replaced = true;
377 } elseif ( $error['message'] instanceof MessageSpecifier
378 && $error['message']->getKey() === $source ) {
379 $this->errors[$index]['message'] = $dest;
380 $replaced = true;
381 }
382 }
383
384 return $replaced;
385 }
386
393 public function __toString() {
394 $status = $this->isOK() ? "OK" : "Error";
395 if ( count( $this->errors ) ) {
396 $errorcount = "collected " . ( count( $this->errors ) ) . " message(s) on the way";
397 } else {
398 $errorcount = "no errors detected";
399 }
400 if ( isset( $this->value ) ) {
401 $valstr = gettype( $this->value ) . " value set";
402 if ( is_object( $this->value ) ) {
403 $valstr .= "\"" . get_class( $this->value ) . "\" instance";
404 }
405 } else {
406 $valstr = "no value set";
407 }
408 $out = sprintf( "<%s, %s, %s>",
409 $status,
410 $errorcount,
411 $valstr
412 );
413 if ( count( $this->errors ) > 0 ) {
414 $hdr = sprintf( "+-%'-8s-+-%'-25s-+-%'-36s-+\n", "", "", "" );
415 $i = 1;
416 $out .= "\n";
417 $out .= $hdr;
418 foreach ( $this->errors as $error ) {
419 if ( $error['message'] instanceof MessageSpecifier ) {
420 $key = $error['message']->getKey();
421 $params = $error['message']->getParams();
422 } elseif ( $error['params'] ) {
423 $key = $error['message'];
424 $params = $error['params'];
425 } else {
426 $key = $error['message'];
427 $params = [];
428 }
429
430 $type = $error['type'];
431 $keyChunks = mb_str_split( $key, 25 );
432 $paramsChunks = mb_str_split( $this->flattenParams( $params, " | " ), 36 );
433
434 // array_map(null,...) is like Python's zip()
435 foreach ( array_map( null, [ $type ], $keyChunks, $paramsChunks )
436 as [ $typeChunk, $keyChunk, $paramsChunk ]
437 ) {
438 $out .= sprintf( "| %-8s | %-25s | %-36s |\n",
439 $typeChunk,
440 $keyChunk,
441 $paramsChunk
442 );
443 }
444
445 $i++;
446 }
447 $out .= $hdr;
448 }
449
450 return $out;
451 }
452
459 private function flattenParams( array $params, string $joiner = ', ' ): string {
460 $ret = [];
461 foreach ( $params as $p ) {
462 if ( is_array( $p ) ) {
463 $r = '[ ' . self::flattenParams( $p ) . ' ]';
464 } elseif ( $p instanceof MessageSpecifier ) {
465 $r = '{ ' . $p->getKey() . ': ' . self::flattenParams( $p->getParams() ) . ' }';
466 } else {
467 $r = (string)$p;
468 }
469
470 $ret[] = mb_strlen( $r ) > 100 ? mb_substr( $r, 0, 99 ) . "..." : $r;
471 }
472 return implode( $joiner, $ret );
473 }
474
483 protected function getStatusArray( $type = false ) {
484 $result = [];
485
486 foreach ( $this->getErrors() as $error ) {
487 if ( $type === false || $error['type'] === $type ) {
488 if ( $error['message'] instanceof MessageSpecifier ) {
489 $result[] = array_merge(
490 [ $error['message']->getKey() ],
491 $error['message']->getParams()
492 );
493 } elseif ( $error['params'] ) {
494 $result[] = array_merge( [ $error['message'] ], $error['params'] );
495 } else {
496 $result[] = [ $error['message'] ];
497 }
498 }
499 }
500
501 return $result;
502 }
503
510 private function normalizeMessage( $message, array $parameters = [] ) {
511 if ( $message instanceof MessageValue ) {
512 $converter = new Converter();
513 return $converter->convertMessageValue( $message );
514 }
515
516 return $message;
517 }
518}
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.
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