mirror of
https://github.com/moodle/moodle.git
synced 2025-02-08 09:02:07 +01:00
Merge branch 'MDL-28006-convert-gradebook' of git://github.com/mudrd8mz/moodle
This commit is contained in:
commit
7ace3a2199
@ -52,6 +52,8 @@ abstract class moodle1_handlers_factory {
|
||||
new moodle1_roles_definition_handler($converter),
|
||||
new moodle1_question_bank_handler($converter),
|
||||
new moodle1_scales_handler($converter),
|
||||
new moodle1_outcomes_handler($converter),
|
||||
new moodle1_gradebook_handler($converter),
|
||||
);
|
||||
|
||||
$handlers = array_merge($handlers, self::get_plugin_handlers('mod', $converter));
|
||||
@ -927,10 +929,23 @@ class moodle1_course_outline_handler extends moodle1_xml_handler {
|
||||
$this->write_xml('module', $cminfo, array('/module/id', '/module/version'));
|
||||
$this->close_xml_writer();
|
||||
|
||||
// todo: write proper grades.xml and roles.xml, for now we just make
|
||||
// sure that those files are present
|
||||
// write grades.xml
|
||||
$this->open_xml_writer($directory.'/grades.xml');
|
||||
$this->xmlwriter->begin_tag('activity_gradebook');
|
||||
$gradeitems = $this->converter->get_stash_or_default('gradebook_modgradeitem_'.$modname, $modinstanceid, array());
|
||||
if (!empty($gradeitems)) {
|
||||
$this->xmlwriter->begin_tag('grade_items');
|
||||
foreach ($gradeitems as $gradeitem) {
|
||||
$this->write_xml('grade_item', $gradeitem, array('/grade_item/id'));
|
||||
}
|
||||
$this->xmlwriter->end_tag('grade_items');
|
||||
}
|
||||
$this->write_xml('grade_letters', array()); // no grade_letters in module context in Moodle 1.9
|
||||
$this->xmlwriter->end_tag('activity_gradebook');
|
||||
$this->close_xml_writer();
|
||||
|
||||
// todo: write proper roles.xml, for now we just make sure the file is present
|
||||
$this->make_sure_xml_exists($directory.'/roles.xml', 'roles');
|
||||
$this->make_sure_xml_exists($directory.'/grades.xml', 'activity_gradebook');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1319,7 +1334,7 @@ class moodle1_scales_handler extends moodle1_handler {
|
||||
protected $fileman = null;
|
||||
|
||||
/**
|
||||
* Registers path that are not qtype-specific
|
||||
* Registers paths
|
||||
*/
|
||||
public function get_paths() {
|
||||
return array(
|
||||
@ -1372,6 +1387,272 @@ class moodle1_scales_handler extends moodle1_handler {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles the conversion of the outcomes
|
||||
*/
|
||||
class moodle1_outcomes_handler extends moodle1_xml_handler {
|
||||
|
||||
/** @var moodle1_file_manager instance used to convert images embedded into outcome descriptions */
|
||||
protected $fileman = null;
|
||||
|
||||
/**
|
||||
* Registers paths
|
||||
*/
|
||||
public function get_paths() {
|
||||
return array(
|
||||
new convert_path('gradebook_grade_outcomes', '/MOODLE_BACKUP/COURSE/GRADEBOOK/GRADE_OUTCOMES'),
|
||||
new convert_path(
|
||||
'gradebook_grade_outcome', '/MOODLE_BACKUP/COURSE/GRADEBOOK/GRADE_OUTCOMES/GRADE_OUTCOME',
|
||||
array(
|
||||
'addfields' => array(
|
||||
'descriptionformat' => FORMAT_MOODLE,
|
||||
),
|
||||
)
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the file manager and starts writing outcomes.xml
|
||||
*/
|
||||
public function on_gradebook_grade_outcomes_start() {
|
||||
|
||||
$syscontextid = $this->converter->get_contextid(CONTEXT_SYSTEM);
|
||||
$this->fileman = $this->converter->get_file_manager($syscontextid, 'grade', 'outcome');
|
||||
|
||||
$this->open_xml_writer('outcomes.xml');
|
||||
$this->xmlwriter->begin_tag('outcomes_definition');
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes GRADE_OUTCOME tags progressively
|
||||
*/
|
||||
public function process_gradebook_grade_outcome(array $data, array $raw) {
|
||||
global $CFG;
|
||||
|
||||
// replay the upgrade step 2009110400
|
||||
if ($CFG->texteditors !== 'textarea') {
|
||||
$data['description'] = text_to_html($data['description'], false, false, true);
|
||||
$data['descriptionformat'] = FORMAT_HTML;
|
||||
}
|
||||
|
||||
// convert course files embedded into the outcome description field
|
||||
$this->fileman->itemid = $data['id'];
|
||||
$data['description'] = moodle1_converter::migrate_referenced_files($data['description'], $this->fileman);
|
||||
|
||||
// write the outcome data
|
||||
$this->write_xml('outcome', $data, array('/outcome/id'));
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes outcomes.xml
|
||||
*/
|
||||
public function on_gradebook_grade_outcomes_end() {
|
||||
$this->xmlwriter->end_tag('outcomes_definition');
|
||||
$this->close_xml_writer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles the conversion of the gradebook structures in the moodle.xml file
|
||||
*/
|
||||
class moodle1_gradebook_handler extends moodle1_xml_handler {
|
||||
|
||||
/** @var array of (int)gradecategoryid => (int|null)parentcategoryid */
|
||||
protected $categoryparent = array();
|
||||
|
||||
/**
|
||||
* Registers paths
|
||||
*/
|
||||
public function get_paths() {
|
||||
return array(
|
||||
new convert_path('gradebook', '/MOODLE_BACKUP/COURSE/GRADEBOOK'),
|
||||
new convert_path('gradebook_grade_letter', '/MOODLE_BACKUP/COURSE/GRADEBOOK/GRADE_LETTERS/GRADE_LETTER'),
|
||||
new convert_path(
|
||||
'gradebook_grade_category', '/MOODLE_BACKUP/COURSE/GRADEBOOK/GRADE_CATEGORIES/GRADE_CATEGORY',
|
||||
array(
|
||||
'addfields' => array(
|
||||
'hidden' => 0, // upgrade step 2010011200
|
||||
),
|
||||
)
|
||||
),
|
||||
new convert_path('gradebook_grade_item', '/MOODLE_BACKUP/COURSE/GRADEBOOK/GRADE_ITEMS/GRADE_ITEM'),
|
||||
new convert_path('gradebook_grade_item_grades', '/MOODLE_BACKUP/COURSE/GRADEBOOK/GRADE_ITEMS/GRADE_ITEM/GRADE_GRADES'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the in-memory structures
|
||||
*
|
||||
* This should not be needed actually as the moodle.xml contains just one GRADEBOOK
|
||||
* element. But who knows - maybe someone will want to write a mass conversion
|
||||
* tool in the future (not me definitely ;-)
|
||||
*/
|
||||
public function on_gradebook_start() {
|
||||
$this->categoryparent = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes one GRADE_LETTER data
|
||||
*
|
||||
* In Moodle 1.9, all grade_letters are from course context only. Therefore
|
||||
* we put them here.
|
||||
*/
|
||||
public function process_gradebook_grade_letter(array $data, array $raw) {
|
||||
$this->converter->set_stash('gradebook_gradeletter', $data, $data['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes one GRADE_CATEGORY data
|
||||
*/
|
||||
public function process_gradebook_grade_category(array $data, array $raw) {
|
||||
$this->categoryparent[$data['id']] = $data['parent'];
|
||||
$this->converter->set_stash('gradebook_gradecategory', $data, $data['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes one GRADE_ITEM data
|
||||
*/
|
||||
public function process_gradebook_grade_item(array $data, array $raw) {
|
||||
|
||||
// here we use get_nextid() to get a nondecreasing sequence
|
||||
$data['sortorder'] = $this->converter->get_nextid();
|
||||
|
||||
if ($data['itemtype'] === 'mod') {
|
||||
return $this->process_mod_grade_item($data, $raw);
|
||||
|
||||
} else if (in_array($data['itemtype'], array('manual', 'course', 'category'))) {
|
||||
return $this->process_nonmod_grade_item($data, $raw);
|
||||
|
||||
} else {
|
||||
$this->log('unsupported grade_item type', backup::LOG_ERROR, $data['itemtype']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes one GRADE_ITEM of the type 'mod'
|
||||
*/
|
||||
protected function process_mod_grade_item(array $data, array $raw) {
|
||||
|
||||
$stashname = 'gradebook_modgradeitem_'.$data['itemmodule'];
|
||||
$stashitemid = $data['iteminstance'];
|
||||
$gradeitems = $this->converter->get_stash_or_default($stashname, $stashitemid, array());
|
||||
|
||||
// typically there will be single item with itemnumber 0
|
||||
$gradeitems[$data['itemnumber']] = $data;
|
||||
|
||||
$this->converter->set_stash($stashname, $gradeitems, $stashitemid);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes one GRADE_ITEM of te type 'manual' or 'course' or 'category'
|
||||
*/
|
||||
protected function process_nonmod_grade_item(array $data, array $raw) {
|
||||
|
||||
$stashname = 'gradebook_nonmodgradeitem';
|
||||
$stashitemid = $data['id'];
|
||||
$this->converter->set_stash($stashname, $data, $stashitemid);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo
|
||||
*/
|
||||
public function on_gradebook_grade_item_grades_start() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the collected information into gradebook.xml
|
||||
*/
|
||||
public function on_gradebook_end() {
|
||||
|
||||
$this->open_xml_writer('gradebook.xml');
|
||||
$this->xmlwriter->begin_tag('gradebook');
|
||||
$this->write_grade_categories();
|
||||
$this->write_grade_items();
|
||||
$this->write_grade_letters();
|
||||
$this->xmlwriter->end_tag('gradebook');
|
||||
$this->close_xml_writer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes grade_categories
|
||||
*/
|
||||
protected function write_grade_categories() {
|
||||
|
||||
$this->xmlwriter->begin_tag('grade_categories');
|
||||
foreach ($this->converter->get_stash_itemids('gradebook_gradecategory') as $gradecategoryid) {
|
||||
$gradecategory = $this->converter->get_stash('gradebook_gradecategory', $gradecategoryid);
|
||||
$path = $this->calculate_category_path($gradecategoryid);
|
||||
$gradecategory['depth'] = count($path);
|
||||
$gradecategory['path'] = '/'.implode('/', $path).'/';
|
||||
$this->write_xml('grade_category', $gradecategory, array('/grade_category/id'));
|
||||
}
|
||||
$this->xmlwriter->end_tag('grade_categories');
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the path to the grade_category
|
||||
*
|
||||
* Moodle 1.9 backup does not store the grade_category's depth and path. This method is used
|
||||
* to repopulate this information using the $this->categoryparent values.
|
||||
*
|
||||
* @param int $categoryid
|
||||
* @return array of ids including the categoryid
|
||||
*/
|
||||
protected function calculate_category_path($categoryid) {
|
||||
|
||||
if (!array_key_exists($categoryid, $this->categoryparent)) {
|
||||
throw new moodle1_convert_exception('gradebook_unknown_categoryid', null, $categoryid);
|
||||
}
|
||||
|
||||
$path = array($categoryid);
|
||||
$parent = $this->categoryparent[$categoryid];
|
||||
while (!is_null($parent)) {
|
||||
array_unshift($path, $parent);
|
||||
$parent = $this->categoryparent[$parent];
|
||||
if (in_array($parent, $path)) {
|
||||
throw new moodle1_convert_exception('circular_reference_in_categories_tree');
|
||||
}
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes grade_items
|
||||
*/
|
||||
protected function write_grade_items() {
|
||||
|
||||
$this->xmlwriter->begin_tag('grade_items');
|
||||
foreach ($this->converter->get_stash_itemids('gradebook_nonmodgradeitem') as $gradeitemid) {
|
||||
$gradeitem = $this->converter->get_stash('gradebook_nonmodgradeitem', $gradeitemid);
|
||||
$this->write_xml('grade_item', $gradeitem, array('/grade_item/id'));
|
||||
}
|
||||
$this->xmlwriter->end_tag('grade_items');
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes grade_letters
|
||||
*/
|
||||
protected function write_grade_letters() {
|
||||
|
||||
$this->xmlwriter->begin_tag('grade_letters');
|
||||
foreach ($this->converter->get_stash_itemids('gradebook_gradeletter') as $gradeletterid) {
|
||||
$gradeletter = $this->converter->get_stash('gradebook_gradeletter', $gradeletterid);
|
||||
$this->write_xml('grade_letter', $gradeletter, array('/grade_letter/id'));
|
||||
}
|
||||
$this->xmlwriter->end_tag('grade_letters');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shared base class for activity modules, blocks and qtype handlers
|
||||
*/
|
||||
|
@ -470,6 +470,22 @@ class moodle1_converter extends base_converter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores a given stash or returns the given default if there is no such stash
|
||||
*
|
||||
* @param string $stashname name of the stash
|
||||
* @param int $itemid optional id for multiple infos within the same stashname
|
||||
* @param mixed $default information to return if the info has not been stashed previously
|
||||
* @return mixed stashed data or the default value
|
||||
*/
|
||||
public function get_stash_or_default($stashname, $itemid = 0, $default = null) {
|
||||
try {
|
||||
return $this->get_stash($stashname, $itemid);
|
||||
} catch (moodle1_convert_empty_storage_exception $e) {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of existing stashes
|
||||
*
|
||||
|
@ -160,6 +160,38 @@ class moodle1_converter_test extends UnitTestCase {
|
||||
$converter->drop_stash_storage();
|
||||
}
|
||||
|
||||
public function test_get_stash_or_default() {
|
||||
$converter = convert_factory::get_converter('moodle1', $this->tempdir);
|
||||
$converter->create_stash_storage();
|
||||
|
||||
$this->assertTrue(is_null($converter->get_stash_or_default('stashname')));
|
||||
$this->assertTrue(is_null($converter->get_stash_or_default('stashname', 7)));
|
||||
$this->assertTrue('default' === $converter->get_stash_or_default('stashname', 0, 'default'));
|
||||
$this->assertTrue(array('foo', 'bar') === $converter->get_stash_or_default('stashname', 42, array('foo', 'bar')));
|
||||
|
||||
//$converter->set_stash('stashname', 0);
|
||||
//$this->assertFalse(is_null($converter->get_stash_or_default('stashname'))); // todo returns true now, this needs MDL-27713 to be fixed
|
||||
|
||||
//$converter->set_stash('stashname', '');
|
||||
//$this->assertFalse(is_null($converter->get_stash_or_default('stashname'))); // todo returns true now, this needs MDL-27713 to be fixed
|
||||
|
||||
//$converter->set_stash('stashname', array());
|
||||
//$this->assertFalse(is_null($converter->get_stash_or_default('stashname'))); // todo returns true now, this needs MDL-27713 to be fixed
|
||||
|
||||
$converter->set_stash('stashname', 42);
|
||||
$this->assertTrue(42 === $converter->get_stash_or_default('stashname'));
|
||||
$this->assertTrue(is_null($converter->get_stash_or_default('stashname', 1)));
|
||||
$this->assertTrue(42 === $converter->get_stash_or_default('stashname', 0, 61));
|
||||
|
||||
$converter->set_stash('stashname', array(42 => (object)array('id' => 42)), 18);
|
||||
$stashed = $converter->get_stash_or_default('stashname', 18, 1984);
|
||||
$this->assertIsA($stashed, 'array');
|
||||
$this->assertTrue(is_object($stashed[42]));
|
||||
$this->assertTrue($stashed[42]->id === 42);
|
||||
|
||||
$converter->drop_stash_storage();
|
||||
}
|
||||
|
||||
public function test_get_contextid() {
|
||||
$converter = convert_factory::get_converter('moodle1', $this->tempdir);
|
||||
|
||||
|
@ -146,12 +146,18 @@ class restore_gradebook_structure_step extends restore_structure_step {
|
||||
|
||||
$data->courseid = $this->get_courseid();
|
||||
|
||||
//manual grade items store category id in categoryid
|
||||
if ($data->itemtype=='manual') {
|
||||
// manual grade items store category id in categoryid
|
||||
$data->categoryid = $this->get_mappingid('grade_category', $data->categoryid, NULL);
|
||||
} //course and category grade items store their category id in iteminstance
|
||||
else if ($data->itemtype=='course' || $data->itemtype=='category') {
|
||||
} else if ($data->itemtype=='course') {
|
||||
// course grade item stores their category id in iteminstance
|
||||
$coursecat = grade_category::fetch_course_category($this->get_courseid());
|
||||
$data->iteminstance = $coursecat->id;
|
||||
} else if ($data->itemtype=='category') {
|
||||
// category grade items store their category id in iteminstance
|
||||
$data->iteminstance = $this->get_mappingid('grade_category', $data->iteminstance, NULL);
|
||||
} else {
|
||||
throw new restore_step_exception('unexpected_grade_item_type', $data->itemtype);
|
||||
}
|
||||
|
||||
$data->scaleid = $this->get_mappingid('scale', $data->scaleid, NULL);
|
||||
@ -300,14 +306,18 @@ class restore_gradebook_structure_step extends restore_structure_step {
|
||||
|
||||
//if this is an activity grade item that needs to be put back in its correct category
|
||||
if (!empty($grade_item_backup->parentitemid)) {
|
||||
$updateobj->categoryid = $this->get_mappingid('grade_category', $grade_item_backup->parentitemid);
|
||||
$oldcategoryid = $this->get_mappingid('grade_category', $grade_item_backup->parentitemid, null);
|
||||
if (!is_null($oldcategoryid)) {
|
||||
$updateobj->categoryid = $oldcategoryid;
|
||||
$DB->update_record('grade_items', $updateobj);
|
||||
}
|
||||
} else {
|
||||
//mark course and category items as needing to be recalculated
|
||||
$updateobj->needsupdate=1;
|
||||
}
|
||||
$DB->update_record('grade_items', $updateobj);
|
||||
}
|
||||
}
|
||||
}
|
||||
$rs->close();
|
||||
|
||||
// We need to update the calculations for calculated grade items that may reference old
|
||||
|
@ -89,7 +89,7 @@ abstract class convert_helper {
|
||||
$filepath = $dirpath . '/moodle_backup.xml';
|
||||
|
||||
if (!is_dir($dirpath)) {
|
||||
throw new converter_helper_exception('tmp_backup_directory_not_found', $dirpath);
|
||||
throw new convert_helper_exception('tmp_backup_directory_not_found', $dirpath);
|
||||
}
|
||||
|
||||
if (!file_exists($filepath)) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user