Tuesday, November 8, 2011

Converting M1.9 Plug-ins to M2 - Block Part 6 - Global Config

This is part seven of my series concerning porting Moodle 1.9 code to Moodle 2.

I have decided that the block needs to allow its default settings to be configured for each site installation. This would allow a site manager to control what the defaults are for the search string, update rate and number of tweets displayed. To do that, I need to add a global configuration function to the block.

In Moodle 1.9, global configuration was handled by the presence of a settings.php file in the block directory, and the function has_config defined to return "true". The good news, is that Moodle 2 does it exactly the same way, with some added differences I can take advantage of.

To start with, I'll create my new settings.php file. Basically, I'm adding global versions of the local settings I have defined in edit_form.php. The settings developer documentation points me to information that will help with this, but I think I can fake it.

Here is what I entered as my settings.php:
$settings->add(new admin_setting_configtext('block_twitter_search/defaultsearch',
                   get_string('defaultsearch', 'block_twitter_search'),
                   get_string('configdefaultsearch', 'block_twitter_search'), '#moodle', PARAM_TEXT));

$settings->add(new admin_setting_configselect('block_twitter_search/defaultnumtweets',
                   get_string('defaultnumtweets', 'block_twitter_search'),
                   get_string('configdefaultnumtweets', 'block_twitter_search'), 10, range(0, 20)));

$settings->add(new admin_setting_configtext('block_twitter_search/defaultpolltime',
                   get_string('defaultpolltime', 'block_twitter_search'),
                   get_string('configdefaultpolltime', 'block_twitter_search'), '30000', PARAM_INT));
If you've created a global settings function for Moodle 1.9, you will see this isn't really different. But there is one thing I've done differently. For the name of the three configuration elements, I've added the prefix 'block_twitter_search/'. In the past, I would have named each element with a '_' instead of a '/'. What the '/' does is move the global configuration variable from the global namespace stored in the global $CFG object to a local namespace within the block object. Without the '/', I could access the variable directly from the $CFG global without any other code, but I would also be increasing the size of that global unnecessarily. If I use the block's namespace, the same variables will be available to me through the get_config API call. Using the '/', I am doing things the way Moodle prefers me to do.

Note, that I also entered language strings for the settings, two per setting (one for the displayed setting label, and one for a description of what it's for).

Now if I go to my 'Site admin / Plugins / Blocks' page, I can see "Twitter search" as one of the options in the menu. Clicking this link brings up the settings page I just created. I should also be able to access this page from the 'Manage blocks' main page by using the 'Settings' link next to my block. But, when I go there now, there is no 'Settings' link.

There's a simple solution to getting this link. I need to add a has_config function to my class and return 'true'. I'm not sure of the reason, but Moodle uses the presence of the settings.php file to indicate that the global settings link should be present in the menu, and the has_config function to indicate that the settings link should be present on the 'Manage blocks' page. Having both ensures that the link will be available in both places.

So now that I have a way to define the defaults, I need to add code so that they are used.

The variables I defined for the global settings are available through the use of the function call, get_config($plugin, $name). I will add the use of this for each default to my specialization function code that currently has the defaults hard-coded. So, where before, the code looked like this:
if(empty($this->config->search_string)) {
    $this->config->search_string = "#moodle";
Now, I make it look like this:
if(empty($this->config->search_string)) {
    if (($defaultsearch = get_config('block_twitter_search', 'defaultsearch')) === false) {
        $defaultsearch = '#moodle';
    $this->config->search_string = $defaultsearch; 
This will set the block setting to whatever default we specified in the global settings, if it exists. The use of ' === false' is necessary so that there is a  difference between a setting that is intentionally blank (or zero) and one that doesn't exist.

For testing, I change my global settings to something other than the hardcoded values (I use, '#remote-learner', '5', and '60000'). Then I add a new instance of the block to a course and edit the settings for that block. Now I see my configured defaults instead. That's what I wanted.

At this point, I'm going to call this block migration complete. I have zipped up my final code, and made it available through my public dropbox. Feel free to download and play with it. In my next series of posts, I'll tackle a Moodle activity plug-in.


  1. 1. The need for has_config sounds like a bug to me. Have you looked to see if that is reported in the tracker, and if not, reported it?

    2. Calling get_config('block_twitter_search', 'defaultsearch') with two arguments is normally wrong. If you later need some other config variable then you end up doing multiple DB queries, which is bad for performance. Better to just do get_config('block_twitter_search') once.

    A good way to handle this is with the lazy-load pattern. Make a get_global_config method that does: if (is_null($this->globalconfig)) { $this->globalconfig = get_config('block_twitter_search'); } return $this->globalconfig;

  2. Thanks again Tim! That would indeed be more efficient. (I didn't look close enough at the 'get_config' function to realize it would return all config variables in a structure.)

  3. Hi Mike,

    Just found this via a tweet from Tim. Didn't realise that someone else had taken on porting my block to M2 and pushed a start at doing it myself to github and the Moodle Plugins Directory yesterday!

    Is your code available in a repo anywhere? I hadn't ported the AJAX stuff yet (it always seemed a bit clunky and I wanted to investigate if there was a better way of doing this for M2) and it'd be nice to pull this and your other improvements...

  4. Hi Kevin -

    Yep. The code is posted in a zip right now at http://dl.dropbox.com/u/17278808/twitter_search.zip.