[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Generic operation result. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 * http://www.gnu.org/copyleft/gpl.html 19 * 20 * @file 21 */ 22 23 /** 24 * Generic operation result class 25 * Has warning/error list, boolean status and arbitrary value 26 * 27 * "Good" means the operation was completed with no warnings or errors. 28 * 29 * "OK" means the operation was partially or wholly completed. 30 * 31 * An operation which is not OK should have errors so that the user can be 32 * informed as to what went wrong. Calling the fatal() function sets an error 33 * message and simultaneously switches off the OK flag. 34 * 35 * The recommended pattern for Status objects is to return a Status object 36 * unconditionally, i.e. both on success and on failure -- so that the 37 * developer of the calling code is reminded that the function can fail, and 38 * so that a lack of error-handling will be explicit. 39 */ 40 class Status { 41 /** @var bool */ 42 public $ok = true; 43 44 /** @var mixed */ 45 public $value; 46 47 /** Counters for batch operations */ 48 /** @var int */ 49 public $successCount = 0; 50 51 /** @var int */ 52 public $failCount = 0; 53 54 /** Array to indicate which items of the batch operations were successful */ 55 /** @var array */ 56 public $success = array(); 57 58 /** @var array */ 59 public $errors = array(); 60 61 /** @var callable */ 62 public $cleanCallback = false; 63 64 /** 65 * Factory function for fatal errors 66 * 67 * @param string|Message $message Message name or object 68 * @return Status 69 */ 70 static function newFatal( $message /*, parameters...*/ ) { 71 $params = func_get_args(); 72 $result = new self; 73 call_user_func_array( array( &$result, 'error' ), $params ); 74 $result->ok = false; 75 return $result; 76 } 77 78 /** 79 * Factory function for good results 80 * 81 * @param mixed $value 82 * @return Status 83 */ 84 static function newGood( $value = null ) { 85 $result = new self; 86 $result->value = $value; 87 return $result; 88 } 89 90 /** 91 * Change operation result 92 * 93 * @param bool $ok Whether the operation completed 94 * @param mixed $value 95 */ 96 public function setResult( $ok, $value = null ) { 97 $this->ok = $ok; 98 $this->value = $value; 99 } 100 101 /** 102 * Returns whether the operation completed and didn't have any error or 103 * warnings 104 * 105 * @return bool 106 */ 107 public function isGood() { 108 return $this->ok && !$this->errors; 109 } 110 111 /** 112 * Returns whether the operation completed 113 * 114 * @return bool 115 */ 116 public function isOK() { 117 return $this->ok; 118 } 119 120 /** 121 * Add a new warning 122 * 123 * @param string|Message $message Message name or object 124 */ 125 public function warning( $message /*, parameters... */ ) { 126 $params = array_slice( func_get_args(), 1 ); 127 $this->errors[] = array( 128 'type' => 'warning', 129 'message' => $message, 130 'params' => $params ); 131 } 132 133 /** 134 * Add an error, do not set fatal flag 135 * This can be used for non-fatal errors 136 * 137 * @param string|Message $message Message name or object 138 */ 139 public function error( $message /*, parameters... */ ) { 140 $params = array_slice( func_get_args(), 1 ); 141 $this->errors[] = array( 142 'type' => 'error', 143 'message' => $message, 144 'params' => $params ); 145 } 146 147 /** 148 * Add an error and set OK to false, indicating that the operation 149 * as a whole was fatal 150 * 151 * @param string|Message $message Message name or object 152 */ 153 public function fatal( $message /*, parameters... */ ) { 154 $params = array_slice( func_get_args(), 1 ); 155 $this->errors[] = array( 156 'type' => 'error', 157 'message' => $message, 158 'params' => $params ); 159 $this->ok = false; 160 } 161 162 /** 163 * Sanitize the callback parameter on wakeup, to avoid arbitrary execution. 164 */ 165 public function __wakeup() { 166 $this->cleanCallback = false; 167 } 168 169 /** 170 * @param array $params 171 * @return array 172 */ 173 protected function cleanParams( $params ) { 174 if ( !$this->cleanCallback ) { 175 return $params; 176 } 177 $cleanParams = array(); 178 foreach ( $params as $i => $param ) { 179 $cleanParams[$i] = call_user_func( $this->cleanCallback, $param ); 180 } 181 return $cleanParams; 182 } 183 184 /** 185 * Get the error list as a wikitext formatted list 186 * 187 * @param string $shortContext A short enclosing context message name, to 188 * be used when there is a single error 189 * @param string $longContext A long enclosing context message name, for a list 190 * @return string 191 */ 192 public function getWikiText( $shortContext = false, $longContext = false ) { 193 if ( count( $this->errors ) == 0 ) { 194 if ( $this->ok ) { 195 $this->fatal( 'internalerror_info', 196 __METHOD__ . " called for a good result, this is incorrect\n" ); 197 } else { 198 $this->fatal( 'internalerror_info', 199 __METHOD__ . ": Invalid result object: no error text but not OK\n" ); 200 } 201 } 202 if ( count( $this->errors ) == 1 ) { 203 $s = $this->getErrorMessage( $this->errors[0] )->plain(); 204 if ( $shortContext ) { 205 $s = wfMessage( $shortContext, $s )->plain(); 206 } elseif ( $longContext ) { 207 $s = wfMessage( $longContext, "* $s\n" )->plain(); 208 } 209 } else { 210 $errors = $this->getErrorMessageArray( $this->errors ); 211 foreach ( $errors as &$error ) { 212 $error = $error->plain(); 213 } 214 $s = '* ' . implode( "\n* ", $errors ) . "\n"; 215 if ( $longContext ) { 216 $s = wfMessage( $longContext, $s )->plain(); 217 } elseif ( $shortContext ) { 218 $s = wfMessage( $shortContext, "\n$s\n" )->plain(); 219 } 220 } 221 return $s; 222 } 223 224 /** 225 * Get the error list as a Message object 226 * 227 * @param string|string[] $shortContext A short enclosing context message name (or an array of 228 * message names), to be used when there is a single error. 229 * @param string|string[] $longContext A long enclosing context message name (or an array of 230 * message names), for a list. 231 * 232 * @return Message 233 */ 234 public function getMessage( $shortContext = false, $longContext = false ) { 235 if ( count( $this->errors ) == 0 ) { 236 if ( $this->ok ) { 237 $this->fatal( 'internalerror_info', 238 __METHOD__ . " called for a good result, this is incorrect\n" ); 239 } else { 240 $this->fatal( 'internalerror_info', 241 __METHOD__ . ": Invalid result object: no error text but not OK\n" ); 242 } 243 } 244 if ( count( $this->errors ) == 1 ) { 245 $s = $this->getErrorMessage( $this->errors[0] ); 246 if ( $shortContext ) { 247 $s = wfMessage( $shortContext, $s ); 248 } elseif ( $longContext ) { 249 $wrapper = new RawMessage( "* \$1\n" ); 250 $wrapper->params( $s )->parse(); 251 $s = wfMessage( $longContext, $wrapper ); 252 } 253 } else { 254 $msgs = $this->getErrorMessageArray( $this->errors ); 255 $msgCount = count( $msgs ); 256 257 if ( $shortContext ) { 258 $msgCount++; 259 } 260 261 $s = new RawMessage( '* $' . implode( "\n* \$", range( 1, $msgCount ) ) ); 262 $s->params( $msgs )->parse(); 263 264 if ( $longContext ) { 265 $s = wfMessage( $longContext, $s ); 266 } elseif ( $shortContext ) { 267 $wrapper = new RawMessage( "\n\$1\n", $s ); 268 $wrapper->parse(); 269 $s = wfMessage( $shortContext, $wrapper ); 270 } 271 } 272 273 return $s; 274 } 275 276 /** 277 * Return the message for a single error. 278 * @param mixed $error With an array & two values keyed by 279 * 'message' and 'params', use those keys-value pairs. 280 * Otherwise, if its an array, just use the first value as the 281 * message and the remaining items as the params. 282 * 283 * @return string 284 */ 285 protected function getErrorMessage( $error ) { 286 if ( is_array( $error ) ) { 287 if ( isset( $error['message'] ) && $error['message'] instanceof Message ) { 288 $msg = $error['message']; 289 } elseif ( isset( $error['message'] ) && isset( $error['params'] ) ) { 290 $msg = wfMessage( $error['message'], 291 array_map( 'wfEscapeWikiText', $this->cleanParams( $error['params'] ) ) ); 292 } else { 293 $msgName = array_shift( $error ); 294 $msg = wfMessage( $msgName, 295 array_map( 'wfEscapeWikiText', $this->cleanParams( $error ) ) ); 296 } 297 } else { 298 $msg = wfMessage( $error ); 299 } 300 return $msg; 301 } 302 303 /** 304 * Get the error message as HTML. This is done by parsing the wikitext error 305 * message. 306 * @param string $shortContext A short enclosing context message name, to 307 * be used when there is a single error 308 * @param string $longContext A long enclosing context message name, for a list 309 * @return string 310 */ 311 public function getHTML( $shortContext = false, $longContext = false ) { 312 $text = $this->getWikiText( $shortContext, $longContext ); 313 $out = MessageCache::singleton()->parse( $text, null, true, true ); 314 return $out instanceof ParserOutput ? $out->getText() : $out; 315 } 316 317 /** 318 * Return an array with the wikitext for each item in the array. 319 * @param array $errors 320 * @return array 321 */ 322 protected function getErrorMessageArray( $errors ) { 323 return array_map( array( $this, 'getErrorMessage' ), $errors ); 324 } 325 326 /** 327 * Merge another status object into this one 328 * 329 * @param Status $other Other Status object 330 * @param bool $overwriteValue Whether to override the "value" member 331 */ 332 public function merge( $other, $overwriteValue = false ) { 333 $this->errors = array_merge( $this->errors, $other->errors ); 334 $this->ok = $this->ok && $other->ok; 335 if ( $overwriteValue ) { 336 $this->value = $other->value; 337 } 338 $this->successCount += $other->successCount; 339 $this->failCount += $other->failCount; 340 } 341 342 /** 343 * Get the list of errors (but not warnings) 344 * 345 * @return array A list in which each entry is an array with a message key as its first element. 346 * The remaining array elements are the message parameters. 347 */ 348 public function getErrorsArray() { 349 return $this->getStatusArray( "error" ); 350 } 351 352 /** 353 * Get the list of warnings (but not errors) 354 * 355 * @return array A list in which each entry is an array with a message key as its first element. 356 * The remaining array elements are the message parameters. 357 */ 358 public function getWarningsArray() { 359 return $this->getStatusArray( "warning" ); 360 } 361 362 /** 363 * Returns a list of status messages of the given type 364 * @param string $type 365 * @return array 366 */ 367 protected function getStatusArray( $type ) { 368 $result = array(); 369 foreach ( $this->errors as $error ) { 370 if ( $error['type'] === $type ) { 371 if ( $error['message'] instanceof Message ) { 372 $result[] = array_merge( 373 array( $error['message']->getKey() ), 374 $error['message']->getParams() 375 ); 376 } elseif ( $error['params'] ) { 377 $result[] = array_merge( array( $error['message'] ), $error['params'] ); 378 } else { 379 $result[] = array( $error['message'] ); 380 } 381 } 382 } 383 384 return $result; 385 } 386 387 /** 388 * Returns a list of status messages of the given type, with message and 389 * params left untouched, like a sane version of getStatusArray 390 * 391 * @param string $type 392 * 393 * @return array 394 */ 395 public function getErrorsByType( $type ) { 396 $result = array(); 397 foreach ( $this->errors as $error ) { 398 if ( $error['type'] === $type ) { 399 $result[] = $error; 400 } 401 } 402 return $result; 403 } 404 405 /** 406 * Returns true if the specified message is present as a warning or error 407 * 408 * @param string|Message $message Message key or object to search for 409 * 410 * @return bool 411 */ 412 public function hasMessage( $message ) { 413 if ( $message instanceof Message ) { 414 $message = $message->getKey(); 415 } 416 foreach ( $this->errors as $error ) { 417 if ( $error['message'] instanceof Message 418 && $error['message']->getKey() === $message 419 ) { 420 return true; 421 } elseif ( $error['message'] === $message ) { 422 return true; 423 } 424 } 425 return false; 426 } 427 428 /** 429 * If the specified source message exists, replace it with the specified 430 * destination message, but keep the same parameters as in the original error. 431 * 432 * Note, due to the lack of tools for comparing Message objects, this 433 * function will not work when using a Message object as the search parameter. 434 * 435 * @param Message|string $source Message key or object to search for 436 * @param Message|string $dest Replacement message key or object 437 * @return bool Return true if the replacement was done, false otherwise. 438 */ 439 public function replaceMessage( $source, $dest ) { 440 $replaced = false; 441 foreach ( $this->errors as $index => $error ) { 442 if ( $error['message'] === $source ) { 443 $this->errors[$index]['message'] = $dest; 444 $replaced = true; 445 } 446 } 447 return $replaced; 448 } 449 450 /** 451 * @return mixed 452 */ 453 public function getValue() { 454 return $this->value; 455 } 456 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |