Monday, March 5, 2018

Looking at Moodle's new plugin development API's - Part 1

David Mudrack, of Moodle HQ released a plugin called the "My Todo List" block. While functional, its real purpose is to show off the latest advanced coding techniques available in recent versions of Moodle. See his Tweet. From the readme:
The main purpose of this plugin is to demonstrate usage of advanced coding techniques available in recent Moodle versions. Most notably:
  • Rendering HTML output via Mustache templates.
  • AJAX based workflow of the elementary CRUD operations.
  • Organising JS into AMD modules.
  • Organising external functions into traits.
  • Low-level access to the database via persistent models.
  • Using exporters for handling the data structures in rendering and AJAX.
For this post, I will install and examine the code with the goal of learning better how to use these concepts.

While I have been a plugin developer for many years, I have not been able to keep up with all of the latest techniques to enhance the plugins I maintain. I am personally really interested in getting better with AJAX and AMD, as many of my plugins could benefit from these features. I have already experimented and released code with renderers and Mustache templates (see the series beginning here), so I won't go deep into those unless I see something new.

To begin, I fork David's repository into my own Github repository. This gives me place to install and play with the code. Once I have a local copy, I load it into my IDE (I use PhpStorm) and take a look at the code.

A quick perusal of the code shows that this is indeed a simple plugin, and uses the techniques I'm most interested in! The main block code file,  block_todo.php, contains five methods, four of which I'm familiar with from standard block development: init(), get_content(), specialization(), and applicable_formats(). But the fifth, get_required_javascript(), I am not familiar with and it is not defined on the block development page. I suspect this has to do with the AMD module feature. And, while that may be true, it appears that it calls the parent method, meaning this function is part of the block class. I need to do some searching to see why this function is there.

I search the development documentation on Moodledocs, and find this function referred to on the "jQuery pre2.9" page. So, it must be a function that has remained even with the new AMD module addition. I think I may want to look for the AMD Module documentation first.

I find a page in the Moodle development docs wiki on Javascript Modules. This appears to be the main documentation for using AMD in plugins. Skimming through I see that initializing an AMD javascript function is done with the $this->page->requires->js_call_amd() function. This is done in the ToDo block's get_required_javascript method.

A closer look at the parent block class, defines the get_required_javascript method as:
Allows the block to load any JS it requires into the page.
By default this function simply permits the user to dock the block if it is dockable.
So, I'm not sure that this function is actually required, but may just be a convenient place to call the js_call_amd function from. I search all of the core blocks for js_call_amd and find two, both of which call it from the get_required_javascript method. So this seems to be the place to do that. Maybe later, I'll play with that to see if that is a required way to do it.

In any case, the function passes the arguments:
'block_todo/control', 'init', ['instanceid' => $this->instance->id]
This coincides with the file amd/src/control.js, which is the expected location within a plugin to find the AMD javascript files.

Getting back to the function of the plugin, the main block get_content function, is a very simple function that does two things: gets a list of todo items, and outputs them on the screen. The technique uses one technique I'm familiar with, templates, and two I am unfamiliar with, Moodle persistents and Moodle exporters.

This is what I am seeing in get_content:
// Load the list of persistent todo item models from the database.
$items = block_todo\item::get_my_todo_items();
This code uses the persistent class, which appears to be a new technique to manage database data using CRUD techniques. It will be interesting to learn why this exists and when it should be used.
// Prepare the exporter of the todo items list.
$list = new block_todo\external\list_exporter([
    'instanceid' => $this->instance->id
,
], [
    'items' => $items,
    'context' => $this->context
,]);
This code uses exporter class and appears to be a technique to manage data passed in and out of web service functions, used by external applications and AJAX.
// Render the list using a template and exported data.
$this->content->text = $OUTPUT->render_from_template('block_todo/content',
    $list->export($OUTPUT));
This code is using a Mustache template to display the block content and utilizes the exporter class to send the data rather than renderers defined for the plugin, as I am used to. Again, I will need to discover why this technique is used.

I have some concepts to learn, so I install the block just to see what it does and how it works. After adding it to my dashboard page, I play with it, and see that it is as advertises, a simple "To Do" list.


Hovering over the controls shows no obvious links, and a quick perusal of the page code shows a form, but not a standard functioning Moodle form. It looks like all of the controls are using Javascript, AJAX and web services to do the actual work. This will be all new to me. :-)

Next post, I will start my functional learning.