Hi Urs,
I think something is incorrect in your plan above: "I guess I need to implement "after_execute_xxx" routines for all modules...". You don't need to make anything within modules, but within the course format plugin.
Here it is one simple example, hope it helps to clarify the thing a bit:
Let's imagine one course format, named "pinkboard". It is one ultra-cool course format allowing you to move the activities to any position in the course area, to get things visually different. So, let's assume we need one DB table where we store the x and y positions for each module. The table would be something like this:
CREATE TABLE mdl_pinkboard_positions
id bigint(10) unsigned NOT NULL AUTO_INCREMENT,
cmid bigint(10) unsigned NOT NULL,
posx int(5) unsigned NOT NULL,
posy int(5) unsigned NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY cmid (cmid)
)
So, for each modid, we have one posx and posy defining the position of the module in the course page.
And now we want to backup and restore that information, let's do it.
The first (important) thing to decide is where are we going to store that information. Course format plugins have 3 possible places where information can be added (at course level, at section level and at module level). Our example is clearly module-related (modid based). So we want to store it at module level, decided.
Once we have decided that point, it's time to implement the backup plugin. It would be something like this:
File: course/format/pinkboard/backup/moodle2/backup_format_pinkboard_plugin.class.php
<?php
class backup_format_pinkboard_plugin extends backup_format_plugin {
/**
* Returns the course format info to add to module hook
*/
protected function define_module_plugin_structure() {
// Define virtual plugin element
$plugin = $this->get_plugin_element(null, $this->get_format_condition(), 'pinkboard');
// Create plugin container element with standard name
$pluginwrapper = new backup_nested_element($this->get_recommended_name());
// Add wrapper to plugin
$plugin->add_child($pluginwrapper);
// Note we really don't need modid (because parent info in module.xml already has it
// but we put it here too (dupe info for sure)
$position = new backup_nested_element('position', null, array('cmid', 'posx', 'posy'));
$pluginwrapper->add_child($position);
$position->set_source_table('pinkboard_positions', array('cmid' => backup::VAR_MODID));
return $plugin;
}
}
And that will cause all the activities/xxxxx/module.xml file to look like this (with the plugin information attached in place):
<?xml version="1.0" encoding="UTF-8"?>
<module id="31" version="2010111500">
<modulename>forum</modulename>
<sectionid>13</sectionid>
...
...
<plugin_format_pinkboard_module>
<position>
<cmid>31</cmid>
<posx>100</posx>
<posy>100</posy>
</position>
</plugin_format_pinkboard_module>
...
...
</module>
More yet, if you look to that code, you will notice that the modid is already being backup in the very first tag of the XML file above (id = 31), and we are (not needed at all) storing it again within our plugin data. As far as we selected the proper level where our information is stored (module), we don't need to include that info (the course module id = 31) again.
Said that, let's see how restore would be:
File: course/format/pinkboard/backup/moodle2/restore_format_pinkboard_plugin.class.php
<?php
class restore_format_pinkboard_plugin extends restore_format_plugin {
// Define the type of information we are going to process at module level
protected function define_module_plugin_structure() {
$elepath = $this->get_pathfor('/position');
return array(new restore_path_element('position', $elepath));
}
public function process_position($data) {
global $DB;
$data = (object)$data;
// Aha, we really don't need to "after_execute" anything.
// The mapping between original and new cmid is already
// available via API. Let's use it!
$data->cmid = $this->task->get_moduleid();
$DB->insert_record('pinkboard_positions', $data);
}
// We really don't need this, because the process method already
// has been able to get the new cmid using available API. Anyway,
// this can be interesting to process "other" things.
public function after_execute_module() {
// Nothing to do
}
}
Said that, we just define the paths the plugin is going to restore at module level (define_module_plugin_structure), the process function for it (process_position) and the after_execute method that will be executed at module level (after_execute_module).
But look carefully, as commented above, the cmid in our backup is completely not used, because the old to new cmid conversion has been already performed and the new cmid is available using the own restore API with (get_moduleid), making the after_execute_module method 100% not necessary.
So, summarizing, the fist step is to have a good DB implementation, with each table pointing (being linked) with one course/section/course module id. And then, create the backup & restore plugins at the correct levels always.
If that happens, then, surely, you won't need to use those after_execute methods too much, because the information you need to convert has been already converted and is available via restore API.
Of course you can need those methods to process other information like other cmids or whatever, but it is highly dependent of how you've structured your information.
And that's all, I hope this simple (but potentially real) implementation of one course format plugin is useful to understand a bit more how it works. As said at the beginning, no need to implement anything within modules nor something similar. The information should be auto-contained and processed, exclusively by the (backup and restore) plugins. If that doesn't work I'd feel initially biased to think that something in the DB design of your format needs review in order to get everything properly attached to the available hooks (course, section and module).
Ciao