1 <?php 2 3 // This file is part of Moodle - http://moodle.org/ 4 // 5 // Moodle is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // Moodle is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 17 18 /** 19 * Provides support for the conversion of moodle1 backup to the moodle2 format 20 * 21 * @package mod_workshop 22 * @copyright 2011 David Mudrak <david@moodle.com> 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 defined('MOODLE_INTERNAL') || die(); 27 28 /** 29 * Workshop conversion handler 30 */ 31 class moodle1_mod_workshop_handler extends moodle1_mod_handler { 32 33 /** @var array the temporary in-memory cache for the current <MOD> contents */ 34 protected $currentworkshop = null; 35 36 /** @var array in-memory cache for the course module information for the current workshop */ 37 protected $currentcminfo = null; 38 39 /** @var array the mapping of legacy elementno => newelementid for the current workshop */ 40 protected $newelementids = array(); 41 42 /** @var moodle1_file_manager for the current workshop */ 43 protected $fileman = null; 44 45 /** @var moodle1_inforef_manager */ 46 protected $inforefman = null; 47 48 /** @var array list of moodle1_workshopform_handler instances */ 49 private $strategyhandlers = null; 50 51 /** @var int parent id for the rubric level */ 52 private $currentelementid = null; 53 54 /** 55 * Declare the paths in moodle.xml we are able to convert 56 * 57 * The method returns list of {@link convert_path} instances. For each path returned, 58 * at least one of on_xxx_start(), process_xxx() and on_xxx_end() methods must be 59 * defined. The method process_xxx() is not executed if the associated path element is 60 * empty (i.e. it contains none elements or sub-paths only). 61 * 62 * Note that the path /MOODLE_BACKUP/COURSE/MODULES/MOD/WORKSHOP does not 63 * actually exist in the file. The last element with the module name was 64 * appended by the moodle1_converter class. 65 * 66 * @return array of {@link convert_path} instances 67 */ 68 public function get_paths() { 69 return array( 70 new convert_path('workshop', '/MOODLE_BACKUP/COURSE/MODULES/MOD/WORKSHOP'), 71 new convert_path('workshop_elements', '/MOODLE_BACKUP/COURSE/MODULES/MOD/WORKSHOP/ELEMENTS'), 72 new convert_path( 73 'workshop_element', '/MOODLE_BACKUP/COURSE/MODULES/MOD/WORKSHOP/ELEMENTS/ELEMENT', 74 array( 75 'dropfields' => array( 76 'stddev', 77 'totalassessments', 78 ), 79 ) 80 ), 81 new convert_path('workshop_element_rubric', '/MOODLE_BACKUP/COURSE/MODULES/MOD/WORKSHOP/ELEMENTS/ELEMENT/RUBRICS/RUBRIC'), 82 ); 83 } 84 85 /** 86 * This is executed every time we have one /MOODLE_BACKUP/COURSE/MODULES/MOD/WORKSHOP 87 * data available 88 */ 89 public function process_workshop($data, $raw) { 90 91 // re-use the upgrade function to convert workshop record 92 $fakerecord = (object)$data; 93 $fakerecord->course = 12345678; 94 $this->currentworkshop = (array)workshop_upgrade_transform_instance($fakerecord); 95 unset($this->currentworkshop['course']); 96 97 // add the new fields with the default values 98 $this->currentworkshop['id'] = $data['id']; 99 $this->currentworkshop['evaluation'] = 'best'; 100 $this->currentworkshop['examplesmode'] = workshop::EXAMPLES_VOLUNTARY; 101 $this->currentworkshop['gradedecimals'] = 0; 102 $this->currentworkshop['instructauthors'] = ''; 103 $this->currentworkshop['instructauthorsformat'] = FORMAT_HTML; 104 $this->currentworkshop['instructreviewers'] = ''; 105 $this->currentworkshop['instructreviewersformat'] = FORMAT_HTML; 106 $this->currentworkshop['latesubmissions'] = 0; 107 $this->currentworkshop['conclusion'] = ''; 108 $this->currentworkshop['conclusionformat'] = FORMAT_HTML; 109 110 foreach (array('submissionend', 'submissionstart', 'assessmentend', 'assessmentstart') as $field) { 111 if (!array_key_exists($field, $this->currentworkshop)) { 112 $this->currentworkshop[$field] = null; 113 } 114 } 115 116 // get the course module id and context id 117 $instanceid = $data['id']; 118 $this->currentcminfo = $this->get_cminfo($instanceid); 119 $moduleid = $this->currentcminfo['id']; 120 $contextid = $this->converter->get_contextid(CONTEXT_MODULE, $moduleid); 121 122 // get a fresh new inforef manager for this instance 123 $this->inforefman = $this->converter->get_inforef_manager('activity', $moduleid); 124 125 // get a fresh new file manager for this instance 126 $this->fileman = $this->converter->get_file_manager($contextid, 'mod_workshop'); 127 128 // convert course files embedded into the intro 129 $this->fileman->filearea = 'intro'; 130 $this->fileman->itemid = 0; 131 $this->currentworkshop['intro'] = moodle1_converter::migrate_referenced_files($this->currentworkshop['intro'], $this->fileman); 132 133 // write workshop.xml 134 $this->open_xml_writer("activities/workshop_{$moduleid}/workshop.xml"); 135 $this->xmlwriter->begin_tag('activity', array('id' => $instanceid, 'moduleid' => $moduleid, 136 'modulename' => 'workshop', 'contextid' => $contextid)); 137 $this->xmlwriter->begin_tag('workshop', array('id' => $instanceid)); 138 139 foreach ($this->currentworkshop as $field => $value) { 140 if ($field <> 'id') { 141 $this->xmlwriter->full_tag($field, $value); 142 } 143 } 144 145 return $this->currentworkshop; 146 } 147 148 /** 149 * This is executed when the parser reaches <ELEMENTS> 150 * 151 * The dimensions definition follows. One of the grading strategy subplugins 152 * will append dimensions data in {@link self::process_workshop_element()} 153 */ 154 public function on_workshop_elements_start() { 155 156 $this->xmlwriter->begin_tag('subplugin_workshopform_'.$this->currentworkshop['strategy'].'_workshop'); 157 158 // inform the strategy handler that a new workshop instance is being processed 159 $handler = $this->get_strategy_handler($this->currentworkshop['strategy']); 160 $handler->use_xml_writer($this->xmlwriter); 161 $handler->on_elements_start(); 162 } 163 164 /** 165 * Processes one <ELEMENT> tag from moodle.xml 166 */ 167 public function process_workshop_element($data, $raw) { 168 169 // generate artificial element id and remember it for later usage 170 $data['id'] = $this->converter->get_nextid(); 171 $this->currentelementid = $data['id']; 172 $this->newelementids[$data['elementno']] = $data['id']; 173 174 // let the strategy subplugin do whatever it needs to 175 $handler = $this->get_strategy_handler($this->currentworkshop['strategy']); 176 return $handler->process_legacy_element($data, $raw); 177 } 178 179 /** 180 * Processes one <RUBRIC> tag from moodle.xml 181 */ 182 public function process_workshop_element_rubric($data, $raw) { 183 if ($this->currentworkshop['strategy'] == 'rubric') { 184 $handler = $this->get_strategy_handler('rubric'); 185 $data['elementid'] = $this->currentelementid; 186 $handler->process_legacy_rubric($data, $raw); 187 } 188 } 189 190 /** 191 * This is executed when the parser reaches </ELEMENT> 192 */ 193 public function on_workshop_element_end() { 194 // give the strategy handlers a chance to write what they need 195 $handler = $this->get_strategy_handler($this->currentworkshop['strategy']); 196 $handler->on_legacy_element_end(); 197 } 198 199 /** 200 * This is executed when the parser reaches </ELEMENTS> 201 */ 202 public function on_workshop_elements_end() { 203 // give the strategy hanlders last chance to write what they need 204 $handler = $this->get_strategy_handler($this->currentworkshop['strategy']); 205 $handler->on_elements_end(); 206 207 // close the dimensions definition 208 $this->xmlwriter->end_tag('subplugin_workshopform_'.$this->currentworkshop['strategy'].'_workshop'); 209 210 // as a temporary hack, we just write empty wrappers for the rest of data 211 $this->write_xml('examplesubmissions', array()); 212 $this->write_xml('submissions', array()); 213 $this->write_xml('aggregations', array()); 214 } 215 216 /** 217 * This is executed when the parser reaches </MOD> 218 */ 219 public function on_workshop_end() { 220 // close workshop.xml 221 $this->xmlwriter->end_tag('workshop'); 222 $this->xmlwriter->end_tag('activity'); 223 $this->close_xml_writer(); 224 225 // write inforef.xml 226 $this->inforefman->add_refs('file', $this->fileman->get_fileids()); 227 $moduleid = $this->currentcminfo['id']; 228 $this->open_xml_writer("activities/workshop_{$moduleid}/inforef.xml"); 229 $this->inforefman->write_refs($this->xmlwriter); 230 $this->close_xml_writer(); 231 232 // get ready for the next instance 233 $this->currentworkshop = null; 234 $this->currentcminfo = null; 235 $this->newelementids = array(); 236 } 237 238 /** 239 * Provides access to the current <workshop> data 240 * 241 * @return array|null 242 */ 243 public function get_current_workshop() { 244 return $this->currentworkshop; 245 } 246 247 /** 248 * Provides access to the instance's inforef manager 249 * 250 * @return moodle1_inforef_manager 251 */ 252 public function get_inforef_manager() { 253 return $this->inforefman; 254 } 255 256 /// internal implementation details follow ///////////////////////////////// 257 258 /** 259 * Factory method returning the handler of the given grading strategy subplugin 260 * 261 * @param string $strategy the name of the grading strategy 262 * @throws moodle1_convert_exception 263 * @return moodle1_workshopform_handler the instance of the handler 264 */ 265 protected function get_strategy_handler($strategy) { 266 global $CFG; // we include other files here 267 268 if (is_null($this->strategyhandlers)) { 269 $this->strategyhandlers = array(); 270 $subplugins = core_component::get_plugin_list('workshopform'); 271 foreach ($subplugins as $name => $dir) { 272 $handlerfile = $dir.'/backup/moodle1/lib.php'; 273 $handlerclass = "moodle1_workshopform_{$name}_handler"; 274 if (!file_exists($handlerfile)) { 275 continue; 276 } 277 require_once($handlerfile); 278 279 if (!class_exists($handlerclass)) { 280 throw new moodle1_convert_exception('missing_handler_class', $handlerclass); 281 } 282 $this->log('preparing workshop grading strategy handler', backup::LOG_DEBUG, $handlerclass); 283 $this->strategyhandlers[$name] = new $handlerclass($this, $name); 284 if (!$this->strategyhandlers[$name] instanceof moodle1_workshopform_handler) { 285 throw new moodle1_convert_exception('wrong_handler_class', get_class($this->strategyhandlers[$name])); 286 } 287 } 288 } 289 290 if (!isset($this->strategyhandlers[$strategy])) { 291 throw new moodle1_convert_exception('usupported_subplugin', 'workshopform_'.$strategy); 292 } 293 294 return $this->strategyhandlers[$strategy]; 295 } 296 } 297 298 299 /** 300 * Base class for the grading strategy subplugin handler 301 */ 302 abstract class moodle1_workshopform_handler extends moodle1_submod_handler { 303 304 /** 305 * @param moodle1_mod_handler $workshophandler the handler of a module we are subplugin of 306 * @param string $subpluginname the name of the subplugin 307 */ 308 public function __construct(moodle1_mod_handler $workshophandler, $subpluginname) { 309 parent::__construct($workshophandler, 'workshopform', $subpluginname); 310 } 311 312 /** 313 * Provides a xml_writer instance to this workshopform handler 314 * 315 * @param xml_writer $xmlwriter 316 */ 317 public function use_xml_writer(xml_writer $xmlwriter) { 318 $this->xmlwriter = $xmlwriter; 319 } 320 321 /** 322 * Called when we reach <ELEMENTS> 323 * 324 * Gives the handler a chance to prepare for a new workshop instance 325 */ 326 public function on_elements_start() { 327 // do nothing by default 328 } 329 330 /** 331 * Called everytime when legacy <ELEMENT> data are available 332 * 333 * @param array $data legacy element data 334 * @param array $raw raw element data 335 * 336 * @return array converted 337 */ 338 public function process_legacy_element(array $data, array $raw) { 339 return $data; 340 } 341 342 /** 343 * Called when we reach </ELEMENT> 344 */ 345 public function on_legacy_element_end() { 346 // do nothing by default 347 } 348 349 /** 350 * Called when we reach </ELEMENTS> 351 */ 352 public function on_elements_end() { 353 // do nothing by default 354 } 355 } 356 357 /** 358 * Given a record containing data from 1.9 workshop table, returns object containing data as should be saved in 2.0 workshop table 359 * 360 * @param stdClass $old record from 1.9 workshop table 361 * @return stdClass 362 */ 363 function workshop_upgrade_transform_instance(stdClass $old) { 364 global $CFG; 365 require_once (__DIR__ . '/../../locallib.php'); 366 367 $new = new stdClass(); 368 $new->course = $old->course; 369 $new->name = $old->name; 370 $new->intro = $old->description; 371 $new->introformat = $old->format; 372 if ($old->nattachments == 0) { 373 // Convert to the new method for disabling file submissions. 374 $new->submissiontypefile = WORKSHOP_SUBMISSION_TYPE_DISABLED; 375 $new->submissiontypetext = WORKSHOP_SUBMISSION_TYPE_REQUIRED; 376 $new->nattachments = 1; 377 } else { 378 $new->nattachments = $old->nattachments; 379 } 380 $new->maxbytes = $old->maxbytes; 381 $new->grade = $old->grade; 382 $new->gradinggrade = $old->gradinggrade; 383 $new->phase = workshop::PHASE_CLOSED; 384 $new->timemodified = time(); 385 if ($old->ntassessments > 0) { 386 $new->useexamples = 1; 387 } else { 388 $new->useexamples = 0; 389 } 390 $new->usepeerassessment = 1; 391 $new->useselfassessment = $old->includeself; 392 switch ($old->gradingstrategy) { 393 case 0: // 'notgraded' - renamed 394 $new->strategy = 'comments'; 395 break; 396 case 1: // 'accumulative' 397 $new->strategy = 'accumulative'; 398 break; 399 case 2: // 'errorbanded' - renamed 400 $new->strategy = 'numerrors'; 401 break; 402 case 3: // 'criterion' - will be migrated into 'rubric' 403 $new->strategy = 'rubric'; 404 break; 405 case 4: // 'rubric' 406 $new->strategy = 'rubric'; 407 break; 408 } 409 if ($old->submissionstart < $old->submissionend) { 410 $new->submissionstart = $old->submissionstart; 411 $new->submissionend = $old->submissionend; 412 } 413 if ($old->assessmentstart < $old->assessmentend) { 414 $new->assessmentstart = $old->assessmentstart; 415 $new->assessmentend = $old->assessmentend; 416 } 417 418 return $new; 419 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body