ElearningWorld.org

For the online learning world

Technical

Output three ways

Introduction

Moodle principally generates its HTML output using PHP (some can be generated via JavaScript on your web browser) using a web server using the ‘Client Server’* concept. The output is a result of processing input from the user and other data from a data source, such as a database, to produce a specific result tailored to that user. But how can it do this? How does it generate the web page that you view? In this post I will describe on a basic level three ways it does to produce the web page you see.

*If you want to understand more about this, then please read the section ‘Client Server’ on my previous post ‘The perils of ‘display: none’.

Disclaimers

Firefox® is a registered trademark of the Mozilla Foundation.

Ubuntu® is a registered trademark of Canonical Ltd – www.ubuntu.com/legal/terms-and-policies/intellectual-property-policy

Moodle™ is a registered trademark of ‘Martin Dougiamas’ – moodle.com/trademarks.

Other names / logos can be trademarks of their respective owners. Please review their website for details.

I am independent from the organisations listed above and am in no way writing for or endorsed by them.

The concept

PHP exists as a language to facilitate the production of dynamic rather than static web pages. Where a ‘static’ web page (its content) cannot be changed unless done so manually by human intervention and with a ‘dynamic’ web page the machine can alter its content without human intervention.

This is a generalisation as for the most part with Moodle a human instigates the creation of the dynamic web page for them. But here, imagine the scenario that you as a user wishes to know the list of courses you are enrolled on:

  • With a static web page, you would make the request with your user id to a software developer who would take that request, look in the database your enrolled courses and then use the result to hand craft a HTML page for you and upload it to the server for you to view, say with the URL path ‘1234/mycourses’ appended to the end of the domain (where ‘1234’ is your user id). This clearly would take time and anybody knowing your user id could also view the page.
  • With a dynamic web page, you make a request, then the machine uses the data you send to it (like the session id generated when you login), looks in the data database for your enrolled courses (after translating the session id to a user id), generates the page and sends it directly back to you, say with the URL path ‘/my’ appended to the end of the domain. Notice that I state the word ‘directly’ here, the data is transmitted directly to you and ‘only you’ (unless someone else can read the data that is transmitted over the network – another story!). This all happens very quickly and pragmatically makes Moodle as a tool for learning ‘work’ rather than a slow laborious process that is not fit for purpose.

Three ways

Moodle can generate the HTML output using PHP in three ways (and listed in use time order):

  1. Mixing the static HTML content with the dynamic content / values.
  2. Using PHP alone to create the HTML with the generated content / values.
  3. Using a mixture of a ‘template’ which has the HTML markup and ‘placeholders’ for the generated content / values.

The first is the technique you can use for any bit of PHP. The second uses a PHP class in Moodle called the ‘HTML Writer’ which I understand was introduced in Moodle tracker ‘MDL-21235’ as a means of standardising ‘output helper functions’ (in Object Orientation, ‘functions’ are called ‘methods’ – another story!). And lastly the third using the concept of ‘templating’ is the newest and is there in an attempt to make the clearest, cleanest and maintainable means to a human developer of the output generation process.

All three are currently used because existing code works and there is no reason to change it.

An illustrative scenario

Take the idea that when viewing a course that you want to know how long you have been logged in for. That you want to see this on the course page at the end of the list of sections. For example, the text ‘Admin, you have been logged in for 0h 01m and 58s.’.

Given that we know that the first name of the user is stored in ‘$USER→firstname’ and when they logged in is stored in ‘$USER→currentlogin’, then we can generate the rest of the text with the time using the code:

$loggedinduration = ', you have been logged in for '.
    gmdate('G\h i\m \a\n\d s\s', time() - $USER→currentlogin).'.';

Please don’t worry if this does not make sense, but rather appreciate that its code that has / generates what we need as input to each way. Thus with:

PHP way we can write:

$output = '<div class="row">
    <div class="col-12 pt-3 pb-3">
        <h3>PHP way: '.$USER->firstname.$loggedinduration.'</h3>
    </div>
</div>';

where we have a mixture of HTML markup in a string which is then interspersed with PHP data. This can be difficult to read the more complex the output becomes.

HTML Writer way we can write:

$output = html_writer::start_div('row');
$output .= html_writer::start_div('col-12 pt-3 pb-3');
$output .= html_writer::tag('h3', 'HTML_Writer way: '.$USER->firstname.$loggedinduration);
$output .= html_writer::end_div();
$output .= html_writer::end_div();

where we use PHP only and provide it with ‘data’ / ‘specific instructions’ that is either HTML or the data itself. This can be difficult to both read and write.

Mustache template way we can write:

$sectionsfooter = new stdClass();
$sectionsfooter->firstname = $USER->firstname;
$sectionsfooter->loggedinduration = $loggedinduration;
$output = $this->render_from_template('format_topics/sectionsfooter', $sectionsfooter);

which uses a separate template file called ‘sectionsfooter.mustache’ containing:

<div class="row">
    <div class="col-12 pt-3 pb-3">
        <h3>Mustache template way: {{firstname}}{{loggedinduration}}</h3>
    </div>
</div>

where the HTML markup is inter-spaced with ‘placeholders’ for the data and the PHP ‘method’ ‘render_from_template’ uses the template file in combination with the data parsed to it to generate the output. This separates the ‘form’ and ‘function’ so that concepts that should be separate actually are. Thus if you want to change only the markup to support different display CSS classes (as Bootstrap version 4 ones are used here) then you only need to change the template, the logic that generates the data stays the same. Templates can be ‘overridden’ in themes which means that a theme can change the structure of the web page without having to also having to alter how it is generated.

Thus the first two ways where I’ve shown use of the ‘col-12’ CSS class are specific to themes that use the Bootstrap version 4 framework used by the Boost theme and others. But the last could be overridden and only the template changed for the Clean theme and other Bootstrap version 2.3.2 based themes.

Each way can then be seen on a page like so:

If you wish to try out the code for yourself on Moodle 3.6, then on a ‘test server’ (one that you can try things out on and does not matter if it breaks), edit the file ‘/course/format/topics/renderer.php’ and change the method ‘end_section_list()’ to be:

protected function end_section_list() {
    //return html_writer::end_tag('ul');
    $o = html_writer::end_tag('ul');

    global $USER;
    // Note: User timestamp attributes are in UTC.
    $loggedinduration = ', you have been logged in for '.
        gmdate('G\h i\m \a\n\d s\s', time() - $USER->currentlogin).'.';

    // Pure PHP way.
    $o .= '<div class="row">
        <div class="col-12 pt-3 pb-3">
            <h3>PHP way: '.$USER->firstname.$loggedinduration.'</h3>
        </div>
    </div>';

    // HTML Writer way.
    $o .= html_writer::start_div('row');
    $o .= html_writer::start_div('col-12 pt-3 pb-3');
    $o .= html_writer::tag('h3', 'HTML_Writer way: '.$USER->firstname.$loggedinduration);
    $o .= html_writer::end_div();
    $o .= html_writer::end_div();

    // Mustache way.
    $sectionsfooter = new stdClass();
    $sectionsfooter->firstname = $USER->firstname;
    $sectionsfooter->loggedinduration = $loggedinduration;
    $o .= $this->render_from_template('format_topics/sectionsfooter', $sectionsfooter);

    return $o;
}

then create a file called ‘sectionsfooter.mustache’ within a new folder ‘templates’ in the ‘/course/format/topics’ folder and place in it:

{{!
    This file is part of Moodle - http://moodle.org/

    Moodle is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Moodle is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
}}
<div class="row">
    <div class="col-12 pt-3 pb-3">
        <h3>Mustache template way: {{firstname}}{{loggedinduration}}</h3>
    </div>
</div>

then login to Moodle and go to any ‘Topics’ based course. You might need to ‘Purge all caches’ – docs.moodle.org/36/en/Developer_tools#Purge_all_caches.

Conclusion

How readable to you each method is ultimately depends on you and your preference. Personally I’ll use the method that I consider is the most suitable for any given situation. What do you think?

References

PHP

HTML Writer

Mustache templates

Bootstrap version 4

Gareth Barnard
Latest posts by Gareth Barnard (see all)
blank

Gareth Barnard

Gareth is a developer of numerous Moodle Themes including Essential (the most popular Moodle Theme ever), Foundation, and other plugins such as course formats, including Collapsed Topics.

2 thoughts on “Output three ways

Add a reply or comment...