Merge "DatabaseMssql: Don't duplicate body of makeList()"
[mediawiki.git] / includes / libs / StatusValue.php
blob3c2dd4093da75703ace8bbf854a2f2b223205269
1 <?php
2 /**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
18 * @file
21 /**
22 * Generic operation result class
23 * Has warning/error list, boolean status and arbitrary value
25 * "Good" means the operation was completed with no warnings or errors.
27 * "OK" means the operation was partially or wholly completed.
29 * An operation which is not OK should have errors so that the user can be
30 * informed as to what went wrong. Calling the fatal() function sets an error
31 * message and simultaneously switches off the OK flag.
33 * The recommended pattern for Status objects is to return a StatusValue
34 * unconditionally, i.e. both on success and on failure -- so that the
35 * developer of the calling code is reminded that the function can fail, and
36 * so that a lack of error-handling will be explicit.
38 * The use of Message objects should be avoided when serializability is needed.
40 * @since 1.25
42 class StatusValue {
43 /** @var bool */
44 protected $ok = true;
45 /** @var array */
46 protected $errors = array();
48 /** @var mixed */
49 public $value;
50 /** @var array Map of (key => bool) to indicate success of each part of batch operations */
51 public $success = array();
52 /** @var int Counter for batch operations */
53 public $successCount = 0;
54 /** @var int Counter for batch operations */
55 public $failCount = 0;
57 /**
58 * Factory function for fatal errors
60 * @param string|MessageSpecifier $message Message key or object
61 * @return Status
63 public static function newFatal( $message /*, parameters...*/ ) {
64 $params = func_get_args();
65 $result = new static();
66 call_user_func_array( array( &$result, 'fatal' ), $params );
67 return $result;
70 /**
71 * Factory function for good results
73 * @param mixed $value
74 * @return Status
76 public static function newGood( $value = null ) {
77 $result = new static();
78 $result->value = $value;
79 return $result;
82 /**
83 * Returns whether the operation completed and didn't have any error or
84 * warnings
86 * @return bool
88 public function isGood() {
89 return $this->ok && !$this->errors;
92 /**
93 * Returns whether the operation completed
95 * @return bool
97 public function isOK() {
98 return $this->ok;
102 * @return mixed
104 public function getValue() {
105 return $this->value;
109 * Get the list of errors
111 * Each error is a (message:string or MessageSpecifier,params:array) map
113 * @return array
115 public function getErrors() {
116 return $this->errors;
120 * Change operation status
122 * @param bool $ok
124 public function setOK( $ok ) {
125 $this->ok = $ok;
129 * Change operation resuklt
131 * @param bool $ok Whether the operation completed
132 * @param mixed $value
134 public function setResult( $ok, $value = null ) {
135 $this->ok = $ok;
136 $this->value = $value;
140 * Add a new warning
142 * @param string|MessageSpecifier $message Message key or object
144 public function warning( $message /*, parameters... */ ) {
145 $this->errors[] = array(
146 'type' => 'warning',
147 'message' => $message,
148 'params' => array_slice( func_get_args(), 1 )
153 * Add an error, do not set fatal flag
154 * This can be used for non-fatal errors
156 * @param string|MessageSpecifier $message Message key or object
158 public function error( $message /*, parameters... */ ) {
159 $this->errors[] = array(
160 'type' => 'error',
161 'message' => $message,
162 'params' => array_slice( func_get_args(), 1 )
167 * Add an error and set OK to false, indicating that the operation
168 * as a whole was fatal
170 * @param string|MessageSpecifier $message Message key or object
172 public function fatal( $message /*, parameters... */ ) {
173 $this->errors[] = array(
174 'type' => 'error',
175 'message' => $message,
176 'params' => array_slice( func_get_args(), 1 )
178 $this->ok = false;
182 * Merge another status object into this one
184 * @param Status $other Other Status object
185 * @param bool $overwriteValue Whether to override the "value" member
187 public function merge( $other, $overwriteValue = false ) {
188 $this->errors = array_merge( $this->errors, $other->errors );
189 $this->ok = $this->ok && $other->ok;
190 if ( $overwriteValue ) {
191 $this->value = $other->value;
193 $this->successCount += $other->successCount;
194 $this->failCount += $other->failCount;
198 * Returns a list of status messages of the given type
200 * Each entry is a map of (message:string or MessageSpecifier,params:array))
202 * @param string $type
203 * @return array
205 public function getErrorsByType( $type ) {
206 $result = array();
207 foreach ( $this->errors as $error ) {
208 if ( $error['type'] === $type ) {
209 $result[] = $error;
213 return $result;
217 * Returns true if the specified message is present as a warning or error
219 * @param string|MessageSpecifier $message Message key or object to search for
221 * @return bool
223 public function hasMessage( $message ) {
224 if ( $message instanceof MessageSpecifier ) {
225 $message = $message->getKey();
227 foreach ( $this->errors as $error ) {
228 if ( $error['message'] instanceof MessageSpecifier
229 && $error['message']->getKey() === $message
231 return true;
232 } elseif ( $error['message'] === $message ) {
233 return true;
237 return false;
241 * If the specified source message exists, replace it with the specified
242 * destination message, but keep the same parameters as in the original error.
244 * Note, due to the lack of tools for comparing IStatusMessage objects, this
245 * function will not work when using such an object as the search parameter.
247 * @param IStatusMessage|string $source Message key or object to search for
248 * @param IStatusMessage|string $dest Replacement message key or object
249 * @return bool Return true if the replacement was done, false otherwise.
251 public function replaceMessage( $source, $dest ) {
252 $replaced = false;
254 foreach ( $this->errors as $index => $error ) {
255 if ( $error['message'] === $source ) {
256 $this->errors[$index]['message'] = $dest;
257 $replaced = true;
261 return $replaced;
265 * @return string
267 public function __toString() {
268 $status = $this->isOK() ? "OK" : "Error";
269 if ( count( $this->errors ) ) {
270 $errorcount = "collected " . ( count( $this->errors ) ) . " error(s) on the way";
271 } else {
272 $errorcount = "no errors detected";
274 if ( isset( $this->value ) ) {
275 $valstr = gettype( $this->value ) . " value set";
276 if ( is_object( $this->value ) ) {
277 $valstr .= "\"" . get_class( $this->value ) . "\" instance";
279 } else {
280 $valstr = "no value set";
282 $out = sprintf( "<%s, %s, %s>",
283 $status,
284 $errorcount,
285 $valstr
287 if ( count( $this->errors ) > 0 ) {
288 $hdr = sprintf( "+-%'-4s-+-%'-25s-+-%'-40s-+\n", "", "", "" );
289 $i = 1;
290 $out .= "\n";
291 $out .= $hdr;
292 foreach ( $this->errors as $error ) {
293 if ( $error['message'] instanceof MessageSpecifier ) {
294 $key = $error['message']->getKey();
295 $params = $error['message']->getParams();
296 } elseif ( $error['params'] ) {
297 $key = $error['message'];
298 $params = $error['params'];
299 } else {
300 $key = $error['message'];
301 $params = array();
304 $out .= sprintf( "| %4d | %-25.25s | %-40.40s |\n",
306 $key,
307 implode( " ", $params )
309 $i += 1;
311 $out .= $hdr;
314 return $out;