PageRenderTime 101ms CodeModel.GetById 79ms app.highlight 14ms RepoModel.GetById 5ms app.codeStats 0ms

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