Merge branch 'MDL-27857-assignment-portfolio_21_STABLE' of git://github.com/mudrd8mz...
[moodle.git] / webservice / amf / locallib.php
blob2716027f1d16d9a8750f421b2694ffc8d3bdea12
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
18 /**
19 * AMF web service implementation classes and methods.
21 * @package webservice
22 * @copyright 2009 Moodle Pty Ltd (http://moodle.com)
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 require_once("$CFG->dirroot/webservice/lib.php");
27 require_once( "{$CFG->dirroot}/webservice/amf/introspector.php");
28 require_once 'Zend/Amf/Server.php';
29 /**
30 * Exception indicating an invalid return value from a function.
31 * Used when an externallib function does not return values of the expected structure.
33 class invalid_return_value_exception extends moodle_exception {
34 /**
35 * Constructor
36 * @param string $debuginfo some detailed information
38 function __construct($debuginfo=null) {
39 parent::__construct('invalidreturnvalue', 'webservice_amf', '', $debuginfo, $debuginfo);
43 /**
44 * AMF service server implementation.
45 * @author Petr Skoda (skodak)
47 class webservice_amf_server extends webservice_zend_server {
48 /**
49 * Contructor
50 * @param integer $authmethod authentication method - one of WEBSERVICE_AUTHMETHOD_*
52 public function __construct($authmethod) {
53 parent::__construct($authmethod, 'Moodle_Amf_Server');
54 $this->wsname = 'amf';
56 protected function init_service_class(){
57 parent::init_service_class();
58 //allow access to data about methods available.
59 $this->zend_server->setClass( "MethodDescriptor" );
60 MethodDescriptor::$classnametointrospect = $this->service_class;
63 protected function service_class_method_body($function, $params){
64 //cast the param from object to array (validate_parameters except array only)
65 $castingcode = '';
66 if ($params){
67 $paramstocast = explode(',', $params);
68 foreach ($paramstocast as $paramtocast) {
69 $paramtocast = trim($paramtocast);
70 $castingcode .= $paramtocast .
71 '=webservice_zend_server::cast_objects_to_array('.$paramtocast.');';
76 $externallibcall = $function->classname.'::'.$function->methodname.'('.$params.')';
77 $descriptionmethod = $function->methodname.'_returns()';
78 $callforreturnvaluedesc = $function->classname.'::'.$descriptionmethod;
79 return $castingcode .
80 ' return webservice_amf_server::validate_and_cast_values('.$callforreturnvaluedesc.', '.$externallibcall.');';
82 /**
83 * Validates submitted value, comparing it to a description. If anything is incorrect
84 * invalid_return_value_exception is thrown. Also casts the values to the type specified in
85 * the description.
86 * @param mixed $description description of parameters or null if no return value
87 * @param mixed $value the actual values
88 * @param boolean $singleasobject specifies whether a external_single_structure should be cast to a stdClass object
89 * should always be false for use in validating parameters in externallib functions.
90 * @return mixed params with added defaults for optional items, invalid_parameters_exception thrown if any problem found
92 public static function validate_and_cast_values($description, $value) {
93 if (is_null($description)){
94 return;
96 if ($description instanceof external_value) {
97 if (is_array($value) or is_object($value)) {
98 throw new invalid_return_value_exception('Scalar type expected, array or object received.');
101 if ($description->type == PARAM_BOOL) {
102 // special case for PARAM_BOOL - we want true/false instead of the usual 1/0 - we can not be too strict here ;-)
103 if (is_bool($value) or $value === 0 or $value === 1 or $value === '0' or $value === '1') {
104 return (bool)$value;
107 return validate_param($value, $description->type, $description->allownull, 'Invalid external api parameter');
109 } else if ($description instanceof external_single_structure) {
110 if (!is_array($value)) {
111 throw new invalid_return_value_exception('Only arrays accepted.');
113 $result = array();
114 foreach ($description->keys as $key=>$subdesc) {
115 if (!array_key_exists($key, $value)) {
116 if ($subdesc->required == VALUE_REQUIRED) {
117 throw new invalid_return_value_exception('Missing required key in single structure: '.$key);
119 if ($subdesc instanceof external_value) {
120 if ($subdesc->required == VALUE_DEFAULT) {
121 $result[$key] = self::validate_and_cast_values($subdesc, $subdesc->default);
124 } else {
125 $result[$key] = self::validate_and_cast_values($subdesc, $value[$key]);
127 unset($value[$key]);
129 /* Was decided that extra keys should just be ignored and not returned.
130 * if (!empty($value)) {
131 throw new invalid_return_value_exception('Unexpected keys detected in parameter array.');
133 return (object)$result;
135 } else if ($description instanceof external_multiple_structure) {
136 if (!is_array($value)) {
137 throw new invalid_return_value_exception('Only arrays accepted.');
139 $result = array();
140 foreach ($value as $param) {
141 $result[] = self::validate_and_cast_values($description->content, $param);
143 return $result;
145 } else {
146 throw new invalid_return_value_exception('Invalid external api description.');
151 * Set up zend service class
152 * @return void
154 protected function init_zend_server() {
155 parent::init_zend_server();
156 $this->zend_server->setProduction(false); //set to false for development mode
157 //(complete error message displayed into your AMF client)
158 // TODO: add some exception handling
163 class Moodle_Amf_Server extends Zend_Amf_Server{
165 * Raise a server fault
167 * @param string|Exception $fault
168 * @return void
170 public function fault($fault = null, $code = 404)
172 if (!$fault instanceof Exception) {
173 $fault = new Exception($fault);
175 $request = $this->getRequest();
176 // Get the object encoding of the request.
177 $objectEncoding = $request->getObjectEncoding();
179 // create a response object to place the output from the services.
180 $response = $this->getResponse();
182 // set reponse encoding
183 $response->setObjectEncoding($objectEncoding);
185 $responseBody = $request->getAmfBodies();
187 foreach($responseBody as $body){
188 $return = $this->_errorMessage($objectEncoding, $fault->getMessage(),
189 $fault->getMessage(), $fault->getTraceAsString(),$fault->getCode(), $fault->getLine());
190 $responseType = Zend_AMF_Constants::STATUS_METHOD;
193 $responseURI = $body->getResponseURI() . $responseType;
194 $newBody = new Zend_Amf_Value_MessageBody($responseURI, null, $return);
195 $response->addAmfBody($newBody);
197 $response->finalize();
198 echo $response;
202 // TODO: implement AMF test client somehow, maybe we could use moodle form to feed the data to the flash app somehow