/framework/vendor/zend/Zend/Json/Server.php

http://zoop.googlecode.com/ · PHP · 537 lines · 297 code · 52 blank · 188 comment · 44 complexity · 6453c57ae42e06de50ad7cf81d8580c1 MD5 · raw file

  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 license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Json
  17. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. * @version $Id: Server.php 20096 2010-01-06 02:05:09Z bkarwin $
  20. */
  21. /**
  22. * @see Zend_Server_Abstract
  23. */
  24. require_once 'Zend/Server/Abstract.php';
  25. /**
  26. * @category Zend
  27. * @package Zend_Json
  28. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  29. * @license http://framework.zend.com/license/new-bsd New BSD License
  30. */
  31. class Zend_Json_Server extends Zend_Server_Abstract
  32. {
  33. /**#@+
  34. * Version Constants
  35. */
  36. const VERSION_1 = '1.0';
  37. const VERSION_2 = '2.0';
  38. /**#@-*/
  39. /**
  40. * Flag: whether or not to auto-emit the response
  41. * @var bool
  42. */
  43. protected $_autoEmitResponse = true;
  44. /**
  45. * @var bool Flag; allow overwriting existing methods when creating server definition
  46. */
  47. protected $_overwriteExistingMethods = true;
  48. /**
  49. * Request object
  50. * @var Zend_Json_Server_Request
  51. */
  52. protected $_request;
  53. /**
  54. * Response object
  55. * @var Zend_Json_Server_Response
  56. */
  57. protected $_response;
  58. /**
  59. * SMD object
  60. * @var Zend_Json_Server_Smd
  61. */
  62. protected $_serviceMap;
  63. /**
  64. * SMD class accessors
  65. * @var array
  66. */
  67. protected $_smdMethods;
  68. /**
  69. * @var Zend_Server_Description
  70. */
  71. protected $_table;
  72. /**
  73. * Attach a function or callback to the server
  74. *
  75. * @param string|array $function Valid PHP callback
  76. * @param string $namespace Ignored
  77. * @return Zend_Json_Server
  78. */
  79. public function addFunction($function, $namespace = '')
  80. {
  81. if (!is_string($function) && (!is_array($function) || (2 > count($function)))) {
  82. require_once 'Zend/Json/Server/Exception.php';
  83. throw new Zend_Json_Server_Exception('Unable to attach function; invalid');
  84. }
  85. if (!is_callable($function)) {
  86. require_once 'Zend/Json/Server/Exception.php';
  87. throw new Zend_Json_Server_Exception('Unable to attach function; does not exist');
  88. }
  89. $argv = null;
  90. if (2 < func_num_args()) {
  91. $argv = func_get_args();
  92. $argv = array_slice($argv, 2);
  93. }
  94. require_once 'Zend/Server/Reflection.php';
  95. if (is_string($function)) {
  96. $method = Zend_Server_Reflection::reflectFunction($function, $argv, $namespace);
  97. } else {
  98. $class = array_shift($function);
  99. $action = array_shift($function);
  100. $reflection = Zend_Server_Reflection::reflectClass($class, $argv, $namespace);
  101. $methods = $reflection->getMethods();
  102. $found = false;
  103. foreach ($methods as $method) {
  104. if ($action == $method->getName()) {
  105. $found = true;
  106. break;
  107. }
  108. }
  109. if (!$found) {
  110. $this->fault('Method not found', -32601);
  111. return $this;
  112. }
  113. }
  114. $definition = $this->_buildSignature($method);
  115. $this->_addMethodServiceMap($definition);
  116. return $this;
  117. }
  118. /**
  119. * Register a class with the server
  120. *
  121. * @param string $class
  122. * @param string $namespace Ignored
  123. * @param mixed $argv Ignored
  124. * @return Zend_Json_Server
  125. */
  126. public function setClass($class, $namespace = '', $argv = null)
  127. {
  128. $argv = null;
  129. if (3 < func_num_args()) {
  130. $argv = func_get_args();
  131. $argv = array_slice($argv, 3);
  132. }
  133. require_once 'Zend/Server/Reflection.php';
  134. $reflection = Zend_Server_Reflection::reflectClass($class, $argv, $namespace);
  135. foreach ($reflection->getMethods() as $method) {
  136. $definition = $this->_buildSignature($method, $class);
  137. $this->_addMethodServiceMap($definition);
  138. }
  139. return $this;
  140. }
  141. /**
  142. * Indicate fault response
  143. *
  144. * @param string $fault
  145. * @param int $code
  146. * @return false
  147. */
  148. public function fault($fault = null, $code = 404, $data = null)
  149. {
  150. require_once 'Zend/Json/Server/Error.php';
  151. $error = new Zend_Json_Server_Error($fault, $code, $data);
  152. $this->getResponse()->setError($error);
  153. return $error;
  154. }
  155. /**
  156. * Handle request
  157. *
  158. * @param Zend_Json_Server_Request $request
  159. * @return null|Zend_Json_Server_Response
  160. */
  161. public function handle($request = false)
  162. {
  163. if ((false !== $request) && (!$request instanceof Zend_Json_Server_Request)) {
  164. require_once 'Zend/Json/Server/Exception.php';
  165. throw new Zend_Json_Server_Exception('Invalid request type provided; cannot handle');
  166. } elseif ($request) {
  167. $this->setRequest($request);
  168. }
  169. // Handle request
  170. $this->_handle();
  171. // Get response
  172. $response = $this->_getReadyResponse();
  173. // Emit response?
  174. if ($this->autoEmitResponse()) {
  175. echo $response;
  176. return;
  177. }
  178. // or return it?
  179. return $response;
  180. }
  181. /**
  182. * Load function definitions
  183. *
  184. * @param array|Zend_Server_Definition $definition
  185. * @return void
  186. */
  187. public function loadFunctions($definition)
  188. {
  189. if (!is_array($definition) && (!$definition instanceof Zend_Server_Definition)) {
  190. require_once 'Zend/Json/Server/Exception.php';
  191. throw new Zend_Json_Server_Exception('Invalid definition provided to loadFunctions()');
  192. }
  193. foreach ($definition as $key => $method) {
  194. $this->_table->addMethod($method, $key);
  195. $this->_addMethodServiceMap($method);
  196. }
  197. }
  198. public function setPersistence($mode)
  199. {
  200. }
  201. /**
  202. * Set request object
  203. *
  204. * @param Zend_Json_Server_Request $request
  205. * @return Zend_Json_Server
  206. */
  207. public function setRequest(Zend_Json_Server_Request $request)
  208. {
  209. $this->_request = $request;
  210. return $this;
  211. }
  212. /**
  213. * Get JSON-RPC request object
  214. *
  215. * @return Zend_Json_Server_Request
  216. */
  217. public function getRequest()
  218. {
  219. if (null === ($request = $this->_request)) {
  220. require_once 'Zend/Json/Server/Request/Http.php';
  221. $this->setRequest(new Zend_Json_Server_Request_Http());
  222. }
  223. return $this->_request;
  224. }
  225. /**
  226. * Set response object
  227. *
  228. * @param Zend_Json_Server_Response $response
  229. * @return Zend_Json_Server
  230. */
  231. public function setResponse(Zend_Json_Server_Response $response)
  232. {
  233. $this->_response = $response;
  234. return $this;
  235. }
  236. /**
  237. * Get response object
  238. *
  239. * @return Zend_Json_Server_Response
  240. */
  241. public function getResponse()
  242. {
  243. if (null === ($response = $this->_response)) {
  244. require_once 'Zend/Json/Server/Response/Http.php';
  245. $this->setResponse(new Zend_Json_Server_Response_Http());
  246. }
  247. return $this->_response;
  248. }
  249. /**
  250. * Set flag indicating whether or not to auto-emit response
  251. *
  252. * @param bool $flag
  253. * @return Zend_Json_Server
  254. */
  255. public function setAutoEmitResponse($flag)
  256. {
  257. $this->_autoEmitResponse = (bool) $flag;
  258. return $this;
  259. }
  260. /**
  261. * Will we auto-emit the response?
  262. *
  263. * @return bool
  264. */
  265. public function autoEmitResponse()
  266. {
  267. return $this->_autoEmitResponse;
  268. }
  269. // overloading for SMD metadata
  270. /**
  271. * Overload to accessors of SMD object
  272. *
  273. * @param string $method
  274. * @param array $args
  275. * @return mixed
  276. */
  277. public function __call($method, $args)
  278. {
  279. if (preg_match('/^(set|get)/', $method, $matches)) {
  280. if (in_array($method, $this->_getSmdMethods())) {
  281. if ('set' == $matches[1]) {
  282. $value = array_shift($args);
  283. $this->getServiceMap()->$method($value);
  284. return $this;
  285. } else {
  286. return $this->getServiceMap()->$method();
  287. }
  288. }
  289. }
  290. return null;
  291. }
  292. /**
  293. * Retrieve SMD object
  294. *
  295. * @return Zend_Json_Server_Smd
  296. */
  297. public function getServiceMap()
  298. {
  299. if (null === $this->_serviceMap) {
  300. require_once 'Zend/Json/Server/Smd.php';
  301. $this->_serviceMap = new Zend_Json_Server_Smd();
  302. }
  303. return $this->_serviceMap;
  304. }
  305. /**
  306. * Add service method to service map
  307. *
  308. * @param Zend_Server_Reflection_Function $method
  309. * @return void
  310. */
  311. protected function _addMethodServiceMap(Zend_Server_Method_Definition $method)
  312. {
  313. $serviceInfo = array(
  314. 'name' => $method->getName(),
  315. 'return' => $this->_getReturnType($method),
  316. );
  317. $params = $this->_getParams($method);
  318. $serviceInfo['params'] = $params;
  319. $serviceMap = $this->getServiceMap();
  320. if (false !== $serviceMap->getService($serviceInfo['name'])) {
  321. $serviceMap->removeService($serviceInfo['name']);
  322. }
  323. $serviceMap->addService($serviceInfo);
  324. }
  325. /**
  326. * Translate PHP type to JSON type
  327. *
  328. * @param string $type
  329. * @return string
  330. */
  331. protected function _fixType($type)
  332. {
  333. return $type;
  334. }
  335. /**
  336. * Get default params from signature
  337. *
  338. * @param array $args
  339. * @param array $params
  340. * @return array
  341. */
  342. protected function _getDefaultParams(array $args, array $params)
  343. {
  344. $defaultParams = array_slice($params, count($args));
  345. foreach ($defaultParams as $param) {
  346. $value = null;
  347. if (array_key_exists('default', $param)) {
  348. $value = $param['default'];
  349. }
  350. array_push($args, $value);
  351. }
  352. return $args;
  353. }
  354. /**
  355. * Get method param type
  356. *
  357. * @param Zend_Server_Reflection_Function_Abstract $method
  358. * @return string|array
  359. */
  360. protected function _getParams(Zend_Server_Method_Definition $method)
  361. {
  362. $params = array();
  363. foreach ($method->getPrototypes() as $prototype) {
  364. foreach ($prototype->getParameterObjects() as $key => $parameter) {
  365. if (!isset($params[$key])) {
  366. $params[$key] = array(
  367. 'type' => $parameter->getType(),
  368. 'name' => $parameter->getName(),
  369. 'optional' => $parameter->isOptional(),
  370. );
  371. if (null !== ($default = $parameter->getDefaultValue())) {
  372. $params[$key]['default'] = $default;
  373. }
  374. $description = $parameter->getDescription();
  375. if (!empty($description)) {
  376. $params[$key]['description'] = $description;
  377. }
  378. continue;
  379. }
  380. $newType = $parameter->getType();
  381. if (!is_array($params[$key]['type'])) {
  382. if ($params[$key]['type'] == $newType) {
  383. continue;
  384. }
  385. $params[$key]['type'] = (array) $params[$key]['type'];
  386. } elseif (in_array($newType, $params[$key]['type'])) {
  387. continue;
  388. }
  389. array_push($params[$key]['type'], $parameter->getType());
  390. }
  391. }
  392. return $params;
  393. }
  394. /**
  395. * Set response state
  396. *
  397. * @return Zend_Json_Server_Response
  398. */
  399. protected function _getReadyResponse()
  400. {
  401. $request = $this->getRequest();
  402. $response = $this->getResponse();
  403. $response->setServiceMap($this->getServiceMap());
  404. if (null !== ($id = $request->getId())) {
  405. $response->setId($id);
  406. }
  407. if (null !== ($version = $request->getVersion())) {
  408. $response->setVersion($version);
  409. }
  410. return $response;
  411. }
  412. /**
  413. * Get method return type
  414. *
  415. * @param Zend_Server_Reflection_Function_Abstract $method
  416. * @return string|array
  417. */
  418. protected function _getReturnType(Zend_Server_Method_Definition $method)
  419. {
  420. $return = array();
  421. foreach ($method->getPrototypes() as $prototype) {
  422. $return[] = $prototype->getReturnType();
  423. }
  424. if (1 == count($return)) {
  425. return $return[0];
  426. }
  427. return $return;
  428. }
  429. /**
  430. * Retrieve list of allowed SMD methods for proxying
  431. *
  432. * @return array
  433. */
  434. protected function _getSmdMethods()
  435. {
  436. if (null === $this->_smdMethods) {
  437. $this->_smdMethods = array();
  438. require_once 'Zend/Json/Server/Smd.php';
  439. $methods = get_class_methods('Zend_Json_Server_Smd');
  440. foreach ($methods as $key => $method) {
  441. if (!preg_match('/^(set|get)/', $method)) {
  442. continue;
  443. }
  444. if (strstr($method, 'Service')) {
  445. continue;
  446. }
  447. $this->_smdMethods[] = $method;
  448. }
  449. }
  450. return $this->_smdMethods;
  451. }
  452. /**
  453. * Internal method for handling request
  454. *
  455. * @return void
  456. */
  457. protected function _handle()
  458. {
  459. $request = $this->getRequest();
  460. if (!$request->isMethodError() && (null === $request->getMethod())) {
  461. return $this->fault('Invalid Request', -32600);
  462. }
  463. if ($request->isMethodError()) {
  464. return $this->fault('Invalid Request', -32600);
  465. }
  466. $method = $request->getMethod();
  467. if (!$this->_table->hasMethod($method)) {
  468. return $this->fault('Method not found', -32601);
  469. }
  470. $params = $request->getParams();
  471. $invocable = $this->_table->getMethod($method);
  472. $serviceMap = $this->getServiceMap();
  473. $service = $serviceMap->getService($method);
  474. $serviceParams = $service->getParams();
  475. if (count($params) < count($serviceParams)) {
  476. $params = $this->_getDefaultParams($params, $serviceParams);
  477. }
  478. try {
  479. $result = $this->_dispatch($invocable, $params);
  480. } catch (Exception $e) {
  481. return $this->fault($e->getMessage(), $e->getCode(), $e);
  482. }
  483. $this->getResponse()->setResult($result);
  484. }
  485. }