[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/lib/zend/Zend/Rest/ -> Server.php (source)

   1  <?php
   2  /**
   3   * Zend Framework
   4   *
   5   * LICENSE
   6   *
   7   * This source file is subject to the new BSD license that is bundled
   8   * with this package in the file LICENSE.txt.
   9   * It is also available through the world-wide-web at this URL:
  10   * http://framework.zend.com/license/new-bsd
  11   * If you did not receive a copy of the license and are unable to
  12   * obtain it through the world-wide-web, please send an email
  13   * to [email protected] so we can send you a copy immediately.
  14   *
  15   * @category   Zend
  16   * @package    Zend_Rest
  17   * @subpackage Server
  18   * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  19   * @license    http://framework.zend.com/license/new-bsd     New BSD License
  20   * @version    $Id$
  21   */
  22  
  23  /**
  24   * @see Zend_Server_Interface
  25   */
  26  require_once 'Zend/Server/Interface.php';
  27  
  28  /**
  29   * @see Zend_Server_Reflection
  30   */
  31  require_once 'Zend/Server/Reflection.php';
  32  
  33  /**
  34   * @see Zend_Server_Abstract
  35   */
  36  require_once 'Zend/Server/Abstract.php';
  37  
  38  /**
  39   * @category   Zend
  40   * @package    Zend_Rest
  41   * @subpackage Server
  42   * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  43   * @license    http://framework.zend.com/license/new-bsd     New BSD License
  44   */
  45  class Zend_Rest_Server implements Zend_Server_Interface
  46  {
  47      /**
  48       * Class Constructor Args
  49       * @var array
  50       */
  51      protected $_args = array();
  52  
  53      /**
  54       * @var string Encoding
  55       */
  56      protected $_encoding = 'UTF-8';
  57  
  58      /**
  59       * @var array An array of Zend_Server_Reflect_Method
  60       */
  61      protected $_functions = array();
  62  
  63      /**
  64       * @var array Array of headers to send
  65       */
  66      protected $_headers = array();
  67  
  68      /**
  69       * @var array PHP's Magic Methods, these are ignored
  70       */
  71      protected static $magicMethods = array(
  72          '__construct',
  73          '__destruct',
  74          '__get',
  75          '__set',
  76          '__call',
  77          '__sleep',
  78          '__wakeup',
  79          '__isset',
  80          '__unset',
  81          '__tostring',
  82          '__clone',
  83          '__set_state',
  84      );
  85  
  86      /**
  87       * @var string Current Method
  88       */
  89      protected $_method;
  90  
  91      /**
  92       * @var Zend_Server_Reflection
  93       */
  94      protected $_reflection = null;
  95  
  96      /**
  97       * Whether or not {@link handle()} should send output or return the response.
  98       * @var boolean Defaults to false
  99       */
 100      protected $_returnResponse = false;
 101  
 102      /**
 103       * Constructor
 104       */
 105      public function __construct()
 106      {
 107          set_exception_handler(array($this, "fault"));
 108          $this->_reflection = new Zend_Server_Reflection();
 109      }
 110  
 111      /**
 112       * Set XML encoding
 113       *
 114       * @param  string $encoding
 115       * @return Zend_Rest_Server
 116       */
 117      public function setEncoding($encoding)
 118      {
 119          $this->_encoding = (string) $encoding;
 120          return $this;
 121      }
 122  
 123      /**
 124       * Get XML encoding
 125       *
 126       * @return string
 127       */
 128      public function getEncoding()
 129      {
 130          return $this->_encoding;
 131      }
 132  
 133      /**
 134       * Lowercase a string
 135       *
 136       * Lowercase's a string by reference
 137       *
 138       * @param string $value
 139       * @param string $key
 140       * @return string Lower cased string
 141       */
 142      public static function lowerCase(&$value, &$key)
 143      {
 144          return $value = strtolower($value);
 145      }
 146  
 147      /**
 148       * Whether or not to return a response
 149       *
 150       * If called without arguments, returns the value of the flag. If called
 151       * with an argument, sets the flag.
 152       *
 153       * When 'return response' is true, {@link handle()} will not send output,
 154       * but will instead return the response from the dispatched function/method.
 155       *
 156       * @param boolean $flag
 157       * @return boolean|Zend_Rest_Server Returns Zend_Rest_Server when used to set the flag; returns boolean flag value otherwise.
 158       */
 159      public function returnResponse($flag = null)
 160      {
 161          if (null === $flag) {
 162              return $this->_returnResponse;
 163          }
 164  
 165          $this->_returnResponse = ($flag) ? true : false;
 166          return $this;
 167      }
 168  
 169      /**
 170       * Implement Zend_Server_Interface::handle()
 171       *
 172       * @param  array $request
 173       * @throws Zend_Rest_Server_Exception
 174       * @return string|void
 175       */
 176      public function handle($request = false)
 177      {
 178          $this->_headers = array('Content-Type: text/xml');
 179          if (!$request) {
 180              $request = $_REQUEST;
 181          }
 182          if (isset($request['method'])) {
 183              $this->_method = $request['method'];
 184              if (isset($this->_functions[$this->_method])) {
 185                  if ($this->_functions[$this->_method] instanceof Zend_Server_Reflection_Function || $this->_functions[$this->_method] instanceof Zend_Server_Reflection_Method && $this->_functions[$this->_method]->isPublic()) {
 186                      $request_keys = array_keys($request);
 187                      array_walk($request_keys, array(__CLASS__, "lowerCase"));
 188                      $request = array_combine($request_keys, $request);
 189  
 190                      $func_args = $this->_functions[$this->_method]->getParameters();
 191  
 192                      $calling_args = array();
 193                      $missing_args = array();
 194                      foreach ($func_args as $arg) {
 195                          if (isset($request[strtolower($arg->getName())])) {
 196                              $calling_args[] = $request[strtolower($arg->getName())];
 197                          } elseif ($arg->isOptional()) {
 198                              $calling_args[] = $arg->getDefaultValue();
 199                          } else {
 200                              $missing_args[] = $arg->getName();
 201                          }
 202                      }
 203  
 204                      foreach ($request as $key => $value) {
 205                          if (substr($key, 0, 3) == 'arg') {
 206                              $key = str_replace('arg', '', $key);
 207                              $calling_args[$key] = $value;
 208                              if (($index = array_search($key, $missing_args)) !== false) {
 209                                  unset($missing_args[$index]);
 210                              }
 211                          }
 212                      }
 213  
 214                      // Sort arguments by key -- @see ZF-2279
 215                      ksort($calling_args);
 216  
 217                      $result = false;
 218                      if (count($calling_args) < count($func_args)) {
 219                          require_once 'Zend/Rest/Server/Exception.php';
 220                          $result = $this->fault(new Zend_Rest_Server_Exception('Invalid Method Call to ' . $this->_method . '. Missing argument(s): ' . implode(', ', $missing_args) . '.'), 400);
 221                      }
 222  
 223                      if (!$result && $this->_functions[$this->_method] instanceof Zend_Server_Reflection_Method) {
 224                          // Get class
 225                          $class = $this->_functions[$this->_method]->getDeclaringClass()->getName();
 226  
 227                          if ($this->_functions[$this->_method]->isStatic()) {
 228                              // for some reason, invokeArgs() does not work the same as
 229                              // invoke(), and expects the first argument to be an object.
 230                              // So, using a callback if the method is static.
 231                              $result = $this->_callStaticMethod($class, $calling_args);
 232                          } else {
 233                              // Object method
 234                              $result = $this->_callObjectMethod($class, $calling_args);
 235                          }
 236                      } elseif (!$result) {
 237                          try {
 238                              $result = call_user_func_array($this->_functions[$this->_method]->getName(), $calling_args); //$this->_functions[$this->_method]->invokeArgs($calling_args);
 239                          } catch (Exception $e) {
 240                              $result = $this->fault($e);
 241                          }
 242                      }
 243                  } else {
 244                      require_once "Zend/Rest/Server/Exception.php";
 245                      $result = $this->fault(
 246                          new Zend_Rest_Server_Exception("Unknown Method '$this->_method'."),
 247                          404
 248                      );
 249                  }
 250              } else {
 251                  require_once "Zend/Rest/Server/Exception.php";
 252                  $result = $this->fault(
 253                      new Zend_Rest_Server_Exception("Unknown Method '$this->_method'."),
 254                      404
 255                  );
 256              }
 257          } else {
 258              require_once "Zend/Rest/Server/Exception.php";
 259              $result = $this->fault(
 260                  new Zend_Rest_Server_Exception("No Method Specified."),
 261                  404
 262              );
 263          }
 264  
 265          if ($result instanceof SimpleXMLElement) {
 266              $response = $result->asXML();
 267          } elseif ($result instanceof DOMDocument) {
 268              $response = $result->saveXML();
 269          } elseif ($result instanceof DOMNode) {
 270              $response = $result->ownerDocument->saveXML($result);
 271          } elseif (is_array($result) || is_object($result)) {
 272              $response = $this->_handleStruct($result);
 273          } else {
 274              $response = $this->_handleScalar($result);
 275          }
 276  
 277          if (!$this->returnResponse()) {
 278              if (!headers_sent()) {
 279                  foreach ($this->_headers as $header) {
 280                      header($header);
 281                  }
 282              }
 283  
 284              echo $response;
 285              return;
 286          }
 287  
 288          return $response;
 289       }
 290  
 291      /**
 292       * Implement Zend_Server_Interface::setClass()
 293       *
 294       * @param string $classname Class name
 295       * @param string $namespace Class namespace (unused)
 296       * @param array $argv An array of Constructor Arguments
 297       */
 298      public function setClass($classname, $namespace = '', $argv = array())
 299      {
 300          $this->_args = $argv;
 301          foreach ($this->_reflection->reflectClass($classname, $argv)->getMethods() as $method) {
 302              $this->_functions[$method->getName()] = $method;
 303          }
 304      }
 305  
 306      /**
 307       * Handle an array or object result
 308       *
 309       * @param array|object $struct Result Value
 310       * @return string XML Response
 311       */
 312      protected function _handleStruct($struct)
 313      {
 314          $function = $this->_functions[$this->_method];
 315          if ($function instanceof Zend_Server_Reflection_Method) {
 316              $class = $function->getDeclaringClass()->getName();
 317          } else {
 318              $class = false;
 319          }
 320  
 321          $method = $function->getName();
 322  
 323          $dom    = new DOMDocument('1.0', $this->getEncoding());
 324          if ($class) {
 325              $root   = $dom->createElement($class);
 326              $method = $dom->createElement($method);
 327              $root->appendChild($method);
 328          } else {
 329              $root   = $dom->createElement($method);
 330              $method = $root;
 331          }
 332          $root->setAttribute('generator', 'zend');
 333          $root->setAttribute('version', '1.0');
 334          $dom->appendChild($root);
 335  
 336          $this->_structValue($struct, $dom, $method);
 337  
 338          $struct = (array) $struct;
 339          if (!isset($struct['status'])) {
 340              $status = $dom->createElement('status', 'success');
 341              $method->appendChild($status);
 342          }
 343  
 344          return $dom->saveXML();
 345      }
 346  
 347      /**
 348       * Recursively iterate through a struct
 349       *
 350       * Recursively iterates through an associative array or object's properties
 351       * to build XML response.
 352       *
 353       * @param mixed $struct
 354       * @param DOMDocument $dom
 355       * @param DOMElement $parent
 356       * @return void
 357       */
 358      protected function _structValue($struct, DOMDocument $dom, DOMElement $parent)
 359      {
 360          $struct = (array) $struct;
 361  
 362          foreach ($struct as $key => $value) {
 363              if ($value === false) {
 364                  $value = 0;
 365              } elseif ($value === true) {
 366                  $value = 1;
 367              }
 368  
 369              if (ctype_digit((string) $key)) {
 370                  $key = 'key_' . $key;
 371              }
 372  
 373              if (is_array($value) || is_object($value)) {
 374                  $element = $dom->createElement($key);
 375                  $this->_structValue($value, $dom, $element);
 376              } else {
 377                  $element = $dom->createElement($key);
 378                  $element->appendChild($dom->createTextNode($value));
 379              }
 380  
 381              $parent->appendChild($element);
 382          }
 383      }
 384  
 385      /**
 386       * Handle a single value
 387       *
 388       * @param string|int|boolean $value Result value
 389       * @return string XML Response
 390       */
 391      protected function _handleScalar($value)
 392      {
 393          $function = $this->_functions[$this->_method];
 394          if ($function instanceof Zend_Server_Reflection_Method) {
 395              $class = $function->getDeclaringClass()->getName();
 396          } else {
 397              $class = false;
 398          }
 399  
 400          $method = $function->getName();
 401  
 402          $dom = new DOMDocument('1.0', $this->getEncoding());
 403          if ($class) {
 404              $xml = $dom->createElement($class);
 405              $methodNode = $dom->createElement($method);
 406              $xml->appendChild($methodNode);
 407          } else {
 408              $xml = $dom->createElement($method);
 409              $methodNode = $xml;
 410          }
 411          $xml->setAttribute('generator', 'zend');
 412          $xml->setAttribute('version', '1.0');
 413          $dom->appendChild($xml);
 414  
 415          if ($value === false) {
 416              $value = 0;
 417          } elseif ($value === true) {
 418              $value = 1;
 419          }
 420  
 421          if (isset($value)) {
 422              $element = $dom->createElement('response');
 423              $element->appendChild($dom->createTextNode($value));
 424              $methodNode->appendChild($element);
 425          } else {
 426              $methodNode->appendChild($dom->createElement('response'));
 427          }
 428  
 429          $methodNode->appendChild($dom->createElement('status', 'success'));
 430  
 431          return $dom->saveXML();
 432      }
 433  
 434      /**
 435       * Implement Zend_Server_Interface::fault()
 436       *
 437       * Creates XML error response, returning DOMDocument with response.
 438       *
 439       * @param string|Exception $fault Message
 440       * @param int $code Error Code
 441       * @return DOMDocument
 442       */
 443      public function fault($exception = null, $code = null)
 444      {
 445          if (isset($this->_functions[$this->_method])) {
 446              $function = $this->_functions[$this->_method];
 447          } elseif (isset($this->_method)) {
 448              $function = $this->_method;
 449          } else {
 450              $function = 'rest';
 451          }
 452  
 453          if ($function instanceof Zend_Server_Reflection_Method) {
 454              $class = $function->getDeclaringClass()->getName();
 455          } else {
 456              $class = false;
 457          }
 458  
 459          if ($function instanceof Zend_Server_Reflection_Function_Abstract) {
 460              $method = $function->getName();
 461          } else {
 462              $method = $function;
 463          }
 464  
 465          $dom = new DOMDocument('1.0', $this->getEncoding());
 466          if ($class) {
 467              $xml       = $dom->createElement($class);
 468              $xmlMethod = $dom->createElement($method);
 469              $xml->appendChild($xmlMethod);
 470          } else {
 471              $xml       = $dom->createElement($method);
 472              $xmlMethod = $xml;
 473          }
 474          $xml->setAttribute('generator', 'zend');
 475          $xml->setAttribute('version', '1.0');
 476          $dom->appendChild($xml);
 477  
 478          $xmlResponse = $dom->createElement('response');
 479          $xmlMethod->appendChild($xmlResponse);
 480  
 481          if ($exception instanceof Exception) {
 482              $element = $dom->createElement('message');
 483              $element->appendChild($dom->createTextNode($exception->getMessage()));
 484              $xmlResponse->appendChild($element);
 485              $code = $exception->getCode();
 486          } elseif (($exception !== null) || 'rest' == $function) {
 487              $xmlResponse->appendChild($dom->createElement('message', 'An unknown error occured. Please try again.'));
 488          } else {
 489              $xmlResponse->appendChild($dom->createElement('message', 'Call to ' . $method . ' failed.'));
 490          }
 491  
 492          $xmlMethod->appendChild($xmlResponse);
 493          $xmlMethod->appendChild($dom->createElement('status', 'failed'));
 494  
 495          // Headers to send
 496          if ($code === null || (404 != $code)) {
 497              $this->_headers[] = 'HTTP/1.0 400 Bad Request';
 498          } else {
 499              $this->_headers[] = 'HTTP/1.0 404 File Not Found';
 500          }
 501  
 502          return $dom;
 503      }
 504  
 505      /**
 506       * Retrieve any HTTP extra headers set by the server
 507       *
 508       * @return array
 509       */
 510      public function getHeaders()
 511      {
 512          return $this->_headers;
 513      }
 514  
 515      /**
 516       * Implement Zend_Server_Interface::addFunction()
 517       *
 518       * @param string $function Function Name
 519       * @param string $namespace Function namespace (unused)
 520       */
 521      public function addFunction($function, $namespace = '')
 522      {
 523          if (!is_array($function)) {
 524              $function = (array) $function;
 525          }
 526  
 527          foreach ($function as $func) {
 528              if (is_callable($func) && !in_array($func, self::$magicMethods)) {
 529                  $this->_functions[$func] = $this->_reflection->reflectFunction($func);
 530              } else {
 531                  require_once 'Zend/Rest/Server/Exception.php';
 532                  throw new Zend_Rest_Server_Exception("Invalid Method Added to Service.");
 533              }
 534          }
 535      }
 536  
 537      /**
 538       * Implement Zend_Server_Interface::getFunctions()
 539       *
 540       * @return array An array of Zend_Server_Reflection_Method's
 541       */
 542      public function getFunctions()
 543      {
 544          return $this->_functions;
 545      }
 546  
 547      /**
 548       * Implement Zend_Server_Interface::loadFunctions()
 549       *
 550       * @todo Implement
 551       * @param array $functions
 552       */
 553      public function loadFunctions($functions)
 554      {
 555      }
 556  
 557      /**
 558       * Implement Zend_Server_Interface::setPersistence()
 559       *
 560       * @todo Implement
 561       * @param int $mode
 562       */
 563      public function setPersistence($mode)
 564      {
 565      }
 566  
 567      /**
 568       * Call a static class method and return the result
 569       *
 570       * @param  string $class
 571       * @param  array $args
 572       * @return mixed
 573       */
 574      protected function _callStaticMethod($class, array $args)
 575      {
 576          try {
 577              $result = call_user_func_array(array($class, $this->_functions[$this->_method]->getName()), $args);
 578          } catch (Exception $e) {
 579              $result = $this->fault($e);
 580          }
 581          return $result;
 582      }
 583  
 584      /**
 585       * Call an instance method of an object
 586       *
 587       * @param  string $class
 588       * @param  array $args
 589       * @return mixed
 590       * @throws Zend_Rest_Server_Exception For invalid class name
 591       */
 592      protected function _callObjectMethod($class, array $args)
 593      {
 594          try {
 595              if ($this->_functions[$this->_method]->getDeclaringClass()->getConstructor()) {
 596                  $object = $this->_functions[$this->_method]->getDeclaringClass()->newInstanceArgs($this->_args);
 597              } else {
 598                  $object = $this->_functions[$this->_method]->getDeclaringClass()->newInstance();
 599              }
 600          } catch (Exception $e) {
 601              require_once 'Zend/Rest/Server/Exception.php';
 602              throw new Zend_Rest_Server_Exception('Error instantiating class ' . $class .
 603                                                   ' to invoke method ' . $this->_functions[$this->_method]->getName() .
 604                                                   ' (' . $e->getMessage() . ') ',
 605                                                   500, $e);
 606          }
 607  
 608          try {
 609              $result = $this->_functions[$this->_method]->invokeArgs($object, $args);
 610          } catch (Exception $e) {
 611              $result = $this->fault($e);
 612          }
 613  
 614          return $result;
 615      }
 616  }


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1