moodle/webservice/amf/locallib.php

228 lines
8.3 KiB
PHP

<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* AMF web service implementation classes and methods.
*
* @package webservice_amf
* @copyright 2009 Petr Skodak
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once("$CFG->dirroot/webservice/lib.php");
require_once( "{$CFG->dirroot}/webservice/amf/introspector.php");
require_once 'Zend/Amf/Server.php';
/**
* Exception indicating an invalid return value from a function.
*
* Used when an externallib function does not return values of the expected structure.
*
* @package webservice_amf
* @copyright 2010 Jamie Pratt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class invalid_return_value_exception extends moodle_exception {
/**
* Constructor
*
* @param string $debuginfo some detailed information
*/
function __construct($debuginfo=null) {
parent::__construct('invalidreturnvalue', 'webservice_amf', '', $debuginfo, $debuginfo);
}
}
/**
* AMF service server implementation.
*
* @package webservice_amf
* @copyright 2009 Petr Skodak
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class webservice_amf_server extends webservice_zend_server {
/**
* Contructor
*
* @param integer $authmethod authentication method - one of WEBSERVICE_AUTHMETHOD_*
*/
public function __construct($authmethod) {
parent::__construct($authmethod, 'Moodle_Amf_Server');
$this->wsname = 'amf';
}
/**
* Load virtual class needed for Zend api
*/
protected function init_service_class(){
parent::init_service_class();
//allow access to data about methods available.
$this->zend_server->setClass( "MethodDescriptor" );
MethodDescriptor::$classnametointrospect = $this->service_class;
}
/**
* Get the generated web service function code.
*
* @param stdClass $function contains function name and class name
* @param array $params all the function parameters
* @return string the generate web service function code
*/
protected function service_class_method_body($function, $params){
//cast the param from object to array (validate_parameters except array only)
$castingcode = '';
if ($params){
$paramstocast = explode(',', $params);
foreach ($paramstocast as $paramtocast) {
$paramtocast = trim($paramtocast);
$castingcode .= $paramtocast .
'=webservice_zend_server::cast_objects_to_array('.$paramtocast.');';
}
}
$externallibcall = $function->classname.'::'.$function->methodname.'('.$params.')';
$descriptionmethod = $function->methodname.'_returns()';
$callforreturnvaluedesc = $function->classname.'::'.$descriptionmethod;
return $castingcode .
' return webservice_amf_server::validate_and_cast_values('.$callforreturnvaluedesc.', '.$externallibcall.');';
}
/**
* Validates submitted value, comparing it to a description. If anything is incorrect
* invalid_return_value_exception is thrown. Also casts the values to the type specified in
* the description.
*
* @param external_description $description description of parameters or null if no return value
* @param mixed $value the actual values
* @return mixed params with added defaults for optional items
* @throws invalid_return_value_exception
*/
public static function validate_and_cast_values($description, $value) {
if (is_null($description)){
return;
}
if ($description instanceof external_value) {
if (is_array($value) or is_object($value)) {
throw new invalid_return_value_exception('Scalar type expected, array or object received.');
}
if ($description->type == PARAM_BOOL) {
// special case for PARAM_BOOL - we want true/false instead of the usual 1/0 - we can not be too strict here ;-)
if (is_bool($value) or $value === 0 or $value === 1 or $value === '0' or $value === '1') {
return (bool)$value;
}
}
return validate_param($value, $description->type, $description->allownull, 'Invalid external api parameter');
} else if ($description instanceof external_single_structure) {
if (!is_array($value)) {
throw new invalid_return_value_exception('Only arrays accepted.');
}
$result = array();
foreach ($description->keys as $key=>$subdesc) {
if (!array_key_exists($key, $value)) {
if ($subdesc->required == VALUE_REQUIRED) {
throw new invalid_return_value_exception('Missing required key in single structure: '.$key);
}
if ($subdesc instanceof external_value) {
if ($subdesc->required == VALUE_DEFAULT) {
$result[$key] = self::validate_and_cast_values($subdesc, $subdesc->default);
}
}
} else {
$result[$key] = self::validate_and_cast_values($subdesc, $value[$key]);
}
unset($value[$key]);
}
return (object)$result;
} else if ($description instanceof external_multiple_structure) {
if (!is_array($value)) {
throw new invalid_return_value_exception('Only arrays accepted.');
}
$result = array();
foreach ($value as $param) {
$result[] = self::validate_and_cast_values($description->content, $param);
}
return $result;
} else {
throw new invalid_return_value_exception('Invalid external api description.');
}
}
/**
* Set up zend service class
*/
protected function init_zend_server() {
parent::init_zend_server();
$this->zend_server->setProduction(false); //set to false for development mode
//(complete error message displayed into your AMF client)
}
}
/**
* Zend Amf server with a different fault management
*
* @package webservice_amf
* @copyright 2010 Jamie Pratt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class Moodle_Amf_Server extends Zend_Amf_Server{
/**
* Raise a server fault
*
* @param string|Exception $fault
* @param int $code fault code
*/
public function fault($fault = null, $code = 404)
{
if (!$fault instanceof Exception) {
$fault = new Exception($fault);
}
$request = $this->getRequest();
// Get the object encoding of the request.
$objectEncoding = $request->getObjectEncoding();
// create a response object to place the output from the services.
$response = $this->getResponse();
// set response encoding
$response->setObjectEncoding($objectEncoding);
$responseBody = $request->getAmfBodies();
foreach($responseBody as $body){
$return = $this->_errorMessage($objectEncoding, $fault->getMessage(),
$fault->getMessage(), $fault->getTraceAsString(),$fault->getCode(), $fault->getLine());
$responseType = Zend_AMF_Constants::STATUS_METHOD;
$responseURI = $body->getResponseURI() . $responseType;
$newBody = new Zend_Amf_Value_MessageBody($responseURI, null, $return);
$response->addAmfBody($newBody);
}
$response->finalize();
echo $response;
}
}