|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00003 // This file is part of Moodle - http://moodle.org/ 00004 // 00005 // Moodle is free software: you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation, either version 3 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // Moodle is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00017 00026 require_once("$CFG->dirroot/webservice/lib.php"); 00027 require_once( "{$CFG->dirroot}/webservice/amf/introspector.php"); 00028 require_once 'Zend/Amf/Server.php'; 00033 class invalid_return_value_exception extends moodle_exception { 00038 function __construct($debuginfo=null) { 00039 parent::__construct('invalidreturnvalue', 'webservice_amf', '', $debuginfo, $debuginfo); 00040 } 00041 } 00042 00047 class webservice_amf_server extends webservice_zend_server { 00052 public function __construct($authmethod) { 00053 parent::__construct($authmethod, 'Moodle_Amf_Server'); 00054 $this->wsname = 'amf'; 00055 } 00056 protected function init_service_class(){ 00057 parent::init_service_class(); 00058 //allow access to data about methods available. 00059 $this->zend_server->setClass( "MethodDescriptor" ); 00060 MethodDescriptor::$classnametointrospect = $this->service_class; 00061 } 00062 00063 protected function service_class_method_body($function, $params){ 00064 //cast the param from object to array (validate_parameters except array only) 00065 $castingcode = ''; 00066 if ($params){ 00067 $paramstocast = explode(',', $params); 00068 foreach ($paramstocast as $paramtocast) { 00069 $paramtocast = trim($paramtocast); 00070 $castingcode .= $paramtocast . 00071 '=webservice_zend_server::cast_objects_to_array('.$paramtocast.');'; 00072 } 00073 00074 } 00075 00076 $externallibcall = $function->classname.'::'.$function->methodname.'('.$params.')'; 00077 $descriptionmethod = $function->methodname.'_returns()'; 00078 $callforreturnvaluedesc = $function->classname.'::'.$descriptionmethod; 00079 return $castingcode . 00080 ' return webservice_amf_server::validate_and_cast_values('.$callforreturnvaluedesc.', '.$externallibcall.');'; 00081 } 00092 public static function validate_and_cast_values($description, $value) { 00093 if (is_null($description)){ 00094 return; 00095 } 00096 if ($description instanceof external_value) { 00097 if (is_array($value) or is_object($value)) { 00098 throw new invalid_return_value_exception('Scalar type expected, array or object received.'); 00099 } 00100 00101 if ($description->type == PARAM_BOOL) { 00102 // special case for PARAM_BOOL - we want true/false instead of the usual 1/0 - we can not be too strict here ;-) 00103 if (is_bool($value) or $value === 0 or $value === 1 or $value === '0' or $value === '1') { 00104 return (bool)$value; 00105 } 00106 } 00107 return validate_param($value, $description->type, $description->allownull, 'Invalid external api parameter'); 00108 00109 } else if ($description instanceof external_single_structure) { 00110 if (!is_array($value)) { 00111 throw new invalid_return_value_exception('Only arrays accepted.'); 00112 } 00113 $result = array(); 00114 foreach ($description->keys as $key=>$subdesc) { 00115 if (!array_key_exists($key, $value)) { 00116 if ($subdesc->required == VALUE_REQUIRED) { 00117 throw new invalid_return_value_exception('Missing required key in single structure: '.$key); 00118 } 00119 if ($subdesc instanceof external_value) { 00120 if ($subdesc->required == VALUE_DEFAULT) { 00121 $result[$key] = self::validate_and_cast_values($subdesc, $subdesc->default); 00122 } 00123 } 00124 } else { 00125 $result[$key] = self::validate_and_cast_values($subdesc, $value[$key]); 00126 } 00127 unset($value[$key]); 00128 } 00129 /* Was decided that extra keys should just be ignored and not returned. 00130 * if (!empty($value)) { 00131 throw new invalid_return_value_exception('Unexpected keys detected in parameter array.'); 00132 }*/ 00133 return (object)$result; 00134 00135 } else if ($description instanceof external_multiple_structure) { 00136 if (!is_array($value)) { 00137 throw new invalid_return_value_exception('Only arrays accepted.'); 00138 } 00139 $result = array(); 00140 foreach ($value as $param) { 00141 $result[] = self::validate_and_cast_values($description->content, $param); 00142 } 00143 return $result; 00144 00145 } else { 00146 throw new invalid_return_value_exception('Invalid external api description.'); 00147 } 00148 } 00149 00154 protected function init_zend_server() { 00155 parent::init_zend_server(); 00156 $this->zend_server->setProduction(false); //set to false for development mode 00157 //(complete error message displayed into your AMF client) 00158 // TODO: add some exception handling 00159 } 00160 00161 00162 } 00163 class Moodle_Amf_Server extends Zend_Amf_Server{ 00170 public function fault($fault = null, $code = 404) 00171 { 00172 if (!$fault instanceof Exception) { 00173 $fault = new Exception($fault); 00174 } 00175 $request = $this->getRequest(); 00176 // Get the object encoding of the request. 00177 $objectEncoding = $request->getObjectEncoding(); 00178 00179 // create a response object to place the output from the services. 00180 $response = $this->getResponse(); 00181 00182 // set reponse encoding 00183 $response->setObjectEncoding($objectEncoding); 00184 00185 $responseBody = $request->getAmfBodies(); 00186 00187 foreach($responseBody as $body){ 00188 $return = $this->_errorMessage($objectEncoding, $fault->getMessage(), 00189 $fault->getMessage(), $fault->getTraceAsString(),$fault->getCode(), $fault->getLine()); 00190 $responseType = Zend_AMF_Constants::STATUS_METHOD; 00191 00192 00193 $responseURI = $body->getResponseURI() . $responseType; 00194 $newBody = new Zend_Amf_Value_MessageBody($responseURI, null, $return); 00195 $response->addAmfBody($newBody); 00196 } 00197 $response->finalize(); 00198 echo $response; 00199 } 00200 } 00201 00202 // TODO: implement AMF test client somehow, maybe we could use moodle form to feed the data to the flash app somehow