File indexing completed on 2024-12-22 05:36:27
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Amf 0017 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0018 * @license http://framework.zend.com/license/new-bsd New BSD License 0019 * @version $Id$ 0020 */ 0021 0022 /** @see Zend_Amf_Parse_TypeLoader */ 0023 // require_once 'Zend/Amf/Parse/TypeLoader.php'; 0024 0025 /** @see Zend_Reflection_Class */ 0026 // require_once 'Zend/Reflection/Class.php'; 0027 0028 /** @see Zend_Server_Reflection */ 0029 // require_once 'Zend/Server/Reflection.php'; 0030 0031 /** 0032 * This class implements a service for generating AMF service descriptions as XML. 0033 * 0034 * @package Zend_Amf 0035 * @subpackage Adobe 0036 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0037 * @license http://framework.zend.com/license/new-bsd New BSD License 0038 */ 0039 class Zend_Amf_Adobe_Introspector 0040 { 0041 /** 0042 * Options used: 0043 * - server: instance of Zend_Amf_Server to use 0044 * - directories: directories where class files may be looked up 0045 * 0046 * @var array Introspector options 0047 */ 0048 protected $_options; 0049 0050 /** 0051 * @var DOMElement DOM element to store types 0052 */ 0053 protected $_types; 0054 0055 /** 0056 * @var array Map of the known types 0057 */ 0058 protected $_typesMap = array(); 0059 0060 /** 0061 * @var DOMDocument XML document to store data 0062 */ 0063 protected $_xml; 0064 0065 /** 0066 * Constructor 0067 * 0068 * @return void 0069 */ 0070 public function __construct() 0071 { 0072 $this->_xml = new DOMDocument('1.0', 'utf-8'); 0073 } 0074 0075 /** 0076 * Create XML definition on an AMF service class 0077 * 0078 * @param string $serviceClass Service class name 0079 * @param array $options invocation options 0080 * @return string XML with service class introspection 0081 */ 0082 public function introspect($serviceClass, $options = array()) 0083 { 0084 $this->_options = $options; 0085 0086 if (strpbrk($serviceClass, '\\/<>')) { 0087 return $this->_returnError('Invalid service name'); 0088 } 0089 0090 // Transform com.foo.Bar into com_foo_Bar 0091 $serviceClass = str_replace('.' , '_', $serviceClass); 0092 0093 // Introspect! 0094 if (!class_exists($serviceClass)) { 0095 // require_once 'Zend/Loader.php'; 0096 Zend_Loader::loadClass($serviceClass, $this->_getServicePath()); 0097 } 0098 0099 $serv = $this->_xml->createElement('service-description'); 0100 $serv->setAttribute('xmlns', 'http://ns.adobe.com/flex/service-description/2008'); 0101 0102 $this->_types = $this->_xml->createElement('types'); 0103 $this->_ops = $this->_xml->createElement('operations'); 0104 0105 $r = Zend_Server_Reflection::reflectClass($serviceClass); 0106 $this->_addService($r, $this->_ops); 0107 0108 $serv->appendChild($this->_types); 0109 $serv->appendChild($this->_ops); 0110 $this->_xml->appendChild($serv); 0111 0112 return $this->_xml->saveXML(); 0113 } 0114 0115 /** 0116 * Authentication handler 0117 * 0118 * @param Zend_Acl $acl 0119 * @return unknown_type 0120 */ 0121 public function initAcl(Zend_Acl $acl) 0122 { 0123 return false; // we do not need auth for this class 0124 } 0125 0126 /** 0127 * Generate map of public class attributes 0128 * 0129 * @param string $typename type name 0130 * @param DOMElement $typexml target XML element 0131 * @return void 0132 */ 0133 protected function _addClassAttributes($typename, DOMElement $typexml) 0134 { 0135 // Do not try to autoload here because _phpTypeToAS should 0136 // have already attempted to load this class 0137 if (!class_exists($typename, false)) { 0138 return; 0139 } 0140 0141 $rc = new Zend_Reflection_Class($typename); 0142 foreach ($rc->getProperties() as $prop) { 0143 if (!$prop->isPublic()) { 0144 continue; 0145 } 0146 0147 $propxml = $this->_xml->createElement('property'); 0148 $propxml->setAttribute('name', $prop->getName()); 0149 0150 $type = $this->_registerType($this->_getPropertyType($prop)); 0151 $propxml->setAttribute('type', $type); 0152 0153 $typexml->appendChild($propxml); 0154 } 0155 } 0156 0157 /** 0158 * Build XML service description from reflection class 0159 * 0160 * @param Zend_Server_Reflection_Class $refclass 0161 * @param DOMElement $target target XML element 0162 * @return void 0163 */ 0164 protected function _addService(Zend_Server_Reflection_Class $refclass, DOMElement $target) 0165 { 0166 foreach ($refclass->getMethods() as $method) { 0167 if (!$method->isPublic() 0168 || $method->isConstructor() 0169 || ('__' == substr($method->name, 0, 2)) 0170 ) { 0171 continue; 0172 } 0173 0174 foreach ($method->getPrototypes() as $proto) { 0175 $op = $this->_xml->createElement('operation'); 0176 $op->setAttribute('name', $method->getName()); 0177 0178 $rettype = $this->_registerType($proto->getReturnType()); 0179 $op->setAttribute('returnType', $rettype); 0180 0181 foreach ($proto->getParameters() as $param) { 0182 $arg = $this->_xml->createElement('argument'); 0183 $arg->setAttribute('name', $param->getName()); 0184 0185 $type = $param->getType(); 0186 if ($type == 'mixed' && ($pclass = $param->getClass())) { 0187 $type = $pclass->getName(); 0188 } 0189 0190 $ptype = $this->_registerType($type); 0191 $arg->setAttribute('type', $ptype); 0192 0193 if($param->isDefaultValueAvailable()) { 0194 $arg->setAttribute('defaultvalue', $param->getDefaultValue()); 0195 } 0196 0197 $op->appendChild($arg); 0198 } 0199 0200 $target->appendChild($op); 0201 } 0202 } 0203 } 0204 0205 /** 0206 * Extract type of the property from DocBlock 0207 * 0208 * @param Zend_Reflection_Property $prop reflection property object 0209 * @return string Property type 0210 */ 0211 protected function _getPropertyType(Zend_Reflection_Property $prop) 0212 { 0213 $docBlock = $prop->getDocComment(); 0214 0215 if (!$docBlock) { 0216 return 'Unknown'; 0217 } 0218 0219 if (!$docBlock->hasTag('var')) { 0220 return 'Unknown'; 0221 } 0222 0223 $tag = $docBlock->getTag('var'); 0224 return trim($tag->getDescription()); 0225 } 0226 0227 /** 0228 * Get the array of service directories 0229 * 0230 * @return array Service class directories 0231 */ 0232 protected function _getServicePath() 0233 { 0234 if (isset($this->_options['server'])) { 0235 return $this->_options['server']->getDirectory(); 0236 } 0237 0238 if (isset($this->_options['directories'])) { 0239 return $this->_options['directories']; 0240 } 0241 0242 return array(); 0243 } 0244 0245 /** 0246 * Map from PHP type name to AS type name 0247 * 0248 * @param string $typename PHP type name 0249 * @return string AS type name 0250 */ 0251 protected function _phpTypeToAS($typename) 0252 { 0253 if (class_exists($typename)) { 0254 $vars = get_class_vars($typename); 0255 0256 if (isset($vars['_explicitType'])) { 0257 return $vars['_explicitType']; 0258 } 0259 } 0260 0261 if (false !== ($asname = Zend_Amf_Parse_TypeLoader::getMappedClassName($typename))) { 0262 return $asname; 0263 } 0264 0265 return $typename; 0266 } 0267 0268 /** 0269 * Register new type on the system 0270 * 0271 * @param string $typename type name 0272 * @return string New type name 0273 */ 0274 protected function _registerType($typename) 0275 { 0276 // Known type - return its AS name 0277 if (isset($this->_typesMap[$typename])) { 0278 return $this->_typesMap[$typename]; 0279 } 0280 0281 // Standard types 0282 if (in_array($typename, array('void', 'null', 'mixed', 'unknown_type'))) { 0283 return 'Unknown'; 0284 } 0285 0286 // Arrays 0287 if ('array' == $typename) { 0288 return 'Unknown[]'; 0289 } 0290 0291 if (in_array($typename, array('int', 'integer', 'bool', 'boolean', 'float', 'string', 'object', 'Unknown', 'stdClass'))) { 0292 return $typename; 0293 } 0294 0295 // Resolve and store AS name 0296 $asTypeName = $this->_phpTypeToAS($typename); 0297 $this->_typesMap[$typename] = $asTypeName; 0298 0299 // Create element for the name 0300 $typeEl = $this->_xml->createElement('type'); 0301 $typeEl->setAttribute('name', $asTypeName); 0302 $this->_addClassAttributes($typename, $typeEl); 0303 $this->_types->appendChild($typeEl); 0304 0305 return $asTypeName; 0306 } 0307 0308 /** 0309 * Return error with error message 0310 * 0311 * @param string $msg Error message 0312 * @return string 0313 */ 0314 protected function _returnError($msg) 0315 { 0316 return 'ERROR: $msg'; 0317 } 0318 }