]> git.mjollnir.org Git - moodle.git/commitdiff
web service MDL-12886 alpha web service api + alpha user core functions api + alpha...
authorjerome <jerome>
Tue, 13 Jan 2009 07:00:26 +0000 (07:00 +0000)
committerjerome <jerome>
Tue, 13 Jan 2009 07:00:26 +0000 (07:00 +0000)
12 files changed:
lib/moodlewsapi.php [new file with mode: 0644]
user/api.php [new file with mode: 0644]
user/wsapi.php [new file with mode: 0644]
webservice/rest/lib.php [new file with mode: 0644]
webservice/rest/server.php [new file with mode: 0644]
webservice/rest/testclient/config_rest.php [new file with mode: 0644]
webservice/rest/testclient/createuser.php [new file with mode: 0644]
webservice/rest/testclient/getusers.php [new file with mode: 0644]
webservice/rest/testclient/index.php [new file with mode: 0644]
webservice/rest/testclient/lib.php [new file with mode: 0644]
webservice/rest/testclient/return.gif [new file with mode: 0644]
webservice/rest/testclient/style.css [new file with mode: 0644]

diff --git a/lib/moodlewsapi.php b/lib/moodlewsapi.php
new file mode 100644 (file)
index 0000000..e80cf5a
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+/* 
+* Created on 01/12/2008
+ *
+ * Moodle base webservice api
+ *
+ * @author Jerome Mouneyrac
+ */
+
+/**
+ * DO NOT USE ANYTHING FROM THIS FILE - WORK IN PROGRESS
+ */
+abstract class moodle_ws_api {
+
+ protected $descriptions;
+
+    /**
+     * Constructor - We set the description of this API in order to be access by Web service
+     */
+    function __construct () {
+          $this->descriptions = array();
+         
+    }
+
+     /**
+     *
+     *  @param <type> $functionname
+     */
+    function get_function_webservice_description($functionname) {
+        if (key_exists($functionname, $this->descriptions)) {
+            return $this->descriptions[$functionname];
+        }
+        else {
+            return false;
+        }
+    }
+
+    function get_descriptions() {
+        return $this->descriptions;
+    }
+
+}
+?>
diff --git a/user/api.php b/user/api.php
new file mode 100644 (file)
index 0000000..bf10b2a
--- /dev/null
@@ -0,0 +1,218 @@
+<?php
+/**
+ * Created on 01/12/2008
+ *
+ * user core api
+ *
+ * @author Jerome Mouneyrac
+ */
+
+/**
+ * DO NOT USE ANYTHING FROM THIS FILE - WORK IN PROGRESS
+ */
+final class user_api {
+
+
+
+/**
+ * Returns a subset of users (DO NOT COUNT)
+ * @global object $DB
+ * @param string $sort A SQL snippet for the sorting criteria to use
+ * @param string $recordsperpage how many records do pages have
+ * @param string $page which page to return (starts from 0)
+ * @param string $fields A comma separated list of fields to be returned from the chosen table.
+ * @param object $selectioncriteria:
+ *      ->search         string     A simple string to search for
+ *      ->confirmed      bool       A switch to allow/disallow unconfirmed users
+ *      ->exceptions     array(int) A list of IDs to ignore, eg 2,4,5,8,9,10
+ *      ->firstinitial   string     ?
+ *      ->lastinitial    string     ?
+ * @return array|false Array of {@link $USER} objects. False is returned if an error is encountered.
+ */
+static function tmp_namedparams_get_users($sort='firstname ASC', $recordsperpage=999999, $page=0, $fields='*', $selectioncriteria=NULL) {
+    global $DB;
+
+     ///WS: convert array into an object
+       if (!empty($selectioncriteria) && is_array($selectioncriteria))  {
+        $selectioncriteria = (object) $selectioncriteria;
+    }
+
+    $LIKE      = $DB->sql_ilike();
+    $fullname  = $DB->sql_fullname();
+
+    $select = " username <> :guest AND deleted = 0";
+    $params = array('guest'=>'guest');
+
+    if (!empty($selectioncriteria->search)){
+        $selectioncriteria->search = trim($selectioncriteria->search);
+        $select .= " AND ($fullname $LIKE :search1 OR email $LIKE :search2 OR username = :search3)";
+        $params['search1'] = "%".$selectioncriteria->search."%";
+        $params['search2'] = "%".$selectioncriteria->search."%";
+        $params['search3'] = $selectioncriteria->search;
+    }
+
+    if (!empty($selectioncriteria->confirmed)) {
+        $select .= " AND confirmed = 1";
+    }
+
+    if (!empty($selectioncriteria->exceptions)) {
+        list($selectioncriteria->exceptions, $eparams) = $DB->get_in_or_equal($selectioncriteria->exceptions, SQL_PARAMS_NAMED, 'ex0000', false);
+        $params = $params + $eparams;
+        $except = " AND id ".$selectioncriteria->exceptions;
+    }
+
+    if (!empty($selectioncriteria->firstinitial)) {
+        $select .= " AND firstname $LIKE :fni";
+        $params['fni'] = $selectioncriteria->firstinitial."%";
+    }
+    if (!empty($selectioncriteria->lastinitial)) {
+        $select .= " AND lastname $LIKE :lni";
+        $params['lni'] = $selectioncriteria->lastinitial."%";
+    }
+
+    if (!empty($selectioncriteria->extraselect)) {
+        $select .= " AND ".$selectioncriteria->extraselect;
+        if (empty($selectioncriteria->extraparams)){
+            $params = $params + (array)$selectioncriteria->extraparams;
+        }
+    }
+
+    return $DB->get_records_select('user', $select, $params, $sort, $fields, $page, $recordsperpage);
+}
+
+/**
+ * Returns a subset of users
+ *
+ * @uses $CFG
+ * @param bool $get If false then only a count of the records is returned
+ * @param string $search A simple string to search for
+ * @param bool $confirmed A switch to allow/disallow unconfirmed users
+ * @param array(int) $exceptions A list of IDs to ignore, eg 2,4,5,8,9,10
+ * @param string $sort A SQL snippet for the sorting criteria to use
+ * @param string $firstinitial ?
+ * @param string $lastinitial ?
+ * @param string $page ?
+ * @param string $recordsperpage ?
+ * @param string $fields A comma separated list of fields to be returned from the chosen table.
+ * @return object|false|int  {@link $USER} records unless get is false in which case the integer count of the records found is returned. False is returned if an error is encountered.
+ */
+static function tmp_get_users($get=true, $search='', $confirmed=false, array $exceptions=null, $sort='firstname ASC',
+                   $firstinitial='', $lastinitial='', $page='', $recordsperpage='', $fields='*', $extraselect='', array $extraparams=null) {
+    global $DB;
+
+    if ($get && !$recordsperpage) {
+        debugging('Call to get_users with $get = true no $recordsperpage limit. ' .
+                'On large installations, this will probably cause an out of memory error. ' .
+                'Please think again and change your code so that it does not try to ' .
+                'load so much data into memory.', DEBUG_DEVELOPER);
+    }
+
+    $LIKE      = $DB->sql_ilike();
+    $fullname  = $DB->sql_fullname();
+
+    $select = " username <> :guest AND deleted = 0";
+    $params = array('guest'=>'guest');
+
+    if (!empty($search)){
+        $search = trim($search);
+        $select .= " AND ($fullname $LIKE :search1 OR email $LIKE :search2 OR username = :search3)";
+        $params['search1'] = "%$search%";
+        $params['search2'] = "%$search%";
+        $params['search3'] = "$search";
+    }
+
+    if ($confirmed) {
+        $select .= " AND confirmed = 1";
+    }
+
+    if ($exceptions) {
+        list($exceptions, $eparams) = $DB->get_in_or_equal($exceptions, SQL_PARAMS_NAMED, 'ex0000', false);
+        $params = $params + $eparams;
+        $except = " AND id $exceptions";
+    }
+
+    if ($firstinitial) {
+        $select .= " AND firstname $LIKE :fni";
+        $params['fni'] = "$firstinitial%";
+    }
+    if ($lastinitial) {
+        $select .= " AND lastname $LIKE :lni";
+        $params['lni'] = "$lastinitial%";
+    }
+
+    if ($extraselect) {
+        $select .= " AND $extraselect";
+        $params = $params + (array)$extraparams;
+    }
+
+    if ($get) {
+        return $DB->get_records_select('user', $select, $params, $sort, $fields, $page, $recordsperpage);
+    } else {
+        return $DB->count_records_select('user', $select, $params);
+    }
+}
+
+/**
+ * Creates an User with given information. Required fields are:
+ * -username
+ * -idnumber
+ * -firstname
+ * -lastname
+ * -email
+ *
+ * And there's some interesting fields:
+ * -password
+ * -auth
+ * -confirmed
+ * -timezone
+ * -country
+ * -emailstop
+ * -theme
+ * -lang
+ * -mailformat
+ *
+ * @param assoc array or object $user
+ *
+ * @return userid or thrown exceptions
+ */
+static function tmp_create_user($user) {
+       global $CFG, $DB;
+ ///WS: convert user array into an user object
+       if (is_array($user))  {
+        $user = (object) $user;
+    }
+    
+ ///check password and auth fields
+       if (!isset($user->password)) {
+        $user->password = '';
+    }
+       if (!isset($user->auth)) {
+        $user->auth = 'manual';
+    }
+
+       $required = array('username','firstname','lastname','email');
+       foreach ($required as $req) {
+               if (!isset($user->{$req})) {
+            throw new moodle_exception('missingerequiredfield');
+        }
+       }
+
+       $record = create_user_record($user->username, $user->password, $user->auth);
+       if ($record) {
+               $user->id = $record->id;
+               if ($DB->update_record('user',$user)) {
+            return $record->id;
+        } else {
+            $DB->delete_record('user',array('id' => $record->id));
+        }
+       }
+       throw new moodle_exception('couldnotcreateuser');
+}
+
+}
+
+
+
+
+
+?>
diff --git a/user/wsapi.php b/user/wsapi.php
new file mode 100644 (file)
index 0000000..8c91fdc
--- /dev/null
@@ -0,0 +1,63 @@
+<?php
+/**
+ * Created on 05/03/2008
+ *
+ * users webservice api
+ *
+ * @author Jerome Mouneyrac
+ */
+require_once(dirname(dirname(__FILE__)) . '/lib/moodlewsapi.php');
+
+/**
+ * WORK IN PROGRESS
+ */
+final class user_ws_api extends moodle_ws_api {
+
+    /**
+     * Constructor - We set the description of this API in order to be access by Web service
+     */
+    function __construct () {
+          $this->descriptions = array();
+       ///The desciption of the web service
+       ///
+       ///'wsparams' and 'return' are used to described the web services to the end user (can build WSDL file from these information)
+       ///'paramorder' is used internally by developers implementing a new protocol. It contains the params of the called function in a good order and with default value
+       ///
+       ///Note: web services param names have not importance. However 'paramorder' must match the function params order.
+       ///And all web services param names defined into 'wsparams' should be included into 'paramorder' (otherwise they will not be used)
+       ///
+       ///How to define an object/array attribut web service parameter: 'any object/array name' + _ + 'attribut/key name'. 'attribut/key name' must match the real attribut name.
+       ///e.g: a function has a parameter that is an object with a attribut named 'username'. You will need to declare 'anyobjectname_username' into 'wsparams'.
+       ///     Then 'paramorder'=> array('anyobjectname' => array('username' => ...));
+       ///
+       ///TODO: manage object->object parameter
+          $this->descriptions['tmp_get_users']   = array( 'wsparams' => array('search'=> PARAM_RAW),
+                                                      'return' => array('user', array('id' => PARAM_RAW, 'auth' => PARAM_RAW, 'confirmed' => PARAM_RAW, 'username' => PARAM_RAW, 'idnumber' => PARAM_RAW,
+                                                                                    'firstname' => PARAM_RAW, 'lastname' => PARAM_RAW, 'email' => PARAM_RAW, 'emailstop' => PARAM_RAW,
+                                                                                    'lang' => PARAM_RAW, 'theme' => PARAM_RAW, 'timezone' => PARAM_RAW, 'mailformat' => PARAM_RAW)),
+                                                      'paramorder' => array('get' => true, 'search' => '', 'confirmed' => false, 'exceptions' =>null, 'sort' => 'firstname ASC',
+                                                                          'firstinitial' => '', 'lastinitial' => '', 'page' => '', 'recordsperpage' => '',
+                                                                          'fields' => 'id, auth, confirmed, username, idnumber, firstname, lastname, email, emailstop, lang, theme, timezone, mailformat',
+                                                                          'extraselect' => '', 'extraparams' => null));
+
+          $this->descriptions['tmp_create_user'] = array( 'wsparams' => array('user:username'=> PARAM_RAW, 'user:firstname'=> PARAM_RAW, 'user:lastname'=> PARAM_RAW, 'user:email'=> PARAM_RAW, 'user:password'=> PARAM_RAW),
+                                                      'return' => array('userid', PARAM_RAW),
+                                                      'paramorder' => array('user' => array('username' => null, 'firstname' => null, 'lastname'=> null, 'email'=> null, 'password'=>'')));
+
+          $this->descriptions['tmp_namedparams_get_users']   = array( 'wsparams' => array('selectioncriteria:search'=> PARAM_RAW),
+                                                      'return' => array('user', array('id' => PARAM_RAW, 'auth' => PARAM_RAW, 'confirmed' => PARAM_RAW, 'username' => PARAM_RAW, 'idnumber' => PARAM_RAW,
+                                                                                    'firstname' => PARAM_RAW, 'lastname' => PARAM_RAW, 'email' => PARAM_RAW, 'emailstop' => PARAM_RAW,
+                                                                                    'lang' => PARAM_RAW, 'theme' => PARAM_RAW, 'timezone' => PARAM_RAW, 'mailformat' => PARAM_RAW)),
+                                                      'paramorder' => array('sort' => 'firstname ASC', '$recordsperpage' => 999999, 'page' => 0,
+                                                                            'fields' => 'id, auth, confirmed, username, idnumber, firstname, lastname, email, emailstop, lang, theme, timezone, mailformat',
+                                                                            'selectioncriteria' => array('search' => '')));
+    }
+
+
+}
+
+
+
+
+
+?>
diff --git a/webservice/rest/lib.php b/webservice/rest/lib.php
new file mode 100644 (file)
index 0000000..7cd42b7
--- /dev/null
@@ -0,0 +1,127 @@
+<?php
+/**
+ *
+ * Rest library
+ *
+ * @author Jerome Mouneyrac, Ferran Recio, David Castro Garcia
+ */
+
+/**
+ *
+ * @author Jerome Mouneyrac
+ * @global object $CFG
+ * @param string $rest_arguments example: /mod/forum/get_discussion
+ * @return string xml object
+ */
+function call_moodle_function ($rest_arguments) {
+    global $CFG;
+///REST params conversion
+    $functionname = substr($rest_arguments,strrpos($rest_arguments,"/")+1); //retrieve the function name (it's located after the last '/') in $rest_arguments
+                                                                            //$rest_argument
+    $apipath = substr($rest_arguments,0, strlen($rest_arguments) - strlen($functionname)); //api path is the other part of $rest_arguments
+
+    $classname = str_replace('/', '_', $apipath); // convert '/' into '_' (e.g. /mod/forum/ => _mod_forum_)
+    $classname = substr($classname,1, strlen($classname) - 1); //remove first _ (e.g. _mod_forum => mod_forum)
+    $coreclassname = $classname."api";
+    $classname .= 'ws_api';
+
+///these three next lines can be generic => create a function
+    require_once($CFG->dirroot.$apipath.'wsapi.php');
+    $api = new $classname();
+
+    $description = $api->get_function_webservice_description($functionname); //retrieve the web service description for this function
+
+///This following line is only REST protocol
+    $params = retrieve_params ($description); //retrieve the REST params
+
+///Generic part to any protocols
+    if ($params === false) {
+        //return an error message, the REST params doesn't match with the web service description
+    }
+    require_once($CFG->dirroot.$apipath.'api.php');
+    $res = call_user_func_array  ( $coreclassname.'::'.$functionname, $params);
+
+///Transform result into xml in order to send the REST response
+    $return =  mdl_conn_rest_object_to_xml ($res,$description['return'][0]);
+
+       return "<Result>$return</Result>";
+}
+
+
+/**
+ *
+ * @author Jerome Mouneyrac
+ * @param <type> $description
+ * @return <type>
+ */
+function retrieve_params ($description) {
+    $params = $description['paramorder'];
+    //retrieve REST param matching the description
+
+    foreach ($description['wsparams'] as $paramname => $paramtype) {
+        varlog('--retrieve_params--');
+        varlog($paramname);
+        $value = optional_param($paramname,null,$paramtype);
+        varlog($value);
+        if (!empty($value)) {
+            $fullstopposition = strrpos($paramname,":");
+            varlog(substr($paramname,0,$fullstopposition));
+            varlog(substr($paramname,$fullstopposition+1, strlen($paramname) - $fullstopposition));
+            //case: param is an object/array
+            if  (!empty($fullstopposition)) {
+                    $params[substr($paramname,0,$fullstopposition)][substr($paramname,$fullstopposition+1, strlen($paramname) - $fullstopposition)] = $value;
+            } else {
+                 $params[$paramname] = $value;
+            }
+        }
+    }
+    varlog($params);
+    return $params;
+}
+
+/**
+ * auxiliar function for simplexml_object_to_xml
+ * @author Ferran Recio, David Castro Garcia
+ * @param $obj
+ * @param $tag
+ * @param $atts assoc array (key => value)
+ * @return string
+ */
+function mdl_conn_rest_object_to_xml ($obj, $tag,$atts=false) {
+       $res = '';
+       $tag_atts = '';
+       if ($atts) {
+               $main_atts = array();
+               foreach ($atts as $att=>$val) {
+                       $main_atts[] = "$att=\"".urlencode($val)."\"";
+               }
+               if (count($main_atts)) $tag_atts = ' '.implode(' ',$main_atts);
+       }
+
+       //if is an object
+       if (is_object($obj)) {
+               $parts = get_object_vars($obj);
+               foreach ($parts as $tag2 => $val) {
+                       $res.= mdl_conn_rest_object_to_xml ($val, $tag2);
+               }
+               return "<$tag$tag_atts>\n$res</$tag>\n";
+       }
+       //if it's an array all elements will be inside te same tag but with a new atribute key
+       if (is_array($obj)){
+               if (!$atts) $atts = array();
+               //we came from another array
+               if (isset($atts['keys'])) $atts = array();
+               foreach ($obj as $key=>$val) {
+                       $array_atts = $atts;
+                       $array_atts['key'] = $key;
+                       $res.= mdl_conn_rest_object_to_xml ($val, $tag,$array_atts);
+               }
+               return $res;
+       }
+       //any other type, just encapsule it
+       $obj = htmlentities($obj);
+       return  "<$tag$tag_atts>$obj</$tag>\n";
+
+}
+
+?>
\ No newline at end of file
diff --git a/webservice/rest/server.php b/webservice/rest/server.php
new file mode 100644 (file)
index 0000000..5f84d7a
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+/**
+ * Created on 10/14/2008
+ *
+ * REST Moodle server.
+ *
+ * NOTE: for this first implementation, REST requires implicit url encoded params.
+ * It uses function get_file_argument to get them.
+ *
+ * @author Jerome Mouneyrac
+ * @author Ferran Recio
+ * @author David Castro Garcia
+ */
+
+require_once(dirname(dirname(dirname(__FILE__))) . '/config.php');
+require_once('lib.php');
+
+//retrieve path and function name from the URL
+$rest_arguments = get_file_argument('server.php');
+
+header ("Content-type: text/xml");
+
+echo call_moodle_function($rest_arguments);
+?>
\ No newline at end of file
diff --git a/webservice/rest/testclient/config_rest.php b/webservice/rest/testclient/config_rest.php
new file mode 100644 (file)
index 0000000..e070aad
--- /dev/null
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Created on 10/17/2008
+ *
+ * Rest Test Client configuration file
+ *
+ * @author David Castro Garcia
+ * @author Ferran Recio Calderó
+ * @author Jerome Mouneyrac
+ *
+ */
+
+require_once("../../../config.php");
+require_once ('lib.php');
+$CFG->serverurl = $CFG->wwwroot.'/webservice/rest/server.php';
+if (!function_exists('curl_init')) die ('CURL library was not found!');
+
+?>
\ No newline at end of file
diff --git a/webservice/rest/testclient/createuser.php b/webservice/rest/testclient/createuser.php
new file mode 100644 (file)
index 0000000..2b9344c
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+/**
+ * Created on 10/17/2008
+ *
+ * Rest Test Client
+ *
+ * @author David Castro Garcia
+ * @author Ferran Recio Calderó
+ * @author Jerome Mouneyrac
+ */
+
+require_once ('config_rest.php');
+start_interface("Create A User");
+
+$ch = curl_init();
+
+$data['user:username'] = "jerome4";
+$data['user:firstname'] = "jerome4";
+$data['user:lastname'] = "jerome4";
+$data['user:email'] = "jerome4@mouneyrac.com";
+
+var_dump($data);
+
+curl_setopt($ch, CURLOPT_URL, $CFG->serverurl.'/user/tmp_create_user');
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+curl_setopt($ch, CURLOPT_POST, 1);
+curl_setopt($ch, CURLOPT_POSTFIELDS, format_postdata($data));
+
+$out = curl_exec($ch);
+
+$res = basicxml_xml_to_object($out);
+
+show_object($res->userid);
+
+show_xml ($out);
+
+end_interface();
+?>
\ No newline at end of file
diff --git a/webservice/rest/testclient/getusers.php b/webservice/rest/testclient/getusers.php
new file mode 100644 (file)
index 0000000..5287b94
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Created on 10/17/2008
+ * 
+ * Rest Test Client
+ *
+ * @author David Castro Garcia
+ * @author Ferran Recio Calderó
+ * @author Jerome Mouneyrac
+ */
+
+require_once ('config_rest.php');
+
+$params = array('search');
+
+foreach ($params as $param) {
+       $$param = (isset($_POST[$param]))?$_POST[$param]:'';
+}
+
+start_interface("List of Users");
+?>
+
+<form action="getusers.php" method="post">
+<table border="0">
+    <tr><td>Search: </td><td><input type="text" name="search" value="<?php echo $search; ?>"/></td></tr>
+    <tr><td></td><td><input type="submit" value="Find Users"></td></tr>
+</table>
+</form>
+
+<?php
+
+if ($search) {
+    $data['search'] = $search;
+
+    var_dump($CFG->serverurl.'/user/tmp_get_users');
+
+    $ch = curl_init();
+    curl_setopt($ch, CURLOPT_URL, $CFG->serverurl.'/user/tmp_get_users');
+    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+    curl_setopt($ch, CURLOPT_POST, 1);
+    curl_setopt($ch, CURLOPT_POSTFIELDS, format_postdata($data));
+    $out = curl_exec($ch);
+
+    $res = basicxml_xml_to_object($out);
+
+    show_object($res->user,2,'auth');
+
+    show_xml ($out);
+} else {
+    echo "<p>Fill the form first</p>";
+}
+
+end_interface();
+
+?>
diff --git a/webservice/rest/testclient/index.php b/webservice/rest/testclient/index.php
new file mode 100644 (file)
index 0000000..42e22c2
--- /dev/null
@@ -0,0 +1,27 @@
+<?php
+/**
+ * Created on 10/17/2008
+ * 
+ * Rest Test Client
+ *
+ * @author David Castro Garcia
+ * @author Ferran Recio Calderó
+ * @author Jerome Mouneyrac
+ */
+
+require_once ('config_rest.php');
+
+start_interface (false);
+
+$links = array( array('getusers.php','getusers()'),
+                array('createuser.php','createuser()'),
+                array('namedparams_get_users.php','namedparams_get_users()'));
+
+echo '<ul>';
+foreach ($links as $link) {
+    echo '<li><a href="'.$link[0].'">'.$link[1].'</a></li>';
+}
+echo '</ul>';
+
+end_interface(false);
+?>
\ No newline at end of file
diff --git a/webservice/rest/testclient/lib.php b/webservice/rest/testclient/lib.php
new file mode 100644 (file)
index 0000000..8d99273
--- /dev/null
@@ -0,0 +1,224 @@
+<?php
+/**
+ * Created on 10/17/2008
+ * 
+ * Rest Test Client Suport Library
+ *
+ * @author David Castro Garcia
+ * @author Ferran Recio Calderó
+ */
+
+//--- interface helpers ---
+
+/**
+ * starts the interface
+ */
+function start_interface ($title="&nbsp;") {
+       $title2 = ($title)?$title:"&nbsp;";
+       echo '<html><head>';
+       echo "<title>Moodle Webservice Rest Test Client</title>";
+       echo '<link rel="stylesheet" href="style.css" type="text/css">';
+       echo '</head><body>';
+       echo '<div class="head"><h1>Moodle Webservice Rest Test Client</h1>';
+       echo "<h3>$title2</h3>";
+       echo '</div>';
+       echo '<div class="content">';
+       if ($title) echo '<p class="return"><a href="index.php"><img src="return.gif" border="0"/></a></p>';
+}
+
+/**
+ * end interface
+ * 
+ * @param bool $ret=true: show return button
+ */
+function end_interface ($ret = true) {
+       if ($ret) echo '<p class="return"><a href="index.php"><img src="return.gif" border="0"/></a></p>';
+       echo '</div>';
+       echo '<div class="footer">Created by David Castro i Ferran Recio for Moodle Webservices</div>';
+       echo '</body></html>';
+}
+
+/**
+ * print XML div area
+ * 
+ * @param string $xml
+ * 
+ */
+function show_xml ($xml) {
+       echo '<div class="xmlshow">';
+       echo '<a onClick="document.getElementById(\'toogleme\').style.display = ' .
+                       '(document.getElementById(\'toogleme\').style.display!=\'none\')?\'none\':\'\';">Hide/Show XML</a>';
+       echo "<div style=\"display:none;\" id=\"toogleme\">";
+       echo '<pre>';echo htmlentities($xml);echo '</pre>';
+       echo "</div>";
+       echo "</div>";
+}
+
+/**
+ * format post data
+ */
+function format_postdata ($data) {
+       $o="";
+       foreach ($data as $k=>$v) {
+               $o.= "$k=".rawurlencode($v)."&";
+       }
+       $post_data=substr($o,0,-1);
+       return $post_data;
+}
+
+/**
+ * shows an object in list format
+ * 
+ * @param mixed $obj
+ * @param integer $cols: number of colums
+ * @ string string $check=false: if this attribute is not present, the $obj is ans error
+ * 
+ */
+function show_object ($obj,$cols=1,$check=false) {
+       if (!is_array($obj)) $obj = array($obj);
+       echo '<ul class="results">';
+       foreach ($obj as $r) {
+               
+               if ($check && (!isset($r->$check) || $r->$check==-1)) {
+                       echo '<li class="error">';
+                       echo "EMPTY ROW!";
+               } else {
+                       if (is_object($r)) {
+                               echo '<li class="element">';
+                               $text = array();
+                               $parts = get_object_vars($r);
+                               $num = 1;
+                               $currline = '';
+                               foreach ($parts as $key => $val) {
+                                       $currline.= "<span class=\"resultval\"><b>$key:</b> <i>$val</i></span>, ";
+                                       if ($num >= $cols) {
+                                               $currline=substr($currline,0,-2);
+                                               $text[] = $currline;
+                                               $currline = '';
+                                               $num = 0;
+                                       }
+                                       $num++;
+                               }
+                               echo implode('<br/>',$text);
+                       } else {
+                               if ($r==-1 || !$r) {
+                                       echo '<li class="error">';
+                                       echo "EMPTY ROW!";
+                               } else {
+                                       echo '<li class="element">';
+                                       echo "<span class=\"resultval\"><b>Returned Value:</b> <i>$r</i></span>";
+                               }
+                       }
+               }
+               echo '</li>';
+       }
+       echo '</ul>';
+}
+
+
+//---- XML simple parser ----
+//this code was donated by Ferran Recio
+
+/**
+ * convert a simple xml into php object
+ * 
+ * @author ferran recio
+ * 
+ * @param String $xml
+ * 
+ * @return mixed
+ */
+function basicxml_xml_to_object ($xml) {
+       $xml=utf8_encode($xml);
+       
+       //create the parser
+       $parser = xml_parser_create ();
+       xml_set_default_handler ($parser,'basicxml_xml_to_object_aux');
+       
+       $values = array();
+       $index = array();
+       xml_parse_into_struct($parser,$xml,$values,$index);
+       
+       //print_object($values);
+       //print_object($index);
+       
+       //just simplexml tag (disabled)
+       //if (strtolower($values[0]['tag']) != 'basicxml') return false;
+       //if (strtolower($values[count($values)-1]['tag']) != 'basicxml') return false;
+       
+       $res = basicxml_xml_to_object_aux ($values);
+       //omit the first tag
+       $parts = array_keys(get_object_vars($res));
+       $key = $parts[0];
+       return $res->$key;
+}
+
+/**
+ * auxiliar function to basicxml_xml_to_object
+ * 
+ * @author ferran recio
+ * 
+ * @param mixed $values
+ * 
+ * @return mixed
+ */
+function basicxml_xml_to_object_aux ($values) {
+       
+       if (!is_array($values)) return false;
+       //print_object ($values);
+       $currset = array();
+       $search = false;
+       
+       foreach ($values as $value) {
+               $tag = strtolower($value['tag']);
+               //if we are acomulating, just acomulate it
+               if ($search) {
+                       //if it closes a tag, we just stop searching
+                       if ($tag == $search && $value['type']=='close') {
+                               //recursivity
+                               $obj2 = basicxml_xml_to_object_aux ($currset);
+                               //search cleaning
+                               $search = false;
+                               //add to result
+                               if (isset($res->{$tag})){
+                                       if (is_array($res->{$tag})){
+                                                       $res->{$tag}[] = $obj2;
+                                       } else {
+                                               $res->{$tag} = array($res->{$tag},$obj2);
+                                       }
+                               } else {
+                                       $res->{$tag} = $obj2;
+                               }
+                       } else {
+                               //we are searching. If it's cdada, pass it throw
+                               if ($value['type']=='cdata') continue;
+                               //if isn't cdata, put it in the set and continue searching
+                               //(because isn't the close we're searching)
+                               $currset[] = $value;
+                       }
+               } else {
+                       //walking the xml
+                       if ($value['type']=='open'){
+                               //on open, let's search on it
+                               $currset = array();
+                               $search = $tag;
+                       } else {
+                               //if it's complete just save it
+                               if ($value['type']=='complete') {
+                                       $val = html_entity_decode($value['value']);
+                                       if (isset($res->{$tag})){
+                                               if (is_array($res->{$tag})){
+                                                               $res->{$tag}[] = $val;
+                                               } else {
+                                                       $res->{$tag} = array($res->{$tag},$val);
+                                               }
+                                       } else {
+                                               $res->{$tag} = $val;
+                                       }
+                               }
+                       }
+               }
+       }
+       return $res;
+}
+?>
\ No newline at end of file
diff --git a/webservice/rest/testclient/return.gif b/webservice/rest/testclient/return.gif
new file mode 100644 (file)
index 0000000..ff918c0
Binary files /dev/null and b/webservice/rest/testclient/return.gif differ
diff --git a/webservice/rest/testclient/style.css b/webservice/rest/testclient/style.css
new file mode 100644 (file)
index 0000000..ddd466b
--- /dev/null
@@ -0,0 +1,57 @@
+body {
+       background-color: #FAFFFF;;
+}
+
+.xmlshow {
+       background-color: #DDDDFF;
+       padding:20px;
+}
+
+.xmlshow div {
+       height: 200px;
+       overflow: auto;
+       padding: 20px;
+       background-color: #EEEEFF;
+}
+
+.head, .footer {
+       background-color: #AAAAFF;
+       text-align: center;
+}
+
+.footer {
+       font-size: small;
+       padding: 10px;
+}
+
+.content {
+       padding-left: 20px;
+       padding-right: 20px;
+}
+
+.results li{
+       margin-bottom:20px;
+       padding: 10px;
+       list-style-type: square;
+}
+
+.element {
+       background-color: #CCCCFF;
+}
+
+.element span:hover{
+       background-color:#DDDDFF;
+}
+
+.error {
+       background-color: #FFCCCC;
+}
+
+.return a, .return a:hover, .return a:visited{
+       color:#0000DD;
+}
+
+h1, h2 {
+       margin:0px;
+       padding:5px;
+}
\ No newline at end of file