web/enmi/Zend/Amf/Adobe/Introspector.php
changeset 19 1c2f13fd785c
parent 0 4eba9c11703f
equal deleted inserted replaced
18:bd595ad770fc 19:1c2f13fd785c
       
     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_Amf
       
    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: Introspector.php 23316 2010-11-10 16:37:40Z matthew $
       
    20  */
       
    21 
       
    22 /** @see Zend_Amf_Parse_TypeLoader */
       
    23 require_once 'Zend/Amf/Parse/TypeLoader.php';
       
    24 
       
    25 /** @see Zend_Reflection_Class */
       
    26 require_once 'Zend/Reflection/Class.php';
       
    27 
       
    28 /** @see Zend_Server_Reflection */
       
    29 require_once 'Zend/Server/Reflection.php';
       
    30 
       
    31 /**
       
    32  * This class implements a service for generating AMF service descriptions as XML.
       
    33  *
       
    34  * @package    Zend_Amf
       
    35  * @subpackage Adobe
       
    36  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    37  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    38  */
       
    39 class Zend_Amf_Adobe_Introspector
       
    40 {
       
    41     /**
       
    42      * Options used:
       
    43      * - server: instance of Zend_Amf_Server to use
       
    44      * - directories: directories where class files may be looked up
       
    45      *
       
    46      * @var array Introspector options
       
    47      */
       
    48     protected $_options;
       
    49 
       
    50     /**
       
    51      * @var DOMElement DOM element to store types
       
    52      */
       
    53     protected $_types;
       
    54 
       
    55     /**
       
    56      * @var array Map of the known types
       
    57      */
       
    58     protected $_typesMap = array();
       
    59 
       
    60     /**
       
    61      * @var DOMDocument XML document to store data
       
    62      */
       
    63     protected $_xml;
       
    64 
       
    65     /**
       
    66      * Constructor
       
    67      *
       
    68      * @return void
       
    69      */
       
    70     public function __construct()
       
    71     {
       
    72         $this->_xml = new DOMDocument('1.0', 'utf-8');
       
    73     }
       
    74 
       
    75     /**
       
    76      * Create XML definition on an AMF service class
       
    77      *
       
    78      * @param  string $serviceClass Service class name
       
    79      * @param  array $options invocation options
       
    80      * @return string XML with service class introspection
       
    81      */
       
    82     public function introspect($serviceClass, $options = array())
       
    83     {
       
    84         $this->_options = $options;
       
    85 
       
    86         if (strpbrk($serviceClass, '\\/<>')) {
       
    87             return $this->_returnError('Invalid service name');
       
    88         }
       
    89 
       
    90         // Transform com.foo.Bar into com_foo_Bar
       
    91         $serviceClass = str_replace('.' , '_', $serviceClass);
       
    92 
       
    93         // Introspect!
       
    94         if (!class_exists($serviceClass)) {
       
    95             require_once 'Zend/Loader.php';
       
    96             Zend_Loader::loadClass($serviceClass, $this->_getServicePath());
       
    97         }
       
    98 
       
    99         $serv = $this->_xml->createElement('service-description');
       
   100         $serv->setAttribute('xmlns', 'http://ns.adobe.com/flex/service-description/2008');
       
   101 
       
   102         $this->_types = $this->_xml->createElement('types');
       
   103         $this->_ops   = $this->_xml->createElement('operations');
       
   104 
       
   105         $r = Zend_Server_Reflection::reflectClass($serviceClass);
       
   106         $this->_addService($r, $this->_ops);
       
   107 
       
   108         $serv->appendChild($this->_types);
       
   109         $serv->appendChild($this->_ops);
       
   110         $this->_xml->appendChild($serv);
       
   111 
       
   112         return $this->_xml->saveXML();
       
   113     }
       
   114 
       
   115     /**
       
   116      * Authentication handler
       
   117      *
       
   118      * @param  Zend_Acl $acl
       
   119      * @return unknown_type
       
   120      */
       
   121     public function initAcl(Zend_Acl $acl)
       
   122     {
       
   123         return false; // we do not need auth for this class
       
   124     }
       
   125 
       
   126     /**
       
   127      * Generate map of public class attributes
       
   128      *
       
   129      * @param  string $typename type name
       
   130      * @param  DOMElement $typexml target XML element
       
   131      * @return void
       
   132      */
       
   133     protected function _addClassAttributes($typename, DOMElement $typexml)
       
   134     {
       
   135         // Do not try to autoload here because _phpTypeToAS should
       
   136         // have already attempted to load this class
       
   137         if (!class_exists($typename, false)) {
       
   138             return;
       
   139         }
       
   140 
       
   141         $rc = new Zend_Reflection_Class($typename);
       
   142         foreach ($rc->getProperties() as $prop) {
       
   143             if (!$prop->isPublic()) {
       
   144                 continue;
       
   145             }
       
   146 
       
   147             $propxml = $this->_xml->createElement('property');
       
   148             $propxml->setAttribute('name', $prop->getName());
       
   149 
       
   150             $type = $this->_registerType($this->_getPropertyType($prop));
       
   151             $propxml->setAttribute('type', $type);
       
   152 
       
   153             $typexml->appendChild($propxml);
       
   154         }
       
   155     }
       
   156 
       
   157     /**
       
   158      * Build XML service description from reflection class
       
   159      *
       
   160      * @param  Zend_Server_Reflection_Class $refclass
       
   161      * @param  DOMElement $target target XML element
       
   162      * @return void
       
   163      */
       
   164     protected function _addService(Zend_Server_Reflection_Class $refclass, DOMElement $target)
       
   165     {
       
   166         foreach ($refclass->getMethods() as $method) {
       
   167             if (!$method->isPublic()
       
   168                 || $method->isConstructor()
       
   169                 || ('__' == substr($method->name, 0, 2))
       
   170             ) {
       
   171                 continue;
       
   172             }
       
   173 
       
   174             foreach ($method->getPrototypes() as $proto) {
       
   175                 $op = $this->_xml->createElement('operation');
       
   176                 $op->setAttribute('name', $method->getName());
       
   177 
       
   178                 $rettype = $this->_registerType($proto->getReturnType());
       
   179                 $op->setAttribute('returnType', $rettype);
       
   180 
       
   181                 foreach ($proto->getParameters() as $param) {
       
   182                     $arg = $this->_xml->createElement('argument');
       
   183                     $arg->setAttribute('name', $param->getName());
       
   184 
       
   185                     $type = $param->getType();
       
   186                     if ($type == 'mixed' && ($pclass = $param->getClass())) {
       
   187                         $type = $pclass->getName();
       
   188                     }
       
   189 
       
   190                     $ptype = $this->_registerType($type);
       
   191                     $arg->setAttribute('type', $ptype);
       
   192 
       
   193                     if($param->isDefaultValueAvailable()) {
       
   194                         $arg->setAttribute('defaultvalue', $param->getDefaultValue());
       
   195                     }
       
   196 
       
   197                     $op->appendChild($arg);
       
   198                 }
       
   199 
       
   200                 $target->appendChild($op);
       
   201             }
       
   202         }
       
   203     }
       
   204 
       
   205     /**
       
   206      * Extract type of the property from DocBlock
       
   207      *
       
   208      * @param  Zend_Reflection_Property $prop reflection property object
       
   209      * @return string Property type
       
   210      */
       
   211     protected function _getPropertyType(Zend_Reflection_Property $prop)
       
   212     {
       
   213         $docBlock = $prop->getDocComment();
       
   214 
       
   215         if (!$docBlock) {
       
   216             return 'Unknown';
       
   217         }
       
   218 
       
   219         if (!$docBlock->hasTag('var')) {
       
   220             return 'Unknown';
       
   221         }
       
   222 
       
   223         $tag = $docBlock->getTag('var');
       
   224         return trim($tag->getDescription());
       
   225     }
       
   226 
       
   227     /**
       
   228      * Get the array of service directories
       
   229      *
       
   230      * @return array Service class directories
       
   231      */
       
   232     protected function _getServicePath()
       
   233     {
       
   234         if (isset($this->_options['server'])) {
       
   235             return $this->_options['server']->getDirectory();
       
   236         }
       
   237 
       
   238         if (isset($this->_options['directories'])) {
       
   239             return $this->_options['directories'];
       
   240         }
       
   241 
       
   242         return array();
       
   243     }
       
   244 
       
   245     /**
       
   246      * Map from PHP type name to AS type name
       
   247      *
       
   248      * @param  string $typename PHP type name
       
   249      * @return string AS type name
       
   250      */
       
   251     protected function _phpTypeToAS($typename)
       
   252     {
       
   253         if (class_exists($typename)) {
       
   254             $vars = get_class_vars($typename);
       
   255 
       
   256             if (isset($vars['_explicitType'])) {
       
   257                 return $vars['_explicitType'];
       
   258             }
       
   259         }
       
   260 
       
   261         if (false !== ($asname = Zend_Amf_Parse_TypeLoader::getMappedClassName($typename))) {
       
   262             return $asname;
       
   263         }
       
   264 
       
   265         return $typename;
       
   266     }
       
   267 
       
   268     /**
       
   269      * Register new type on the system
       
   270      *
       
   271      * @param  string $typename type name
       
   272      * @return string New type name
       
   273      */
       
   274     protected function _registerType($typename)
       
   275     {
       
   276         // Known type - return its AS name
       
   277         if (isset($this->_typesMap[$typename])) {
       
   278             return $this->_typesMap[$typename];
       
   279         }
       
   280 
       
   281         // Standard types
       
   282         if (in_array($typename, array('void', 'null', 'mixed', 'unknown_type'))) {
       
   283             return 'Unknown';
       
   284         }
       
   285 
       
   286         // Arrays
       
   287         if ('array' == $typename) {
       
   288             return 'Unknown[]';
       
   289         }
       
   290 
       
   291         if (in_array($typename, array('int', 'integer', 'bool', 'boolean', 'float', 'string', 'object', 'Unknown', 'stdClass'))) {
       
   292             return $typename;
       
   293         }
       
   294 
       
   295         // Resolve and store AS name
       
   296         $asTypeName = $this->_phpTypeToAS($typename);
       
   297         $this->_typesMap[$typename] = $asTypeName;
       
   298 
       
   299         // Create element for the name
       
   300         $typeEl = $this->_xml->createElement('type');
       
   301         $typeEl->setAttribute('name', $asTypeName);
       
   302         $this->_addClassAttributes($typename, $typeEl);
       
   303         $this->_types->appendChild($typeEl);
       
   304 
       
   305         return $asTypeName;
       
   306     }
       
   307 
       
   308    /**
       
   309      * Return error with error message
       
   310      *
       
   311      * @param  string $msg Error message
       
   312      * @return string
       
   313      */
       
   314     protected function _returnError($msg)
       
   315     {
       
   316         return 'ERROR: $msg';
       
   317     }
       
   318 }