X-Git-Url: https://scripts.mit.edu/gitweb/autoinstallsdev/mediawiki.git/blobdiff_plain/19e297c21b10b1b8a3acad5e73fc71dcb35db44a..6932310fd58ebef145fa01eb76edf7150284d8ea:/includes/libs/StatusValue.php diff --git a/includes/libs/StatusValue.php b/includes/libs/StatusValue.php new file mode 100644 index 00000000..f9dcc1b5 --- /dev/null +++ b/includes/libs/StatusValue.php @@ -0,0 +1,351 @@ + bool) to indicate success of each part of batch operations */ + public $success = []; + + /** @var int Counter for batch operations */ + public $successCount = 0; + + /** @var int Counter for batch operations */ + public $failCount = 0; + + /** + * Factory function for fatal errors + * + * @param string|MessageSpecifier $message Message key or object + * @return static + */ + public static function newFatal( $message /*, parameters...*/ ) { + $params = func_get_args(); + $result = new static(); + call_user_func_array( [ &$result, 'fatal' ], $params ); + return $result; + } + + /** + * Factory function for good results + * + * @param mixed $value + * @return static + */ + public static function newGood( $value = null ) { + $result = new static(); + $result->value = $value; + return $result; + } + + /** + * Splits this StatusValue object into two new StatusValue objects, one which contains only + * the error messages, and one that contains the warnings, only. The returned array is + * defined as: + * [ + * 0 => object(StatusValue) # the StatusValue with error messages, only + * 1 => object(StatusValue) # The StatusValue with warning messages, only + * ] + * + * @return StatusValue[] + */ + public function splitByErrorType() { + $errorsOnlyStatusValue = clone $this; + $warningsOnlyStatusValue = clone $this; + $warningsOnlyStatusValue->ok = true; + + $errorsOnlyStatusValue->errors = $warningsOnlyStatusValue->errors = []; + foreach ( $this->errors as $item ) { + if ( $item['type'] === 'warning' ) { + $warningsOnlyStatusValue->errors[] = $item; + } else { + $errorsOnlyStatusValue->errors[] = $item; + } + }; + + return [ $errorsOnlyStatusValue, $warningsOnlyStatusValue ]; + } + + /** + * Returns whether the operation completed and didn't have any error or + * warnings + * + * @return bool + */ + public function isGood() { + return $this->ok && !$this->errors; + } + + /** + * Returns whether the operation completed + * + * @return bool + */ + public function isOK() { + return $this->ok; + } + + /** + * @return mixed + */ + public function getValue() { + return $this->value; + } + + /** + * Get the list of errors + * + * Each error is a (message:string or MessageSpecifier,params:array) map + * + * @return array[] + */ + public function getErrors() { + return $this->errors; + } + + /** + * Change operation status + * + * @param bool $ok + */ + public function setOK( $ok ) { + $this->ok = $ok; + } + + /** + * Change operation result + * + * @param bool $ok Whether the operation completed + * @param mixed $value + */ + public function setResult( $ok, $value = null ) { + $this->ok = (bool)$ok; + $this->value = $value; + } + + /** + * Add a new warning + * + * @param string|MessageSpecifier $message Message key or object + */ + public function warning( $message /*, parameters... */ ) { + $this->errors[] = [ + 'type' => 'warning', + 'message' => $message, + 'params' => array_slice( func_get_args(), 1 ) + ]; + } + + /** + * Add an error, do not set fatal flag + * This can be used for non-fatal errors + * + * @param string|MessageSpecifier $message Message key or object + */ + public function error( $message /*, parameters... */ ) { + $this->errors[] = [ + 'type' => 'error', + 'message' => $message, + 'params' => array_slice( func_get_args(), 1 ) + ]; + } + + /** + * Add an error and set OK to false, indicating that the operation + * as a whole was fatal + * + * @param string|MessageSpecifier $message Message key or object + */ + public function fatal( $message /*, parameters... */ ) { + $this->errors[] = [ + 'type' => 'error', + 'message' => $message, + 'params' => array_slice( func_get_args(), 1 ) + ]; + $this->ok = false; + } + + /** + * Merge another status object into this one + * + * @param StatusValue $other Other StatusValue object + * @param bool $overwriteValue Whether to override the "value" member + */ + public function merge( $other, $overwriteValue = false ) { + $this->errors = array_merge( $this->errors, $other->errors ); + $this->ok = $this->ok && $other->ok; + if ( $overwriteValue ) { + $this->value = $other->value; + } + $this->successCount += $other->successCount; + $this->failCount += $other->failCount; + } + + /** + * Returns a list of status messages of the given type + * + * Each entry is a map of: + * - message: string message key or MessageSpecifier + * - params: array list of parameters + * + * @param string $type + * @return array[] + */ + public function getErrorsByType( $type ) { + $result = []; + foreach ( $this->errors as $error ) { + if ( $error['type'] === $type ) { + $result[] = $error; + } + } + + return $result; + } + + /** + * Returns true if the specified message is present as a warning or error + * + * @param string|MessageSpecifier $message Message key or object to search for + * + * @return bool + */ + public function hasMessage( $message ) { + if ( $message instanceof MessageSpecifier ) { + $message = $message->getKey(); + } + foreach ( $this->errors as $error ) { + if ( $error['message'] instanceof MessageSpecifier + && $error['message']->getKey() === $message + ) { + return true; + } elseif ( $error['message'] === $message ) { + return true; + } + } + + return false; + } + + /** + * If the specified source message exists, replace it with the specified + * destination message, but keep the same parameters as in the original error. + * + * Note, due to the lack of tools for comparing IStatusMessage objects, this + * function will not work when using such an object as the search parameter. + * + * @param MessageSpecifier|string $source Message key or object to search for + * @param MessageSpecifier|string $dest Replacement message key or object + * @return bool Return true if the replacement was done, false otherwise. + */ + public function replaceMessage( $source, $dest ) { + $replaced = false; + + foreach ( $this->errors as $index => $error ) { + if ( $error['message'] === $source ) { + $this->errors[$index]['message'] = $dest; + $replaced = true; + } + } + + return $replaced; + } + + /** + * @return string + */ + public function __toString() { + $status = $this->isOK() ? "OK" : "Error"; + if ( count( $this->errors ) ) { + $errorcount = "collected " . ( count( $this->errors ) ) . " error(s) on the way"; + } else { + $errorcount = "no errors detected"; + } + if ( isset( $this->value ) ) { + $valstr = gettype( $this->value ) . " value set"; + if ( is_object( $this->value ) ) { + $valstr .= "\"" . get_class( $this->value ) . "\" instance"; + } + } else { + $valstr = "no value set"; + } + $out = sprintf( "<%s, %s, %s>", + $status, + $errorcount, + $valstr + ); + if ( count( $this->errors ) > 0 ) { + $hdr = sprintf( "+-%'-4s-+-%'-25s-+-%'-40s-+\n", "", "", "" ); + $i = 1; + $out .= "\n"; + $out .= $hdr; + foreach ( $this->errors as $error ) { + if ( $error['message'] instanceof MessageSpecifier ) { + $key = $error['message']->getKey(); + $params = $error['message']->getParams(); + } elseif ( $error['params'] ) { + $key = $error['message']; + $params = $error['params']; + } else { + $key = $error['message']; + $params = []; + } + + $out .= sprintf( "| %4d | %-25.25s | %-40.40s |\n", + $i, + $key, + implode( " ", $params ) + ); + $i += 1; + } + $out .= $hdr; + } + + return $out; + } +}