diff -r 000000000000 -r 4eba9c11703f web/Zend/Json/Server.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/Zend/Json/Server.php Mon Dec 13 18:29:26 2010 +0100 @@ -0,0 +1,568 @@ + count($function)))) { + require_once 'Zend/Json/Server/Exception.php'; + throw new Zend_Json_Server_Exception('Unable to attach function; invalid'); + } + + if (!is_callable($function)) { + require_once 'Zend/Json/Server/Exception.php'; + throw new Zend_Json_Server_Exception('Unable to attach function; does not exist'); + } + + $argv = null; + if (2 < func_num_args()) { + $argv = func_get_args(); + $argv = array_slice($argv, 2); + } + + require_once 'Zend/Server/Reflection.php'; + if (is_string($function)) { + $method = Zend_Server_Reflection::reflectFunction($function, $argv, $namespace); + } else { + $class = array_shift($function); + $action = array_shift($function); + $reflection = Zend_Server_Reflection::reflectClass($class, $argv, $namespace); + $methods = $reflection->getMethods(); + $found = false; + foreach ($methods as $method) { + if ($action == $method->getName()) { + $found = true; + break; + } + } + if (!$found) { + $this->fault('Method not found', -32601); + return $this; + } + } + + $definition = $this->_buildSignature($method); + $this->_addMethodServiceMap($definition); + + return $this; + } + + /** + * Register a class with the server + * + * @param string $class + * @param string $namespace Ignored + * @param mixed $argv Ignored + * @return Zend_Json_Server + */ + public function setClass($class, $namespace = '', $argv = null) + { + $argv = null; + if (3 < func_num_args()) { + $argv = func_get_args(); + $argv = array_slice($argv, 3); + } + + require_once 'Zend/Server/Reflection.php'; + $reflection = Zend_Server_Reflection::reflectClass($class, $argv, $namespace); + + foreach ($reflection->getMethods() as $method) { + $definition = $this->_buildSignature($method, $class); + $this->_addMethodServiceMap($definition); + } + return $this; + } + + /** + * Indicate fault response + * + * @param string $fault + * @param int $code + * @return false + */ + public function fault($fault = null, $code = 404, $data = null) + { + require_once 'Zend/Json/Server/Error.php'; + $error = new Zend_Json_Server_Error($fault, $code, $data); + $this->getResponse()->setError($error); + return $error; + } + + /** + * Handle request + * + * @param Zend_Json_Server_Request $request + * @return null|Zend_Json_Server_Response + */ + public function handle($request = false) + { + if ((false !== $request) && (!$request instanceof Zend_Json_Server_Request)) { + require_once 'Zend/Json/Server/Exception.php'; + throw new Zend_Json_Server_Exception('Invalid request type provided; cannot handle'); + } elseif ($request) { + $this->setRequest($request); + } + + // Handle request + $this->_handle(); + + // Get response + $response = $this->_getReadyResponse(); + + // Emit response? + if ($this->autoEmitResponse()) { + echo $response; + return; + } + + // or return it? + return $response; + } + + /** + * Load function definitions + * + * @param array|Zend_Server_Definition $definition + * @return void + */ + public function loadFunctions($definition) + { + if (!is_array($definition) && (!$definition instanceof Zend_Server_Definition)) { + require_once 'Zend/Json/Server/Exception.php'; + throw new Zend_Json_Server_Exception('Invalid definition provided to loadFunctions()'); + } + + foreach ($definition as $key => $method) { + $this->_table->addMethod($method, $key); + $this->_addMethodServiceMap($method); + } + } + + public function setPersistence($mode) + { + } + + /** + * Set request object + * + * @param Zend_Json_Server_Request $request + * @return Zend_Json_Server + */ + public function setRequest(Zend_Json_Server_Request $request) + { + $this->_request = $request; + return $this; + } + + /** + * Get JSON-RPC request object + * + * @return Zend_Json_Server_Request + */ + public function getRequest() + { + if (null === ($request = $this->_request)) { + require_once 'Zend/Json/Server/Request/Http.php'; + $this->setRequest(new Zend_Json_Server_Request_Http()); + } + return $this->_request; + } + + /** + * Set response object + * + * @param Zend_Json_Server_Response $response + * @return Zend_Json_Server + */ + public function setResponse(Zend_Json_Server_Response $response) + { + $this->_response = $response; + return $this; + } + + /** + * Get response object + * + * @return Zend_Json_Server_Response + */ + public function getResponse() + { + if (null === ($response = $this->_response)) { + require_once 'Zend/Json/Server/Response/Http.php'; + $this->setResponse(new Zend_Json_Server_Response_Http()); + } + return $this->_response; + } + + /** + * Set flag indicating whether or not to auto-emit response + * + * @param bool $flag + * @return Zend_Json_Server + */ + public function setAutoEmitResponse($flag) + { + $this->_autoEmitResponse = (bool) $flag; + return $this; + } + + /** + * Will we auto-emit the response? + * + * @return bool + */ + public function autoEmitResponse() + { + return $this->_autoEmitResponse; + } + + // overloading for SMD metadata + /** + * Overload to accessors of SMD object + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, $args) + { + if (preg_match('/^(set|get)/', $method, $matches)) { + if (in_array($method, $this->_getSmdMethods())) { + if ('set' == $matches[1]) { + $value = array_shift($args); + $this->getServiceMap()->$method($value); + return $this; + } else { + return $this->getServiceMap()->$method(); + } + } + } + return null; + } + + /** + * Retrieve SMD object + * + * @return Zend_Json_Server_Smd + */ + public function getServiceMap() + { + if (null === $this->_serviceMap) { + require_once 'Zend/Json/Server/Smd.php'; + $this->_serviceMap = new Zend_Json_Server_Smd(); + } + return $this->_serviceMap; + } + + /** + * Add service method to service map + * + * @param Zend_Server_Reflection_Function $method + * @return void + */ + protected function _addMethodServiceMap(Zend_Server_Method_Definition $method) + { + $serviceInfo = array( + 'name' => $method->getName(), + 'return' => $this->_getReturnType($method), + ); + $params = $this->_getParams($method); + $serviceInfo['params'] = $params; + $serviceMap = $this->getServiceMap(); + if (false !== $serviceMap->getService($serviceInfo['name'])) { + $serviceMap->removeService($serviceInfo['name']); + } + $serviceMap->addService($serviceInfo); + } + + /** + * Translate PHP type to JSON type + * + * @param string $type + * @return string + */ + protected function _fixType($type) + { + return $type; + } + + /** + * Get default params from signature + * + * @param array $args + * @param array $params + * @return array + */ + protected function _getDefaultParams(array $args, array $params) + { + $defaultParams = array_slice($params, count($args)); + foreach ($defaultParams as $param) { + $value = null; + if (array_key_exists('default', $param)) { + $value = $param['default']; + } + array_push($args, $value); + } + return $args; + } + + /** + * Get method param type + * + * @param Zend_Server_Reflection_Function_Abstract $method + * @return string|array + */ + protected function _getParams(Zend_Server_Method_Definition $method) + { + $params = array(); + foreach ($method->getPrototypes() as $prototype) { + foreach ($prototype->getParameterObjects() as $key => $parameter) { + if (!isset($params[$key])) { + $params[$key] = array( + 'type' => $parameter->getType(), + 'name' => $parameter->getName(), + 'optional' => $parameter->isOptional(), + ); + if (null !== ($default = $parameter->getDefaultValue())) { + $params[$key]['default'] = $default; + } + $description = $parameter->getDescription(); + if (!empty($description)) { + $params[$key]['description'] = $description; + } + continue; + } + $newType = $parameter->getType(); + if (!is_array($params[$key]['type'])) { + if ($params[$key]['type'] == $newType) { + continue; + } + $params[$key]['type'] = (array) $params[$key]['type']; + } elseif (in_array($newType, $params[$key]['type'])) { + continue; + } + array_push($params[$key]['type'], $parameter->getType()); + } + } + return $params; + } + + /** + * Set response state + * + * @return Zend_Json_Server_Response + */ + protected function _getReadyResponse() + { + $request = $this->getRequest(); + $response = $this->getResponse(); + + $response->setServiceMap($this->getServiceMap()); + if (null !== ($id = $request->getId())) { + $response->setId($id); + } + if (null !== ($version = $request->getVersion())) { + $response->setVersion($version); + } + + return $response; + } + + /** + * Get method return type + * + * @param Zend_Server_Reflection_Function_Abstract $method + * @return string|array + */ + protected function _getReturnType(Zend_Server_Method_Definition $method) + { + $return = array(); + foreach ($method->getPrototypes() as $prototype) { + $return[] = $prototype->getReturnType(); + } + if (1 == count($return)) { + return $return[0]; + } + return $return; + } + + /** + * Retrieve list of allowed SMD methods for proxying + * + * @return array + */ + protected function _getSmdMethods() + { + if (null === $this->_smdMethods) { + $this->_smdMethods = array(); + require_once 'Zend/Json/Server/Smd.php'; + $methods = get_class_methods('Zend_Json_Server_Smd'); + foreach ($methods as $key => $method) { + if (!preg_match('/^(set|get)/', $method)) { + continue; + } + if (strstr($method, 'Service')) { + continue; + } + $this->_smdMethods[] = $method; + } + } + return $this->_smdMethods; + } + + /** + * Internal method for handling request + * + * @return void + */ + protected function _handle() + { + $request = $this->getRequest(); + + if (!$request->isMethodError() && (null === $request->getMethod())) { + return $this->fault('Invalid Request', -32600); + } + + if ($request->isMethodError()) { + return $this->fault('Invalid Request', -32600); + } + + $method = $request->getMethod(); + if (!$this->_table->hasMethod($method)) { + return $this->fault('Method not found', -32601); + } + + $params = $request->getParams(); + $invocable = $this->_table->getMethod($method); + $serviceMap = $this->getServiceMap(); + $service = $serviceMap->getService($method); + $serviceParams = $service->getParams(); + + if (count($params) < count($serviceParams)) { + $params = $this->_getDefaultParams($params, $serviceParams); + } + + //Make sure named parameters are passed in correct order + if ( is_string( key( $params ) ) ) { + + $callback = $invocable->getCallback(); + if ('function' == $callback->getType()) { + $reflection = new ReflectionFunction( $callback->getFunction() ); + $refParams = $reflection->getParameters(); + } else { + + $reflection = new ReflectionMethod( + $callback->getClass(), + $callback->getMethod() + ); + $refParams = $reflection->getParameters(); + } + + $orderedParams = array(); + foreach( $reflection->getParameters() as $refParam ) { + if( isset( $params[ $refParam->getName() ] ) ) { + $orderedParams[ $refParam->getName() ] = $params[ $refParam->getName() ]; + } elseif( $refParam->isOptional() ) { + $orderedParams[ $refParam->getName() ] = null; + } else { + throw new Zend_Server_Exception( + 'Missing required parameter: ' . $refParam->getName() + ); + } + } + $params = $orderedParams; + } + + try { + $result = $this->_dispatch($invocable, $params); + } catch (Exception $e) { + return $this->fault($e->getMessage(), $e->getCode(), $e); + } + + $this->getResponse()->setResult($result); + } +}