[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/includes/ -> Status.php (source)

   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  }


Generated: Fri Nov 28 14:03:12 2014 Cross-referenced by PHPXref 0.7.1