Methodology ? Language magic routing for module or block extensibility sub APIs (proposal)

Methodology ? Language magic routing for module or block extensibility sub APIs (proposal)

by Valery Fremaux -
Number of replies: 8

Hi,

Here come a proposal for a subplugin API architecture, with essential concerns with keeping fluid the i18n system.

This architecture was tested with success in the new Brainstorm version that will be published soon.

This has concerns with people who want to have their blocks or module extensible, so they would develop some form of plugability in it. The main issue with language files is that you may not be able to make Moodle explore your own subdirectories to discover and find automagically the new strings and help topics.

Here is the way I resolved it in Brainstorm.

Brainstorm has an extension pattern that uses an "operators" directory where subplugins reside. Each operator is a plugin that will be in a named directory in "operators".

So, the module topology is :

mod/
   brainstorm/
      brainstorm_files...
      operators/
          operator_commons...
          categorize/
             categorize_files...
             lang/
                en_utf8/
                   operator.php // the standard lang file for the sub plugin
                   help/
                      brainstorm_categorize/
                          help_files...
      lang/   // standard Moodle aware language pack
          en_utf8/
              brainstorm.php
              help/
                 brainstorm/
                    help_files...
                operatorrouter.html  // the important one see below
                         
Of course Moodle cannot foresee where to find subplugins it ignores all of. Let see how to automate language discovery and resolution.

first, we must link dynamically the operators language packs.

in each legacy langpack after the module's stringset we set :

///get all operators lang files
global $CFG, $USER, $SITE;
$DIR = opendir($CFG->dirroot.'/mod/brainstorm/operators');
$lang = current_language();
while($opname = readdir($DIR)){
    if (!is_dir($CFG->dirroot.'/mod/brainstorm/operators/'.$opname)) continue;
    if (ereg("^\\.", $opname)) continue;
    if (file_exists("{$CFG->dirroot}/mod/brainstorm/operators/{$opname}/lang/{$lang}/operator.php")){
        include "{$CFG->dirroot}/mod/brainstorm/operators/{$opname}/lang/{$lang}/operator.php";
    }
}

This scans directory of plugins when the lang file is read by Moodle and add as strings as necessary.

Next, we have an issue on help files. They would be NEVER found so deep in the module pack.

Here the trick is that the help button invokes a target html page by name checking the file ends with .html or not.
The standard way to call the help file is avoiding appending the .html extension, so the call is simply :

<?php helpbutton('sequentialaccess', get_string('sequentialaccess', 'brainstorm'), 'brainstorm'); ?>

The helpbutton function luckily do not check if we have appended other parms or not. So we can invoke it
in a tweacked manner :

<?php helpbutton('operatorrouter.html&amp;operator=categorize&amp;helpitem=allowmultiple', get_string('allowmultiple', 'brainstorm'), 'brainstorm'); ?>

This invokes a standard help file we have in our Moodle aware help directory, but passing along extra parms to that file, so it could deroute its realisation with other content :

In our sub plugin router we find :

<?php
$operator = required_param('operator', PARAM_TEXT);
$helpitem = required_param('helpitem', PARAM_TEXT);
$helpfile = "{$CFG->dirroot}/mod/brainstorm/operators/$operator/lang/{$lang}/help/brainstorm_{$operator}/{$helpitem}";
include $helpfile;
?>

In other words, we made a special help files that loads from another help pack location inside our subarchitecture !!

This works fine and could be used for assignement, where subs assigmenttype lang files are not of immediate use, or questiontype either.

This assumes .html files are php enabled (the actual standard setup in most out-of-the-box web server setups).

Cheers.

Average of ratings: -
In reply to Valery Fremaux

Re: Methodology ? Language magic routing for module or block extensibility sub APIs (proposal)

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
The other way you could try achieving the same end would be to modify the places_to_look_for_lang_strings function in moodlelib. It basically returns an array that is used by get_string and help.php to control the search for language files. You could make that extensible, so that modules could register sub-plugin types.
In reply to Tim Hunt

Re: Methodology ? Language magic routing for module or block extensibility sub APIs (proposal)

by Valery Fremaux -

Were you telling me we couldn't make a module with sub plugins WITHOUT patching the core libs ? wink

This was precisely what this methodology trick was proposing to avoid.

Friendly.

VF.

In reply to Valery Fremaux

Re: Methodology ? Language magic routing for module or block extensibility sub APIs (proposal)

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
Well, I am suggesting it might be worth patching core libraries once, so that in future subplugins can be supported without further patching, or tricks.
In reply to Tim Hunt

Re: Methodology ? Language magic routing for module or block extensibility sub APIs (proposal)

by Valery Fremaux -

Tim,

Somewhat hard to settle down, because you might not foresee the needs of the plugins. If we scan for sublanguage files somewhere, what about a future plugin that will have two or three extensibility APIs ?

or maybe using a new standard declarative callback in the module's API ?

In both case scanning would spend plenty of time...

Nothing mattering with this, I saw you tried a Unit Test in forum as proposed Nicolas Connault. Did you reached the end of the testing process ? 

In reply to Valery Fremaux

Re: Methodology ? Language magic routing for module or block extensibility sub APIs (proposal)

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
I agree the key question is how to do this with good performance.

The thing that makes this possible is that any sub-plugin of the quiz (to take one example) is only going to be used by code in the quiz. Nothing else knows that that sub-plugin exists. And any code inside the quiz module, or outside it that calls quiz code, will have done require('/mod/quiz/lib.php').

So all we need is one core function in moodlelib: register_lang_string_location($prefix, $path), that adds a new entry to the array returned by places_to_search_for_lang_strings(). Then at the top of mod/quiz/lib.php you call register_lang_string_location('report_', 'mod/quiz/report');

This scheme has the potential to improve performance, because any code that does not care about the quiz (e.g. course reports) has one fewer place to search for lang strings.
In reply to Tim Hunt

Re: Methodology ? Language magic routing for module or block extensibility sub APIs (proposal)

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
I have filed this idea as MDL-13816.
In reply to Valery Fremaux

Unit testing

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
To reply to the unit testing part of your post. You need to remember that the unit testing framework was originally added to Moodle by the OU. My colleague Nick Freear did most of the hard work, then I changed a few things and checked it in.

Of course, we have not been so good at actually writing tests blush. Nicolas was the one who got Moodle HQ writing tests for the new gradebook, which is a great development. Then he gave that talk about it at the last UK Moodle moot. Now I have refactored some of the quiz code into classes, so it is actually possible to test it, I had better do so! That is my plan for today actually, just as soon as I stop browsing the forums, and start concentrating.
In reply to Valery Fremaux

Re: Methodology ? Language magic routing for module or block extensibility sub APIs (proposal)

by Martin Dougiamas -
Picture of Core developers Picture of Documentation writers Picture of Moodle HQ Picture of Particularly helpful Moodlers Picture of Plugin developers Picture of Testers
It's a pretty good idea, but it does mean more code (however it works now, which is cool) ... perhaps in core later to keep it simpler we should have a way of modules registering locations (much like access.php files register capabilities).