Finally, the requirements for OpenSyllabus integration into Moodle are clearly defined. The main purpose: having a Syllabi (an OpenSyllabus XML file), Moodle has to process this XML file by means of an XSL file, which transforms the original Osyl XML file into a Moodle XML course file, and then process it to have a new Moodle course ready for being used.
However, I only have two more weeks to finish the work (all must be ready soon for Moodlemoot).
The main abstraction (God heavens, I love this word!) is (the main tasks):
- Create a new administration option, called 'Import OpenSyllabus course'.
- That option will link to a Moodle Form, where the administrator will be able to upload an XML file.
- Once the user has selected an Osyl XML file, and he submits it, the file is uploaded.
- After that, the uploaded file will be parsed with an XSL parser, who will transform the original XML into another Moodle readable XML course file.
- In order to reuse some original Moodle code (concretely the course restoration code) the output XML file needs to be zipped.
- Once the file has been zipped, now is the time to invoke the restoration process with the zipped file as parameter.
Until here, all seems to be tidy and clear. Yes, it is. This is the main specification however, I've found some personal problems (the design, how can I made it? how can I implement it?):
- I've no idea about PHP (I'm a pure Java developer, I've never touched PHP).
- How can I add a new link (which points to the import form) in the Moodle admin block?
- How can I create a form for allowing a user to upload a file compatible with Moodle?
- How can I retrieve the file? And the name of the file?
- How can I store a file into an specific folder in PHP?
- How can I process a XML file with an XSL parser with my XSL file to transform it into another XML file in PHP?
- How can I zip files in PHP?
- How can I reuse the restore implementation?
Well, all these questions have their proper answer. But where can I find the answers and understand them? Afortunately I've already found them, however, it has not been easy:
- Or I'm stupid and I can't find it, or Moodle lacks of a good developer documentation (such as complete class diagrams, specifications, sequence diagrams, proper explanations...). It only has an API over hundreds of files composing Moodle (omg, finding something has been really hard).
- I'm tired of searching concrete functions among the API files. Is the Moodle API useful or useless? Can I do my job with brute programming? Or has someone implemented what I need yet?
After some days of desperate study:
- PHP is an Object Oriented language, so a port from Java should not be too difficult. PHP is rather different than Java, however it has some similarities (like classes, attributes...), so with some practice, learning PHP should be easier (in fact, I believe I know now PHP and now I can program better than some time ago)
I've found the admin block is implemented in admin/settings. I've located my option link in courses.php file:
$ADMIN->add('courses', new admin_externalpage('osylimp', get_string('osylimp', 'admin'), $CFG->wwwroot . '/course/osyl.php'));
Moodle has a superclass for forms, called moodleform (located at lib/formslib.php). Using a form example (edit_form.php located in course folder), I've created a new subclass, called syllabi_import_form.
But the form example doesn't have a field for uploading files. How can I make one? After lot of websearching and coffees, I've found that I can add a line into the definition function of my new class:
$mform->addElement('file','syllabi', 'XML course file','maxlength="150" size="20"');
There were lots of similar lines in the document, however, replacing the first parameter with 'file' I've created a field for uploading files.
For retrieving the file value, exists a moodle function for forms: getElementValue. Passing as parameter the name of the file, it will retrieve the value entered by the user. Nevertheless, the value returned by getElementValue for the file field was an array. Arrays in PHP are rather different than Java:
For expressing an array, in Java we use this expression: namevariable[integer]. In PHP, is something similar, but different. Arrays can be used in many ways, like hash tables, priority queues, stacks... so you can use also strings into the [], and mapping a key to a value in the array. See PHP documentation for further explanation.
Finally, I could retrieve the name of the file :)
- For retrieving the file and store it, Moodle forms have a method for storing into an specific path all files the user wants to upload: "save_files".
There are lots of XSL parser for PHP: the most interesting I found was Sablotron. However, I couldn't get it working, so I've used the built-in XSLT parser (libxslt library). In PHP documentation about XSL I've found some functions to get it working. This is the main procedure:
$xp = new XSLTProcessor(); //First we create a XSLT process
$xsl = new DomDocument; //Then, we must load an XSL file
$xsl->load('../OsylCourse.xsl');
$xp->importStylesheet($xsl); //After that, we must import the XSL file
//to the XSLT process
$xml_doc = new DomDocument; //now we have to load the XML file
$xml_doc->load($CFG->dataroot.'/3/backupdata/'.$file['name']);
/*finally, we have to apply the transformation to the document and
save it to a file*/
if ($xml_out = $xp->transformToDOC($xml_doc)) {
$xml_out->save($CFG->dataroot.'/3/backupdata/moodle.xml');
} else {
trigger_error('XSL transformation failed.', E_USER_ERROR);
}Zipping a file is quite easy:
$zip = new ZipArchive(); //First we create an instance of a Zip file
/*Then, with open system call we create a zip file*/
if ($zip->open($CFG->dataroot.'/3/backupdata/course.zip', ZIPARCHIVE::CREATE)!==TRUE) {
exit("cannot open");
}
//Add as many files as you want (also directories)
$zip->addFile($CFG->dataroot.'/3/backupdata/moodle.xml', 'moodle.xml');
//Close the zip file
$zip->close();
For further information see PHP Documentation for ZIP.
- Reuse the restoration code is easy. Simply pass as a parameter the recently zipped file.
Well, that's all for now. However, there are plenty of bugs. For now, I'm only making a functional prototype for Moodlemoot... Doing things well requires time :)