/**
* Returns all the components and fileareas used by all the installed qtypes
*
* The method introspects each qtype, asking it about fileareas used. Then,
* one 2-level array is returned. 1st level is the component name (qtype_xxxx)
* and 2nd level is one array of filearea => mappings to look
*
* Note that this function is used both in backup and restore, so it is important
* to use the same mapping names (usually, name of the table in singular) always
*
* TODO: Surely this can be promoted to backup_plugin easily and make it to
* work for ANY plugin, not only qtypes (but we don't need it for now)
*/
public static function get_components_and_fileareas($filter = null) {
$components = array();
// Get all the plugins of this type
$qtypes = get_plugin_list('qtype');
foreach ($qtypes as $name => $path) {
// Apply filter if specified
if (!is_null($filter) && $filter != $name) {
continue;
}
// Calculate the componentname
$componentname = 'qtype_' . $name;
// Get the plugin fileareas (all them MUST belong to the same component)
$classname = 'backup_qtype_' . $name . '_plugin';
if (class_exists($classname)) {
$elements = call_user_func(array($classname, 'get_qtype_fileareas'));
if ($elements) {
// If there are elements, add them to $components
$components[$componentname] = $elements;
}
}
}
return $components;
}
/**
* Returns one array with filearea => mappingname elements for the qtype
*
* Used by {@link get_components_and_fileareas} to know about all the qtype
* files to be processed both in backup and restore.
*/
public static function get_qtype_fileareas() {
// By default, return empty array, only qtypes having own fileareas will override this
return array();
}
}
backup_qtype_' . $name . '_plugin so backup_qtype_' . 'match' . '_plugin
/**
* Provides the information to backup match questions
*
*/
class backup_qtype_match_plugin extends backup_qtype_plugin {
/**
* Returns the qtype information to attach to question element
*/
protected function define_question_plugin_structure() {
// Define the virtual plugin element with the condition to fulfill
$plugin = $this->get_plugin_element(null, '../../qtype', 'match');
// Create one standard named plugin element (the visible container)
$pluginwrapper = new backup_nested_element($this->get_recommended_name());
// connect the visible container ASAP
$plugin->add_child($pluginwrapper);
// Now create the qtype own structures
$matchoptions = new backup_nested_element('matchoptions', array('id'), array(
'subquestions', 'shuffleanswers', 'correctfeedback', 'correctfeedbackformat',
'partiallycorrectfeedback', 'partiallycorrectfeedbackformat',
'incorrectfeedback', 'incorrectfeedbackformat', 'shownumcorrect'));
$matches = new backup_nested_element('matches');
$match = new backup_nested_element('match', array('id'), array(
'code', 'questiontext', 'questiontextformat', 'answertext'));
// Now the own qtype tree
$pluginwrapper->add_child($matchoptions);
$pluginwrapper->add_child($matches);
$matches->add_child($match);
So $pluginwrapper have the necessary names to get the say correctfeedback infos.
for the course where I had some questions the last one being a match the sructure is
[optigroup:base_nested_element:private] =>
[used:base_nested_element:private] => Array
(
[0] => qtype_question_plugin
[1] => plugin_qtype_calculated_question
[2] => answers
[3] => answer
[4] => numerical_units
[5] => numerical_unit
[6] => numerical_options
[7] => numerical_option
[8] => dataset_definitions
[9] => dataset_definition
[10] => dataset_items
[11] => dataset_item
[12] => calculated_records
[13] => calculated_record
[14] => calculated_options
[15] => calculated_option
[16] => plugin_qtype_calculatedmulti_question
[17] => plugin_qtype_calculatedsimple_question
[18] => plugin_qtype_essay_question
[19] => essay
[20] => plugin_qtype_match_question
[21] => matchoptions
[22] => matches
[23] => match
)
and this give a complex structure like
[counter:protected] => 0
[final_elements:base_nested_element:private] => Array
(
[subquestions] => backup_final_element Object
(
[annotationitem:protected] =>
[attributes:base_final_element:private] => Array
(
)
[parent:base_final_element:private] => backup_nested_element Object
*RECURSION*
[name:base_atom:private] => subquestions
[value:base_atom:private] =>
[is_set:base_atom:private] =>
)
[shuffleanswers] => backup_final_element Object
(
[annotationitem:protected] =>
[attributes:base_final_element:private] => Array
(
)
[parent:base_final_element:private] => backup_nested_element Object
*RECURSION*
[name:base_atom:private] => shuffleanswers
[value:base_atom:private] =>
[is_set:base_atom:private] =>
)
[correctfeedback] => backup_final_element Object
(
[annotationitem:protected] =>
[attributes:base_final_element:private] => Array
(
)
[parent:base_final_element:private] => backup_nested_element Object
*RECURSION*
[name:base_atom:private] => correctfeedback
[value:base_atom:private] =>
[is_set:base_atom:private] =>
)
[correctfeedbackformat] => backup_final_element Object
(
[annotationitem:protected] =>
[attributes:base_final_element:private] => Array
(
)
[parent:base_final_element:private] => backup_nested_element Object
*RECURSION*
[name:base_atom:private] => correctfeedbackformat
[value:base_atom:private] =>
[is_set:base_atom:private] =>
)
[partiallycorrectfeedback] => backup_final_element Object
(
[annotationitem:protected] =>
[attributes:base_final_element:private] => Array
(
)
[parent:base_final_element:private] => backup_nested_element Object
*RECURSION*
[name:base_atom:private] => partiallycorrectfeedback
[value:base_atom:private] =>
[is_set:base_atom:private] =>
)
[partiallycorrectfeedbackformat] => backup_final_element Object
(
[annotationitem:protected] =>
[attributes:base_final_element:private] => Array
(
)
[parent:base_final_element:private] => backup_nested_element Object
*RECURSION*
[name:base_atom:private] => partiallycorrectfeedbackformat
[value:base_atom:private] =>
[is_set:base_atom:private] =>
)
[incorrectfeedback] => backup_final_element Object
(
[annotationitem:protected] =>
[attributes:base_final_element:private] => Array
(
)
[parent:base_final_element:private] => backup_nested_element Object
*RECURSION*
[name:base_atom:private] => incorrectfeedback
[value:base_atom:private] =>
[is_set:base_atom:private] =>
)
[incorrectfeedbackformat] => backup_final_element Object
(
[annotationitem:protected] =>
[attributes:base_final_element:private] => Array
(
)
[parent:base_final_element:private] => backup_nested_element Object
*RECURSION*
[name:base_atom:private] => incorrectfeedbackformat
[value:base_atom:private] =>
[is_set:base_atom:private] =>
)
[shownumcorrect] => backup_final_element Object
(
[annotationitem:protected] =>
[attributes:base_final_element:private] => Array
(
)
[parent:base_final_element:private] => backup_nested_element Object
*RECURSION*
[name:base_atom:private] => shownumcorrect
[value:base_atom:private] =>
[is_set:base_atom:private] =>
)
)
the files can be retrieved once you know the name of the filearea under which they are saved like "questiontext" in the files datatable.
the function get_qtype_fileareas() let each questiontype identify the filearea to look for.
I intuitively can figure out and can use this structure but in no way I could build it
Pierre