Monday, January 9, 2017

Part 2 - Using the Renderer

In part two of the "Adding renderers and templates to your Moodle plugin" series, I will present how to use the renderer I created in part one in my plugin.

To summarize what I completed in part one, I created a renderer for my questionnaire module plugin using the classes/output/ structure and namespaces. This construction allows my classes to take advantage of Moodle's autoloading.

Damyon Wiese, one of the Moodle HQ leads, pointed out an error I made in part one. I showed a version of the renderer that used the class name "mod_questionnaire_renderer" without namespaces, in the file "renderer.php" located in the classes/output/ directory. Apparently, this will not work in a final solution. If I don't use namespaces, then that file must be located in either the plugin root or in classes/. In any case, it is always best to use the namespace solution that I finished with. I have updated Part 1 to reflect the correct structures.

Now I am going to edit the index.php file to use the renderer I created.

In the pre-renderer index file, I used PHP's echo statement with Moodle's global $OUTPUT object and html_writer helper class to display the screen output. The global $OUTPUT object is the global renderer object available to any script in Moodle. If a script is not using renderers, it will likely use this object to perform its necessary output operations. When a plugin uses its own renderer, it instantiates its own renderer object and uses it in place of $OUTPUT.

To instantiate my plugin's renderer, I use the get_renderer helper function. This function is part of the core moodle_page class, and can be accessed through the global $PAGE object, available to any Moodle script. Like the global $OUTPUT object, the global $PAGE object is instantiated at the start of every Moodle script through the normal setup functions. If a script specifically includes the main config.php file, it will already have direct access to these global objects. If not, it will need to specifically include them with a PHP global statement.

To get a renderer object for my plugin, I need to add the line:
    $output = $PAGE->get_renderer('mod_questionnaire');

This function is responsible for locating my renderer and returning an instantiated object of my renderer's class. This is the function that looks for a class named mod_questionnaire_renderer in the plugin root directory, or the classes/ subdirectory, or one that can be autoloaded from the namespace mod_questionnaire\output namespace named renderer.

Once I have this, anywhere I would have used $OUTPUT, I will now use the plugin's $output instead.

So, I change:
    echo $OUTPUT->header();
to
    echo $output->header();
And:
    echo $OUTPUT->footer();
to:
    echo $output->footer();

Note that the renderer I created does not specifically contain the header() or footer() functions. These are inherited from the parent class, plugin_renderer_base, and are used as defined there. If I want to change what the output of these functions are, I can extend or replace them in my renderer. But, these are important functions that do much of the heavy lifting for page setup and completion, so it's best to just use the core methods.

The other output my index script currently does is create an html_table object, set it up, and output it using the html_writer helper class. Since my renderer now takes care of that, I'm going to remove all of those bits and pass the necessary data to the renderer instead. That actual content of the page will be output with the statement:
    echo $output->render_index($headings, $align, $content);

The function render_index is the one new function I did create, and it is responsible for returning the complete page's HTML to the caller.

So, using my renderer, my index page code to perform the page output, is really handled by four statements:
    $output = $PAGE->get_renderer('mod_questionnaire');    
    echo $output->header();
    echo $output->render_index($headings, $align, $content);
    echo $output->footer();

The rest of the script is really there to define the three variables passed to the render_index function.

To see the changes made, the original index.php file (before renderers) can be found here. The modified version using renderers can be found here. The diff comparison can be viewed here.

In the next post, I will add template usage to the renderer solution.