mirror of
https://github.com/moodle/moodle.git
synced 2025-03-13 20:26:32 +01:00
More backup-converter API improvements
Added write_xml() helper that writes the given tree-ish structure into the current xml writer. Improved get_contextid() so that it can use indices for searching data. Added set_stash() and get_stash() helper methods.
This commit is contained in:
parent
a5fe591280
commit
beb7de3736
@ -174,12 +174,51 @@ abstract class moodle1_xml_handler extends moodle1_handler {
|
||||
|
||||
/**
|
||||
* Dumps the data into the XML file
|
||||
*
|
||||
* @param string $element the name of the root element of the tree
|
||||
* @param array $data the associative array of data to write
|
||||
* @param array $attribs list of additional fields written as attributes instead of nested elements (all 'id' are there automatically)
|
||||
* @param string $parent used internally during the recursion, do not set yourself
|
||||
*/
|
||||
public function write_xml(array $data) {
|
||||
public function write_xml($element, array $data, array $attribs = array(), $parent = '/') {
|
||||
|
||||
$mypath = $parent . $element;
|
||||
$myattribs = array();
|
||||
|
||||
// detect properties that should be rendered as element's attributes instead of children
|
||||
foreach ($data as $name => $value) {
|
||||
if (!is_array($value)) {
|
||||
if ($name === 'id' or in_array($mypath . '/' . $name, $attribs)) {
|
||||
$myattribs[$name] = $value;
|
||||
unset($data[$name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// reorder the $data so that all sub-branches are at the end (needed by our parser)
|
||||
$leaves = array();
|
||||
$branches = array();
|
||||
foreach ($data as $name => $value) {
|
||||
if (is_array($value)) {
|
||||
$branches[$name] = $value;
|
||||
} else {
|
||||
$leaves[$name] = $value;
|
||||
}
|
||||
}
|
||||
$data = array_merge($leaves, $branches);
|
||||
|
||||
$this->xmlwriter->begin_tag($element, $myattribs);
|
||||
|
||||
foreach ($data as $name => $value) {
|
||||
$this->xmlwriter->full_tag($name, $value);
|
||||
if (is_array($value)) {
|
||||
// recursively call self
|
||||
$this->write_xml($name, $value, $attribs, $mypath);
|
||||
} else {
|
||||
$this->xmlwriter->full_tag($name, $value);
|
||||
}
|
||||
}
|
||||
|
||||
$this->xmlwriter->end_tag($element);
|
||||
}
|
||||
}
|
||||
|
||||
@ -267,19 +306,15 @@ class moodle1_root_handler extends moodle1_handler {
|
||||
|
||||
/**
|
||||
* Handles the conversion of /MOODLE_BACKUP/INFO paths
|
||||
*
|
||||
* We do not produce any XML file here, just storing the data in the temp
|
||||
* table so thay can be used by a later handler.
|
||||
*/
|
||||
class moodle1_info_handler extends moodle1_handler {
|
||||
|
||||
public function get_paths() {
|
||||
return array(
|
||||
new convert_path(
|
||||
'info', '/MOODLE_BACKUP/INFO',
|
||||
array(
|
||||
'newfields' => array(
|
||||
'mnet_remoteusers' => 0,
|
||||
),
|
||||
)
|
||||
),
|
||||
new convert_path('info', '/MOODLE_BACKUP/INFO'),
|
||||
new convert_path('info_details', '/MOODLE_BACKUP/INFO/DETAILS'),
|
||||
new convert_path('info_details_mod', '/MOODLE_BACKUP/INFO/DETAILS/MOD'),
|
||||
new convert_path('info_details_mod_instance', '/MOODLE_BACKUP/INFO/DETAILS/MOD/INSTANCES/INSTANCE'),
|
||||
@ -327,6 +362,8 @@ class moodle1_course_header_handler extends moodle1_xml_handler {
|
||||
'enablecompletion' => 0,
|
||||
'completionstartonenrol' => 0,
|
||||
'completionnotify' => 0,
|
||||
'tags' => array(),
|
||||
'allowed_modules' => array(),
|
||||
),
|
||||
'dropfields' => array(
|
||||
'roles_overrides',
|
||||
@ -352,7 +389,14 @@ class moodle1_course_header_handler extends moodle1_xml_handler {
|
||||
)
|
||||
)
|
||||
),
|
||||
new convert_path('course_header_category', '/MOODLE_BACKUP/COURSE/HEADER/CATEGORY'),
|
||||
new convert_path(
|
||||
'course_header_category', '/MOODLE_BACKUP/COURSE/HEADER/CATEGORY',
|
||||
array(
|
||||
'newfields' => array(
|
||||
'description' => null,
|
||||
)
|
||||
)
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@ -372,22 +416,23 @@ class moodle1_course_header_handler extends moodle1_xml_handler {
|
||||
|
||||
public function on_course_header_end() {
|
||||
|
||||
$contextid = convert_helper::get_contextid($this->course['id'], 'course', $this->converter->get_id());
|
||||
$contextid = $this->converter->get_contextid(CONTEXT_COURSE, $this->course['id']);
|
||||
|
||||
// stash the information needed by other handlers
|
||||
$info = array(
|
||||
'original_course_id' => $this->course['id'],
|
||||
'original_course_fullname' => $this->course['fullname'],
|
||||
'original_course_shortname' => $this->course['shortname'],
|
||||
'original_course_startdate' => $this->course['startdate'],
|
||||
'original_course_contextid' => $contextid
|
||||
);
|
||||
$this->converter->set_stash('original_course_info', $info);
|
||||
|
||||
$this->course['contextid'] = $contextid;
|
||||
$this->course['category'] = $this->category;
|
||||
|
||||
$this->open_xml_writer('course/course.xml');
|
||||
$this->xmlwriter->begin_tag('course', array(
|
||||
'id' => $this->course['id'],
|
||||
'contextid' => $contextid,
|
||||
));
|
||||
$this->write_xml($this->course);
|
||||
$this->xmlwriter->begin_tag('category', array('id' => $this->category['id']));
|
||||
$this->xmlwriter->full_tag('name', $this->category['name']);
|
||||
$this->xmlwriter->full_tag('description', null);
|
||||
$this->xmlwriter->end_tag('category');
|
||||
$this->xmlwriter->full_tag('tags', null);
|
||||
$this->xmlwriter->full_tag('allowed_modules', null);
|
||||
$this->xmlwriter->end_tag('course');
|
||||
$this->write_xml('course', $this->course, array('/course/contextid'));
|
||||
$this->close_xml_writer();
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -244,10 +244,10 @@ class moodle1_converter extends base_converter {
|
||||
throw new convert_exception('missing_path_handler', $data['path']);
|
||||
}
|
||||
|
||||
$element = $this->pathelements[$data['path']];
|
||||
$object = $element->get_processing_object();
|
||||
$method = $element->get_processing_method();
|
||||
$rdata = null; // data returned by the processing method, if any
|
||||
$element = $this->pathelements[$data['path']];
|
||||
$object = $element->get_processing_object();
|
||||
$method = $element->get_processing_method();
|
||||
$returned = null; // data returned by the processing method, if any
|
||||
|
||||
if (empty($object)) {
|
||||
throw new convert_exception('missing_processing_object', $object);
|
||||
@ -261,13 +261,14 @@ class moodle1_converter extends base_converter {
|
||||
// if the path is not locked, apply the element's recipes and dispatch
|
||||
// the cooked tags to the processing method
|
||||
if (is_null($this->pathlock)) {
|
||||
$cooked = $element->apply_recipes($data['tags']);
|
||||
$rdata = $object->$method($cooked, $data['tags']);
|
||||
$rawdatatags = $data['tags'];
|
||||
$data['tags'] = $element->apply_recipes($data['tags']);
|
||||
$returned = $object->$method($data['tags'], $rawdatatags);
|
||||
}
|
||||
|
||||
// if the dispatched method returned SKIP_ALL_CHILDREN, remember the current path
|
||||
// and lock it so that its children are not dispatched
|
||||
if ($rdata === self::SKIP_ALL_CHILDREN) {
|
||||
if ($returned === self::SKIP_ALL_CHILDREN) {
|
||||
// check we haven't any previous lock
|
||||
if (!is_null($this->pathlock)) {
|
||||
throw new convert_exception('already_locked_path', $data['path']);
|
||||
@ -276,8 +277,8 @@ class moodle1_converter extends base_converter {
|
||||
$this->pathlock = $data['path'] . '/';
|
||||
|
||||
// if the method has returned any info, set element data to it
|
||||
} else if (!is_null($rdata)) {
|
||||
$element->set_data($rdata);
|
||||
} else if (!is_null($returned)) {
|
||||
$element->set_data($returned);
|
||||
|
||||
// use just the cooked parsed data otherwise
|
||||
} else {
|
||||
@ -384,6 +385,61 @@ class moodle1_converter extends base_converter {
|
||||
return restore_dbops::get_backup_ids_record($this->get_id(), $itemname, $itemid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store some information for later processing
|
||||
*
|
||||
* This implenentation uses backup_ids_temp table to store data. Make
|
||||
* sure that the stash name is unique.
|
||||
*
|
||||
* @param string $stashname name of the stash
|
||||
* @param mixed $info information to stash
|
||||
*/
|
||||
public function set_stash($stashname, $info) {
|
||||
$this->set_backup_ids_record($stashname, 0, 0, null, $info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores a given stash stored previously by {@link self::set_stash()}
|
||||
*
|
||||
* @param string $stashname name of the stash
|
||||
* @return mixed stashed data
|
||||
*/
|
||||
public function get_stash($stashname) {
|
||||
return $this->get_backup_ids_record($stashname, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an artificial context id
|
||||
*
|
||||
* Moodle 1.9 backups do not contain any context information. But we need them
|
||||
* in Moodle 2.x format so here we generate fictive context id for every given
|
||||
* context level + instance combo.
|
||||
*
|
||||
* This implementation maps context level and instanceid to the columns
|
||||
* of the backup_ids_temp table and uses the id of the record in that table
|
||||
* as the context id.
|
||||
*
|
||||
* @see get_context_instance()
|
||||
* @param int $level the context level, like CONTEXT_COURSE or CONTEXT_MODULE
|
||||
* @param int $instance the instance id, for example $course->id for courses or $cm->id for activity modules
|
||||
* @return int the context id
|
||||
*/
|
||||
public function get_contextid($level, $instance) {
|
||||
|
||||
$itemname = 'context' . $level;
|
||||
$itemid = $instance;
|
||||
|
||||
$existing = $this->get_backup_ids_record($itemname, $itemid);
|
||||
|
||||
if (empty($existing)) {
|
||||
// this context level + instance is required for the first time
|
||||
// store it and re-read to obtain its record id
|
||||
$this->set_backup_ids_record($itemname, $itemid);
|
||||
$existing = $this->get_backup_ids_record($itemname, $itemid);
|
||||
}
|
||||
|
||||
return $existing->id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -176,44 +176,6 @@ abstract class convert_helper {
|
||||
return implode(", ", array_map($mapper, array_keys($fields), array_values($fields)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an artificial context ID
|
||||
*
|
||||
* @param int $instance The moodle component instance ID, same value used for get_context_instance()
|
||||
* @param string $component The moodle component, like block_html, mod_quiz, etc
|
||||
* @param string $converterid The converter ID
|
||||
* @return int
|
||||
* @todo Add caching?
|
||||
* @todo Can we make the lookup faster? Not taking advantage of indexes
|
||||
*/
|
||||
public static function get_contextid($instance, $component = 'moodle', $converterid = NULL) {
|
||||
global $DB;
|
||||
|
||||
// Attempt to retrieve the contextid
|
||||
$contextid = $DB->get_field_select('backup_ids_temp', 'id',
|
||||
$DB->sql_compare_text('info', 100).' = '.$DB->sql_compare_text('?', 100).' AND itemid = ? AND itemname = ?',
|
||||
array($component, $instance, 'context'));
|
||||
|
||||
if (!empty($contextid)) {
|
||||
return $contextid;
|
||||
}
|
||||
|
||||
$context = new stdClass();
|
||||
$context->itemid = $instance;
|
||||
$context->itemname = 'context';
|
||||
$context->info = $component;
|
||||
|
||||
if (!is_null($converterid)) {
|
||||
$context->backupid = $converterid;
|
||||
}
|
||||
if ($id = $DB->insert_record('backup_ids_temp', $context)) {
|
||||
return $id;
|
||||
} else {
|
||||
$msg = self::obj_to_readable($context);
|
||||
throw new convert_helper_exception('failed_insert_record', $msg);
|
||||
}
|
||||
}
|
||||
|
||||
/// end of public API //////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user