3.0 Create a Web Service

advertisement
Creating a Moodle web service with mNet, August 2007
The Open University
Creating a Moodle web service with mNet
1.0 Introduction ............................................................................................ 2
2.0 Create Peer to Peer Network ........................................................................ 3
3.0 Create a Web Service ................................................................................. 4
3.1 Create Service ...................................................................................... 4
3.2 Enable service through mNet .................................................................... 4
3.3 Register Service .................................................................................... 5
3.4 Publish service ...................................................................................... 5
3.5 Consume Service ................................................................................... 5
Conclusion ................................................................................................... 7
Appendix A................................................................................................... 8
Appendix B .................................................................................................. 11
Appendix C.................................................................................................. 14
Appendix D ................................................................................................. 15
Page 1 of 18
Creating a Moodle web service with mNet, August 2007
The Open University
1.0 Introduction
This documentation comes as part of the Open University Offline Moodle project
which is aimed at providing the facility to synchronise one Moodle application with
another.
Web Services are used where it is necessary to call methods of a remote application
as though they are available in the local application. This is necessary within the
Offline Moodle context because both Moodle instances must share data frequently
and the data must come from many different locations within the Moodle
infrastructure.
The Mobile Network (mNet) feature of Moodle has been chosen to provide web
services for Offline Moodle however this feature is relatively new in the latest 1.9
release. For this reason there is not currently any documentation as to how to
implement a web service using the mNet architecture.
A basic web service has now been created using mNet and this documentation will
explain how web services were enabled for the Offline Moodle project
Page 2 of 18
Creating a Moodle web service with mNet, August 2007
The Open University
2.0 Create Peer to Peer Network
2.1 Install Moodles
To implement a web service two applications must talk to each other. For the
purposes of this document our 2 applications will be
1. Moodle Offline
2. Moodle Hub
Moodle Offline is the name given to an instance of Moodle operating on a desktop
personal computer.
Moodle Hub is the name given to an instance of Moodle operating on a hosted server
environment.
Details on how to install Moodle as well as how to set up an environment to run it can
be found at http://docs.moodle.org/en/Installing_Moodle.
2.2 Enable mNet
Both instances must have mNet enabled and trust each other. The procedure for
achieving this is at http://docs.moodle.org/en/Moodle_Network. We enabled mNet
to the point where Single Sign On was working and we could roam around both sites
as one user.
Page 3 of 18
Creating a Moodle web service with mNet, August 2007
The Open University
3.0 Create a Web Service
mNet defines a process for enabling web services. This section refers heavily to the
guidance given at http://docs.moodle.org/en/Web_Services_API. Enabling a new
service involves a few shorts steps:
1. Create Service: create a service for mNet to use.
2. Enable service through mNet: tell mNet how to use your new service
3. Register Service: Let Moodle and mNet know the service is available
4. Publish Service: Allow the service to be used by selected trusted applications
5. Consume Service: Get a trusted application to call and make use of the
service you just created and published
3.1 Create Service
mNet requires that a proxy class be defined that exposes the web services. This class
must adhere to the mNet interface specification and must be in place for Moodle to
recognise any methods that must be exposed. It is through these methods that you
can expose the inner methods of Moodle as you require.
To create our class we simply used the auth/mnet/auth.php file as a template.
Appendix A contains the code for our file located at synch/mnet/synch.php. The
class simply exposes two methods. The methods you wish to expose must be listed in
the method mnet_publishes as shown. This information is used later to register with
mNet that these methods are available as part of a web service.
Once the class and its methods have been ‘registered’ in Moodle they will become
available for publishing. Only when they are published can the be used, or consumed.
Note: You will notice remnants of the auth class within the code. I leave them there
as reminders of what else can be done.
3.2 Enable service through mNet
This process involves incorporating our class into the mNet framework so that mNet
knows what to do when methods from our class get called. Appendix B contains the
code to add to the core mNet files and those files used by the admin feature in
admin/mnet.
Page 4 of 18
Creating a Moodle web service with mNet, August 2007
The Open University
3.3 Register Service
Now that we have made alterations to the mNet code, it will now know where to look
when the service and its methods are called. At this point the service itself is not
recognised within Moodle.
Our next step is to go to the admin home page which is easily reached from the
‘notifications’ option of the ‘Site Administration’ menu. This calls the methods we
updated in the previous step and should find our new class. It will then add the
methods to the database. The table it changes is ‘mnet_rpc’. If you are interested
you should now see the new methods as the most recent additions to this table.
You will notice that the help field is empty. This is because we have been lazy and
not added comments to the methods. If we do these will also be recorded in the help
field and made available to applications that ask Moodle which methods it exposes.
3.4 Publish service
Even though Moodle is now aware that these methods actually exist, it is still not
possible to call them as web services. The final step we have left is to publish the
service. This involves telling Moodle which of its trusted hosts are allowed to use this
service.
Now we’ve been a bit naughty and missed one step of adding the language files. Not
to worry we didn’t need them until now. Appendix C contains the code for the file
lang/en_utf8/synch_mnet.php. This is required to provide the text to explain how to
publish the new service.
In the same way you enabled the services to allow single sign on, you will enable the
synch service. On the ’Site Administration’ menu go to networking/peers and click on
the peer that you wish to have access to the service and click on the services tab
when it loads. At the bottom of the page you should now see a section named
‘Synch(test)’ along with publish and subscribe options. Tick them both to enable the
service.
3.5 Consume Service
To consume a web service is use to it. So let’s go and check it’s working. Appendix D
has code for a very simple file that shows how the new service works. Of course this
is as simple as you can get but I am just trying to show you enough to get going.
Page 5 of 18
Creating a Moodle web service with mNet, August 2007
The Open University
Create the file where you like as long as it’s within the Moodle framework code.
Correct the link to the config.php file. Then navigate to the file you just created in a
browser. You will find initially that the webservice that is called is the local service,
the one within the Moodle application the file resides in. this just proves whether the
service is enabled locally.
Connecting to a remote service is as simple as setting the correct host id. An example
of this is included in the file but is commented out. Just ensure you use the correct
id. Either look in the database or check the url of the peers you can connect to via
the Network Servers block on your home page for the host id. (See the
documentation re setting up mnet referenced earlier).
If it doesn’t work and you get errors check that the new Synch service is enabled on
both applications. I enabled it for both all hosts and the trusted client on each
instance. Until I know the service better I have left it open like this.
Note: unit tests have been created but they were too cumbersome to include in this
document. To find out more just email me at c.chambers@open.ac.uk
Page 6 of 18
Creating a Moodle web service with mNet, August 2007
The Open University
Conclusion
So there you have it. The actual service you have enabled doesn’t do much but that’s
not the point. You now have the tools to add as many as you want and do anything
you like. The examples I have given just show the basic way to create new classes
and methods and pass parameters back and forth between each. I have tested the
following types:
 String
 Integer
 Double/float
 Array
 Object (These are handled as arrays)
I haven’t tested any further types but I understand it simply follows the xmlrpc spec
at http://www.xmlrpc.com/spec. This reference is useful for a more thorough
understanding of the xml rpc standards that the catalyst guys who built mNet are
adhering to.
Page 7 of 18
Creating a Moodle web service with mNet, August 2007
The Open University
Appendix A
<?php
if (!defined('MOODLE_INTERNAL')) {
die('Direct access to this script is forbidden.');
/// It must be included from a
Moodle page
}
//require_once($CFG->libdir.'/authlib.php');
/**
* Moodle Network authentication plugin.
*/
class synch_plugin_mnet {
/**
* Constructor.
*/
function __construct() {
/*
$this->authtype = 'mnet';
$this->config = get_config('auth/mnet');
*/
}
/**
* Provides the allowed RPC services from this class as an array.
* @return array Allowed RPC services.
*/
function mnet_publishes() {
$sso_idp = array();
$sso_idp['name']
= 'synch_test'; // Name & Description go in lang file
$sso_idp['apiversion'] = 1;
$sso_idp['methods']
= array('test', 'testResponse');
Page 8 of 18
Creating a Moodle web service with mNet, August 2007
The Open University
return array($sso_idp);
}
function test(){
//return 'test method is working on the client baby!.';
/*
// Testing which objects can be passed via the interface.
$testObject = new Object();
$testObject->test = 'just testing what can be passed';
$testObject->testArray = Array('this','is','a','test');
$testObject->testObject = new Object();
$testObject->testObject->field = 'just a field';
$testObject->testsynch_plugin_mnet = new synch_plugin_mnet();
$testObject->testDouble = 56.56;
$testObject->testInt = 56;
return $testObject;
*/
/*
// Testing that 1000 records can be passed via the web service interface
$testRecordSet = array();
$record;
for($i=0;$i<1000;$i++){
$record = new Object();
$record->name = 'My name is '.$i;
$record->id = '314325415345'.$i;
$record->table = 'mdl_some_table_here';
$testRecordSet[] = $record;
}
return $testRecordSet;
*/
Page 9 of 18
Creating a Moodle web service with mNet, August 2007
The Open University
// testing the characters that can be passed
$testCharacters = "!\"£$%^&*()_+-={}[]:@~;'#<>?,./|\\¬`";
return $testCharacters;
}
/*
* @method testResponse designed for unit testing to return the paramater
* provided. Tests the web service data transfer
* @param mixed $input value passed into the method
* @return mixed
*/
function testResponse($input, $input2=null){
if($input2){
$input = array($input, $input2);
}
//return $input;
return array('response'=>$input, 'host'=>array('wwwroot'=>'http://urlof this
server'));
}
}
?>
Page 10 of 18
Creating a Moodle web service with mNet, August 2007
The Open University
Appendix B
Core Changes
The following code must be added to the file mnet/xmlrpc/server.php to the method
mnet_server_dispatch at the end of the if..else checks for dispatched settings. Our
code was placed just after the if…else block beginning
}
elseif
('promiscuous'
==
$CFG->mnet_dispatcher_mode
&&
$MNET_REMOTE_CLIENT->plaintext_is_ok()) {
Here is the code to add.
elseif ($callstack[0] == 'synch') {
// Break out the callstack into its elements
list($base, $plugin, $filename, $methodname) = $callstack;
// We refuse to include anything that is not synch.php
// TODO: use method is_enabled_synch to check which modules
// support synching.
if ($filename == 'synch.php') {
$authclass = 'synch_plugin_'.$plugin;
$includefile = '/synch/'.$plugin.'/synch.php';
$response
= mnet_server_invoke_method($includefile, $methodname,
$method, $payload, $authclass);
$response = mnet_server_prepare_response($response);
echo $response;
} else {
// Generate error response - unable to locate function
exit(mnet_server_fault(702, 'nosuchfunction'));
}
////////////////////////////////////// NO FUNCTION
}
Admin Changes
These are the changes that need to be made to the file admin/mnet/adminlib.php.
Page 11 of 18
Creating a Moodle web service with mNet, August 2007
The Open University
The following code was placed in the method upgrade_RPC_functions at the end of
the method. When visiting the home page of the admin section of Moodle, or clicking
‘notifications’ in the site administration menu, you reach the page admin/index.php.
this page calls the method upgrade_RPC_functions as part of its check for upgraded
components.
This code makes the rpc framework of mNet aware of the synch folder and
consequently it’s contents.
$basedir = $CFG->dirroot.'/synch';
if (file_exists($basedir) && filetype($basedir) == 'dir') {
$dirhandle = opendir($basedir);
while (false !== ($dir = readdir($dirhandle))) {
$firstchar = substr($dir, 0, 1);
if ($firstchar == '.' or $dir == 'CVS' or $dir == '_vti_cnf') {
continue;
}
if (filetype($basedir .'/'. $dir) != 'dir') {
continue;
}
mnet_get_functions('synch', $dir);
}
}
The next bit of code was placed in the method mnet_get_functions between the
if….else statements for ‘mod’ and ‘auth or enrol’. It’s purpose is to specify where to
look within the synch folder structure for the file that contains the webservice class.
It is called by the previous method upgrade_RPC_functions.
else if('synch' == $type){
// synch
$relname = '/'.$type.'/'.$parentname.'/'.$docname;
$filename = $CFG->dirroot.$relname;
Page 12 of 18
Creating a Moodle web service with mNet, August 2007
The Open University
if (file_exists($filename)) include $filename;
$class = $type.($type=='enrol'? 'ment':'').'_plugin_'.$parentname;
if (class_exists($class)) {
$object = new $class();
if (method_exists($object, 'mnet_publishes')) {
(array)$publishes = $object->mnet_publishes();
}
}
}
Page 13 of 18
Creating a Moodle web service with mNet, August 2007
The Open University
Appendix C
<?php
$string['synch_test_name']
= 'Synch (Test)';
$string['synch_test_description']
= 'Publish this service to allow your users to
synch with the $a Moodle site. '.
'<ul><li><em>Dependency</em>:
You
must
also
<strong>subscribe</strong> to the Synchronisation service on $a.</li></ul><br />'.
'Subscribe to this service to allow synchronisation with
$a. '.
'<ul><li><em>Dependency</em>:
You
must
also
<strong>publish</strong> the Synchronisation service to $a.</li></ul><br />';
$string['synch_mnet_login_refused']
= 'Username $a[0] is not permitted to login
from $a[1].';
?>
Page 14 of 18
Creating a Moodle web service with mNet, August 2007
The Open University
Appendix D
This section contains the code for a page that tests the web service we have created.
The include to the config.php file must be adjusted depending on where you put the
file.
<?php
/**
* A template to test Moodle's XML-RPC feature
*
* This script 'remotely' executes the mnet_concatenate_strings function in
* mnet/testlib.php
* It steps through each stage of the process, printing some data as it goes
* along. It should help you to get your remote method working.
*
* @author Colin Chambers c.chambers@open.ac.uk
* @version 0.0.1
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*/
require_once(dirname(__FILE__) . '/../../../config.php');
//require_once dirname(__FILE__)."/../../admin/synch-setup.php";
require_once $CFG->dirroot.'/mnet/xmlrpc/client.php';
error_reporting(E_ALL);
if (isset($_GET['func']) && is_numeric($_GET['func'])) {
$func = $_GET['func'];
// Some HTML sugar
echo '<?xml version="1.0" encoding="utf-8"?>';
?>
<!DOCTYPE
html
PUBLIC
"-//W3C//DTD
XHTML
1.0
Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
<head><title>Moodle MNET Test Client</title></head><body>
Page 15 of 18
Creating a Moodle web service with mNet, August 2007
The Open University
<?php
// For the demo, our 'remote' host is actually our local host.
$wwwroot = $CFG->wwwroot;
// Enter the complete path to the file that contains the function you want to
// call on the remote server. In our example the function is in
// mnet/testlib/
// The function itself is added to that path to complete the $path_to_function
// variable
$path_to_function[0] = 'synch/mnet/synch.php/test';
$path_to_function[1] = 'synch/mnet/synch.php/testResponse';
$paramArray[0] = array();
$paramArray[1] = array(
array('testing just to see if it is working
correctly from the server', 'string'),
array(array('title'=>'You
got
the
love','artist'=>'Candi Staton','format','CD'), 'array'),
array(123456, 'int'),
array(12.3456, 'double'),
);
echo 'Your local wwwroot appears to be <strong>'. $wwwroot ."</strong>.<br
/>\n";
echo "We will use this as the local <em>and</em> remote hosts.<br /><br />\n";
flush();
// mnet_peer pulls information about a remote host from the database.
$mnet_peer = new mnet_peer();
$mnet_peer->set_wwwroot($wwwroot);
$mnethostid = 1010000003; // Choose a valid id from your set up
//$mnet_peer->set_id($mnethostid); //
// Create a new request object
Page 16 of 18
Creating a Moodle web service with mNet, August 2007
The Open University
$mnet_request = new mnet_xmlrpc_client();
// Tell it the path to the method that we want to execute
$mnet_request->set_method($path_to_function[$func]);
// Add parameters for your function. The mnet_concatenate_strings takes three
// parameters, like mnet_concatenate_strings($string1, $string2, $string3)
// PHP is weakly typed, so you can get away with calling most things strings,
// unless it's non-scalar (i.e. an array or object or something).
foreach($paramArray[$func] as $param) {
$mnet_request->add_param($param[0], $param[1]);
}
if (count($mnet_request->params)) {
echo 'Your parameters are:<br />';
while(list($key, $val) = each($mnet_request->params)) {
echo '   <strong>'.$key.':</strong> '. $val."<br/>\n";
}
}
flush();
// We send the request:
$mnet_request->send($mnet_peer);
?>
A
var_dump
of
the
decoded
response:
<strong><pre><?php
var_dump($mnet_request->response); ?></pre></strong><br />
<?php
if (count($mnet_request->params)) {
?>
A
var_dump
of
the
parameters
you
sent:
<strong><pre><?php
var_dump($mnet_request->params); ?></pre></strong><br />
<?php
Page 17 of 18
Creating a Moodle web service with mNet, August 2007
The Open University
}
}
?>
<p>
Choose a function to call:<br />
<a href="testclient.php?func=0">synch/test</a><br />
<a href="testclient.php?func=1">synch/testResponse</a><br />
</body></html>
Page 18 of 18
Download