Skip to content

Commit

Permalink
Improved the moodle1_convert stashing subsystem
Browse files Browse the repository at this point in the history
  • Loading branch information
mudrd8mz committed May 12, 2011
1 parent beb7de3 commit 9b5f1ad
Show file tree
Hide file tree
Showing 3 changed files with 194 additions and 54 deletions.
86 changes: 80 additions & 6 deletions backup/converter/moodle1/handlerlib.php
Expand Up @@ -44,10 +44,12 @@ abstract class moodle1_handlers_factory {
*/
public static function get_handlers(moodle1_converter $converter) {

$handlers = array();
$handlers[] = new moodle1_root_handler($converter);
$handlers[] = new moodle1_info_handler($converter);
$handlers[] = new moodle1_course_header_handler($converter);
$handlers = array(
new moodle1_root_handler($converter),
new moodle1_info_handler($converter),
new moodle1_course_header_handler($converter),
new moodle1_course_outline_handler($converter),
);

$handlers = array_merge($handlers, self::get_plugin_handlers('mod', $converter));
$handlers = array_merge($handlers, self::get_plugin_handlers('block', $converter));
Expand Down Expand Up @@ -292,14 +294,12 @@ public function process_root_element($data) {
* This is executed at the very start of the moodle.xml parsing
*/
public function on_root_element_start() {
$this->converter->create_backup_ids_temp_table();
}

/**
* This is executed at the end of the moodle.xml parsing
*/
public function on_root_element_end() {
$this->converter->drop_backup_ids_temp_table();
}
}

Expand Down Expand Up @@ -436,3 +436,77 @@ public function on_course_header_end() {
$this->close_xml_writer();
}
}


/**
* Handles the conversion of course sections and course modules
*/
class moodle1_course_outline_handler extends moodle1_xml_handler {

/** @var array current section data */
protected $currentsection;

/**
* This handler is interested in course sections and course modules within them
*/
public function get_paths() {
return array(
new convert_path(
'course_section', '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION',
array(
'newfields' => array(
'name' => null,
'summaryformat' => 1,
'sequence' => null,
),
)
),
new convert_path(
'course_module', '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD',
array(
'dropfields' => array(
'roles_overrides',
'roles_assignments',
),
)
)
);
}

public function process_course_section($data) {
$this->currentsection = $data;
}

/**
* Populates the section sequence field (order of course modules) and stashes the
* course module info so that is can be dumped to activities/xxxx_x/module.xml later
*/
public function process_course_module($data) {

// add the course module id into the section's sequence
if (is_null($this->currentsection['sequence'])) {
$this->currentsection['sequence'] = $data['id'];
} else {
$this->currentsection['sequence'] .= ',' . $data['id'];
}

// add the sectionid and sectionnumber
$data['sectionid'] = $this->currentsection['id'];
$data['sectionnumber'] = $this->currentsection['number'];

// stash the course module info in stashes like 'cminfo_forum' with
// itemid set to the instance id
$this->converter->set_stash('cminfo_'.$data['type'], $data, $data['instance']);
}

/**
* Writes sections/section_xxx/section.xml file
*/
public function on_course_section_end() {

$this->open_xml_writer('sections/section_' . $this->currentsection['id'] . '/section.xml');
$this->write_xml('section', $this->currentsection);
$this->close_xml_writer();
unset($this->currentsection);
}
}
108 changes: 61 additions & 47 deletions backup/converter/moodle1/lib.php
Expand Up @@ -120,7 +120,9 @@ protected function init() {
* Converts the contents of the tempdir into the target format in the workdir
*/
protected function execute() {
$this->create_stash_storage();
$this->xmlparser->process();
$this->drop_stash_storage();
}

/**
Expand Down Expand Up @@ -347,65 +349,59 @@ public function path_end_reached($path) {
}

/**
* Creates the backup_ids_temp table
*/
public function create_backup_ids_temp_table() {
backup_controller_dbops::create_backup_ids_temp_table($this->get_id());
}

/**
* Drops the backup_ids_temp table
*/
public function drop_backup_ids_temp_table() {
backup_controller_dbops::drop_backup_ids_temp_table($this->get_id());
}

/**
* Stores a record in the temporary backup_ids table
* Creates the temporary storage for stashed data
*
* @param string $itemname
* @param int $itemid
* @param int $newitemid
* @param int $parentitemid
* @param mixed $info
* @return void
* This implementation uses backup_ids_temp table.
*/
public function set_backup_ids_record($itemname, $itemid, $newitemid = 0, $parentitemid = null, $info = null) {
restore_dbops::set_backup_ids_record($this->get_id(), $itemname, $itemid, $newitemid, $parentitemid, $info);
public function create_stash_storage() {
backup_controller_dbops::create_backup_ids_temp_table($this->get_id());
}

/**
* Restores a previously saved record from backup_ids temporary table
* Drops the temporary storage of stashed data
*
* @param string $itemname
* @param int $itemid
* @return stdClass
* This implementation uses backup_ids_temp table.
*/
public function get_backup_ids_record($itemname, $itemid) {
return restore_dbops::get_backup_ids_record($this->get_id(), $itemname, $itemid);
public function drop_stash_storage() {
backup_controller_dbops::drop_backup_ids_temp_table($this->get_id());
}

/**
* Store some information for later processing
* Stores some information for later processing
*
* This implenentation uses backup_ids_temp table to store data. Make
* sure that the stash name is unique.
* This implementation uses backup_ids_temp table to store data. Make
* sure that the $stashname + $itemid combo is unique.
*
* @param string $stashname name of the stash
* @param mixed $info information to stash
* @param int $itemid optional id for multiple infos within the same stashname
*/
public function set_stash($stashname, $info) {
$this->set_backup_ids_record($stashname, 0, 0, null, $info);
public function set_stash($stashname, $info, $itemid = 0) {
try {
restore_dbops::set_backup_ids_record($this->get_id(), $stashname, $itemid, 0, null, $info);

} catch (dml_exception $e) {
throw new moodle1_convert_storage_exception('unable_to_restore_stash', null, $e->getMessage());
}
}

/**
* Restores a given stash stored previously by {@link self::set_stash()}
*
* @param string $stashname name of the stash
* @param int $itemid optional id for multiple infos within the same stashname
* @throws moodle1_convert_empty_storage_exception if the info has not been stashed previously
* @return mixed stashed data
*/
public function get_stash($stashname) {
return $this->get_backup_ids_record($stashname, 0);
public function get_stash($stashname, $itemid = 0) {

$record = restore_dbops::get_backup_ids_record($this->get_id(), $stashname, $itemid);

if (empty($record)) {
throw new moodle1_convert_empty_storage_exception('required_not_stashed_data');
} else {
return $record->info;
}
}

/**
Expand All @@ -415,34 +411,52 @@ public function get_stash($stashname) {
* 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) {
static $autoincrement = 0;

$itemname = 'context' . $level;
$itemid = $instance;
$stashname = 'context' . $level;

$existing = $this->get_backup_ids_record($itemname, $itemid);
$existing = $this->get_stash($stashname, $instance);

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);
}
$this->set_stash($stashname, $autoincrement++, $instance);
return $autoincrement;

return $existing->id;
} else {
return $existing;
}
}
}


/**
* Exception thrown by this converter
*/
class moodle1_convert_exception extends convert_exception {
}


/**
* Exception thrown by the temporary storage subsystem of moodle1_converter
*/
class moodle1_convert_storage_exception extends moodle1_convert_exception {
}


/**
* Exception thrown by the temporary storage subsystem of moodle1_converter
*/
class moodle1_convert_empty_storage_exception extends moodle1_convert_exception {
}


/**
* XML parser processor
*/
Expand Down
54 changes: 53 additions & 1 deletion backup/converter/moodle1/simpletest/testlib.php
Expand Up @@ -61,6 +61,58 @@ public function test_detect_format() {
public function test_convert_factory() {
$converter = convert_factory::converter('moodle1', $this->tempdir);
$this->assertIsA($converter, 'moodle1_converter');
$converter->convert();
}

public function test_stash_storage_not_created() {
$converter = convert_factory::converter('moodle1', $this->tempdir);
$this->expectException('moodle1_convert_storage_exception');
$converter->set_stash('tempinfo', 12);
}

public function test_stash_requiring_empty_stash() {
$converter = convert_factory::converter('moodle1', $this->tempdir);
$converter->create_stash_storage();
$converter->set_stash('tempinfo', 12);
$this->expectException('moodle1_convert_empty_storage_exception');
try {
$converter->get_stash('anothertempinfo');

} catch (moodle1_convert_empty_storage_exception $e) {
// we must drop the storage here so we are able to re-create it in the next test
$converter->drop_stash_storage();
throw new moodle1_convert_empty_storage_exception('rethrowing');
}
}

public function test_stash_storage() {
$converter = convert_factory::converter('moodle1', $this->tempdir);
$converter->create_stash_storage();

// test stashes without itemid
$converter->set_stash('tempinfo1', 12);
$converter->set_stash('tempinfo2', array('a' => 2, 'b' => 3));
$this->assertIdentical(12, $converter->get_stash('tempinfo1'));
$this->assertIdentical(array('a' => 2, 'b' => 3), $converter->get_stash('tempinfo2'));

// overwriting a stashed value is allowed
$converter->set_stash('tempinfo1', '13');
$this->assertNotIdentical(13, $converter->get_stash('tempinfo1'));
$this->assertIdentical('13', $converter->get_stash('tempinfo1'));

// repeated reading is allowed
$this->assertIdentical('13', $converter->get_stash('tempinfo1'));

// test stashes with itemid
$converter->set_stash('tempinfo', 'Hello', 1);
$converter->set_stash('tempinfo', 'World', 2);
$this->assertIdentical('Hello', $converter->get_stash('tempinfo', 1));
$this->assertIdentical('World', $converter->get_stash('tempinfo', 2));

$converter->drop_stash_storage();
}

public function test_convert_run_convert() {
$converter = convert_factory::converter('moodle1', $this->tempdir);
//$converter->convert();
}
}

0 comments on commit 9b5f1ad

Please sign in to comment.