protected function define_structure() { $userinfo = $this->get_setting_value('userinfo'); // Define each element separated. $chat = new backup_nested_element('chat', array('id'), array('name', 'intro', 'introformat', 'keepdays', 'studentlogs', 'chattime', 'schedule', 'timemodified')); $messages = new backup_nested_element('messages'); $message = new backup_nested_element('message', array('id'), array('userid', 'groupid', 'system', 'message_text', 'timestamp')); // It is not cool to have two tags with same name, so we need to rename message field to message_text. $message->set_source_alias('message', 'message_text'); // Build the tree. $chat->add_child($messages); $messages->add_child($message); // Define sources. $chat->set_source_table('chat', array('id' => backup::VAR_ACTIVITYID)); // User related messages only happen if we are including user info. if ($userinfo) { $message->set_source_table('chat_messages', array('chatid' => backup::VAR_PARENTID)); } // Define id annotations. $message->annotate_ids('user', 'userid'); $message->annotate_ids('group', 'groupid'); // Annotate the file areas in chat module. $chat->annotate_files('mod_chat', 'intro', null); // The chat_intro area doesn't use itemid. // Return the root element (chat), wrapped into standard activity structure. return $this->prepare_activity_structure($chat); }
protected function define_structure() { // The lesson table // This table contains all of the goodness for the lesson module, quite // alot goes into it but nothing relational other than course when will // need to be corrected upon restore $lesson = new backup_nested_element('lesson', array('id'), array('course', 'name', 'practice', 'modattempts', 'usepassword', 'password', 'dependency', 'conditions', 'grade', 'custom', 'ongoing', 'usemaxgrade', 'maxanswers', 'maxattempts', 'review', 'nextpagedefault', 'feedback', 'minquestions', 'maxpages', 'timed', 'maxtime', 'retake', 'activitylink', 'mediafile', 'mediaheight', 'mediawidth', 'mediaclose', 'slideshow', 'width', 'height', 'bgcolor', 'displayleft', 'displayleftif', 'progressbar', 'showhighscores', 'maxhighscores', 'available', 'deadline', 'timemodified')); // Tell the lesson element about the showhighscores elements mapping to the highscores // database field. $lesson->set_source_alias('highscores', 'showhighscores'); // The lesson_pages table // Grouped within a `pages` element, important to note that page is relational // to the lesson, and also to the previous/next page in the series. // Upon restore prevpageid and nextpageid will need to be corrected. $pages = new backup_nested_element('pages'); $page = new backup_nested_element('page', array('id'), array('prevpageid', 'nextpageid', 'qtype', 'qoption', 'layout', 'display', 'timecreated', 'timemodified', 'title', 'contents', 'contentsformat')); // The lesson_answers table // Grouped within an answers `element`, the lesson_answers table relates // to the page and lesson with `pageid` and `lessonid` that will both need // to be corrected during restore. $answers = new backup_nested_element('answers'); $answer = new backup_nested_element('answer', array('id'), array('jumpto', 'grade', 'score', 'flags', 'timecreated', 'timemodified', 'answer_text', 'response', 'answerformat', 'responseformat')); // Tell the answer element about the answer_text elements mapping to the answer // database field. $answer->set_source_alias('answer', 'answer_text'); // The lesson_attempts table // Grouped by an `attempts` element this is relational to the page, lesson, // and user. $attempts = new backup_nested_element('attempts'); $attempt = new backup_nested_element('attempt', array('id'), array('userid', 'retry', 'correct', 'useranswer', 'timeseen')); // The lesson_branch table // Grouped by a `branch` element this is relational to the page, lesson, // and user. $branches = new backup_nested_element('branches'); $branch = new backup_nested_element('branch', array('id'), array('userid', 'retry', 'flag', 'timeseen')); // The lesson_grades table // Grouped by a grades element this is relational to the lesson and user. $grades = new backup_nested_element('grades'); $grade = new backup_nested_element('grade', array('id'), array('userid', 'grade', 'late', 'completed')); // The lesson_high_scores table // Grouped by a highscores element this is relational to the lesson, user, // and possibly a grade. $highscores = new backup_nested_element('highscores'); $highscore = new backup_nested_element('highscore', array('id'), array('gradeid', 'userid', 'nickname')); // The lesson_timer table // Grouped by a `timers` element this is relational to the lesson and user. $timers = new backup_nested_element('timers'); $timer = new backup_nested_element('timer', array('id'), array('userid', 'starttime', 'lessontime')); // Now that we have all of the elements created we've got to put them // together correctly. $lesson->add_child($pages); $pages->add_child($page); $page->add_child($answers); $answers->add_child($answer); $answer->add_child($attempts); $attempts->add_child($attempt); $page->add_child($branches); $branches->add_child($branch); $lesson->add_child($grades); $grades->add_child($grade); $lesson->add_child($highscores); $highscores->add_child($highscore); $lesson->add_child($timers); $timers->add_child($timer); // Set the source table for the elements that aren't reliant on the user // at this point (lesson, lesson_pages, lesson_answers) $lesson->set_source_table('lesson', array('id' => backup::VAR_ACTIVITYID)); //we use SQL here as it must be ordered by prevpageid so that restore gets the pages in the right order. $page->set_source_table('lesson_pages', array('lessonid' => backup::VAR_PARENTID), 'prevpageid ASC'); // We use SQL here as answers must be ordered by id so that the restore gets them in the right order $answer->set_source_table('lesson_answers', array('pageid' => backup::VAR_PARENTID), 'id ASC'); // Check if we are also backing up user information if ($this->get_setting_value('userinfo')) { // Set the source table for elements that are reliant on the user // lesson_attempts, lesson_branch, lesson_grades, lesson_high_scores, lesson_timer $attempt->set_source_table('lesson_attempts', array('answerid' => backup::VAR_PARENTID)); $branch->set_source_table('lesson_branch', array('pageid' => backup::VAR_PARENTID)); $grade->set_source_table('lesson_grades', array('lessonid' => backup::VAR_PARENTID)); $highscore->set_source_table('lesson_high_scores', array('lessonid' => backup::VAR_PARENTID)); $timer->set_source_table('lesson_timer', array('lessonid' => backup::VAR_PARENTID)); } // Annotate the user id's where required. $attempt->annotate_ids('user', 'userid'); $branch->annotate_ids('user', 'userid'); $grade->annotate_ids('user', 'userid'); $highscore->annotate_ids('user', 'userid'); $timer->annotate_ids('user', 'userid'); // Annotate the file areas in user by the lesson module. $lesson->annotate_files('mod_lesson', 'mediafile', null); $page->annotate_files('mod_lesson', 'page_contents', 'id'); // Prepare and return the structure we have just created for the lesson module. return $this->prepare_activity_structure($lesson); }
/** * Backup structures wrong tests (trying to do things the wrong way) */ function test_backup_structure_wrong() { // Instantiate the backup processor $processor = new backup_structure_processor(new xml_writer(new memory_xml_output())); $this->assertTrue($processor instanceof base_processor); // Set one var twice $processor->set_var('onenewvariable', 999); try { $processor->set_var('onenewvariable', 999); $this->assertTrue(false, 'backup_processor_exception expected'); } catch (exception $e) { $this->assertTrue($e instanceof backup_processor_exception); $this->assertEquals($e->errorcode, 'processorvariablealreadyset'); $this->assertEquals($e->a, 'onenewvariable'); } // Get non-existing var try { $var = $processor->get_var('nonexistingvar'); $this->assertTrue(false, 'backup_processor_exception expected'); } catch (exception $e) { $this->assertTrue($e instanceof backup_processor_exception); $this->assertEquals($e->errorcode, 'processorvariablenotfound'); $this->assertEquals($e->a, 'nonexistingvar'); } // Create nested element and try ro get its parent id (doesn't exisit => exception) $ne = new backup_nested_element('test', 'one', 'two', 'three'); try { $ne->set_source_table('forum', array('id' => backup::VAR_PARENTID)); $ne->process($processor); $this->assertTrue(false, 'base_element_struct_exception expected'); } catch (exception $e) { $this->assertTrue($e instanceof base_element_struct_exception); $this->assertEquals($e->errorcode, 'cannotfindparentidforelement'); } // Try to process one nested/final/attribute elements without processor $ne = new backup_nested_element('test', 'one', 'two', 'three'); try { $ne->process(new stdclass()); $this->assertTrue(false, 'base_element_struct_exception expected'); } catch (exception $e) { $this->assertTrue($e instanceof base_element_struct_exception); $this->assertEquals($e->errorcode, 'incorrect_processor'); } $fe = new backup_final_element('test'); try { $fe->process(new stdclass()); $this->assertTrue(false, 'base_element_struct_exception expected'); } catch (exception $e) { $this->assertTrue($e instanceof base_element_struct_exception); $this->assertEquals($e->errorcode, 'incorrect_processor'); } $at = new backup_attribute('test'); try { $at->process(new stdclass()); $this->assertTrue(false, 'base_element_struct_exception expected'); } catch (exception $e) { $this->assertTrue($e instanceof base_element_struct_exception); $this->assertEquals($e->errorcode, 'incorrect_processor'); } // Try to put an incorrect alias $ne = new backup_nested_element('test', 'one', 'two', 'three'); try { $ne->set_source_alias('last', 'nonexisting'); $this->assertTrue(false, 'base_element_struct_exception expected'); } catch (exception $e) { $this->assertTrue($e instanceof base_element_struct_exception); $this->assertEquals($e->errorcode, 'incorrectaliasfinalnamenotfound'); $this->assertEquals($e->a, 'nonexisting'); } // Try various incorrect paths specifying source $ne = new backup_nested_element('test', 'one', 'two', 'three'); try { $ne->set_source_table('forum', array('/test/subtest')); $this->assertTrue(false, 'base_element_struct_exception expected'); } catch (exception $e) { $this->assertTrue($e instanceof base_element_struct_exception); $this->assertEquals($e->errorcode, 'baseelementincorrectfinalorattribute'); $this->assertEquals($e->a, 'subtest'); } try { $ne->set_source_table('forum', array('/wrongtest')); $this->assertTrue(false, 'base_element_struct_exception expected'); } catch (exception $e) { $this->assertTrue($e instanceof base_element_struct_exception); $this->assertEquals($e->errorcode, 'baseelementincorrectgrandparent'); $this->assertEquals($e->a, 'wrongtest'); } try { $ne->set_source_table('forum', array('../nonexisting')); $this->assertTrue(false, 'base_element_struct_exception expected'); } catch (exception $e) { $this->assertTrue($e instanceof base_element_struct_exception); $this->assertEquals($e->errorcode, 'baseelementincorrectparent'); $this->assertEquals($e->a, '..'); } // Try various incorrect file annotations $ne = new backup_nested_element('test', 'one', 'two', 'three'); $ne->annotate_files('test', 'filearea', null); try { $ne->annotate_files('test', 'filearea', null); // Try to add annotations twice $this->assertTrue(false, 'base_element_struct_exception expected'); } catch (exception $e) { $this->assertTrue($e instanceof base_element_struct_exception); $this->assertEquals($e->errorcode, 'annotate_files_duplicate_annotation'); $this->assertEquals($e->a, 'test/filearea/'); } $ne = new backup_nested_element('test', 'one', 'two', 'three'); try { $ne->annotate_files('test', 'filearea', 'four'); // Incorrect element $this->assertTrue(false, 'base_element_struct_exception expected'); } catch (exception $e) { $this->assertTrue($e instanceof base_element_struct_exception); $this->assertEquals($e->errorcode, 'baseelementincorrectfinalorattribute'); $this->assertEquals($e->a, 'four'); } // Try to add incorrect element to backup_optigroup $bog = new backup_optigroup('test'); try { $bog->add_child(new backup_nested_element('test2')); $this->assertTrue(false, 'base_optigroup_exception expected'); } catch (exception $e) { $this->assertTrue($e instanceof base_optigroup_exception); $this->assertEquals($e->errorcode, 'optigroup_element_incorrect'); $this->assertEquals($e->a, 'backup_nested_element'); } $bog = new backup_optigroup('test'); try { $bog->add_child('test2'); $this->assertTrue(false, 'base_optigroup_exception expected'); } catch (exception $e) { $this->assertTrue($e instanceof base_optigroup_exception); $this->assertEquals($e->errorcode, 'optigroup_element_incorrect'); $this->assertEquals($e->a, 'non object'); } try { $bog = new backup_optigroup('test', new stdclass()); $this->assertTrue(false, 'base_optigroup_exception expected'); } catch (exception $e) { $this->assertTrue($e instanceof base_optigroup_exception); $this->assertEquals($e->errorcode, 'optigroup_elements_incorrect'); } // Try a wrong processor with backup_optigroup $bog = new backup_optigroup('test'); try { $bog->process(new stdclass()); $this->assertTrue(false, 'base_element_struct_exception expected'); } catch (exception $e) { $this->assertTrue($e instanceof base_element_struct_exception); $this->assertEquals($e->errorcode, 'incorrect_processor'); } // Try duplicating used elements with backup_optigroup // Adding top->down $bog = new backup_optigroup('test', null, true); $boge1 = new backup_optigroup_element('boge1'); $boge2 = new backup_optigroup_element('boge2'); $ne1 = new backup_nested_element('ne1'); $ne2 = new backup_nested_element('ne1'); $bog->add_child($boge1); $bog->add_child($boge2); $boge1->add_child($ne1); try { $boge2->add_child($ne2); $this->assertTrue(false, 'base_optigroup_exception expected'); } catch (exception $e) { $this->assertTrue($e instanceof base_optigroup_exception); $this->assertEquals($e->errorcode, 'multiple_optigroup_duplicate_element'); $this->assertEquals($e->a, 'ne1'); } // Adding down->top $bog = new backup_optigroup('test', null, true); $boge1 = new backup_optigroup_element('boge1'); $boge2 = new backup_optigroup_element('boge2'); $ne1 = new backup_nested_element('ne1'); $ne2 = new backup_nested_element('ne1'); $boge1->add_child($ne1); $boge2->add_child($ne2); $bog->add_child($boge1); try { $bog->add_child($boge2); $this->assertTrue(false, 'base_element_struct_exception expected'); } catch (exception $e) { $this->assertTrue($e instanceof base_element_struct_exception); $this->assertEquals($e->errorcode, 'baseelementexisting'); $this->assertEquals($e->a, 'ne1'); } }
protected function define_structure() { // Define each element separated $section = new backup_nested_element('section', array('id'), array('number', 'name', 'summary', 'summaryformat', 'sequence', 'visible')); // Define sources $section->set_source_table('course_sections', array('id' => backup::VAR_SECTIONID)); // Aliases $section->set_source_alias('section', 'number'); // Set annotations $section->annotate_files('course', 'section', 'id'); return $section; }
protected function define_structure() { // To know if we are including userinfo $userinfo = $this->get_setting_value('userinfo'); // Define each element separated $quiz = new backup_nested_element('quiz', array('id'), array('name', 'intro', 'introformat', 'timeopen', 'timeclose', 'optionflags', 'penaltyscheme', 'attempts_number', 'attemptonlast', 'grademethod', 'decimalpoints', 'questiondecimalpoints', 'review', 'questionsperpage', 'shufflequestions', 'shuffleanswers', 'questions', 'sumgrades', 'grade', 'timecreated', 'timemodified', 'timelimit', 'password', 'subnet', 'popup', 'delay1', 'delay2', 'showuserpicture', 'showblocks')); $qinstances = new backup_nested_element('question_instances'); $qinstance = new backup_nested_element('question_instance', array('id'), array('question', 'grade')); $feedbacks = new backup_nested_element('feedbacks'); $feedback = new backup_nested_element('feedback', array('id'), array('feedbacktext', 'feedbacktextformat', 'mingrade', 'maxgrade')); $overrides = new backup_nested_element('overrides'); $override = new backup_nested_element('override', array('id'), array('userid', 'groupid', 'timeopen', 'timeclose', 'timelimit', 'attempts', 'password')); $grades = new backup_nested_element('grades'); $grade = new backup_nested_element('grade', array('id'), array('userid', 'gradeval', 'timemodified')); $attempts = new backup_nested_element('attempts'); $attempt = new backup_nested_element('attempt', array('id'), array('uniqueid', 'userid', 'attemptnum', 'sumgrades', 'timestart', 'timefinish', 'timemodified', 'layout', 'preview')); // This module is using questions, so produce the related question states and sessions // attaching them to the $attempt element based in 'uniqueid' matching $this->add_question_attempts_states($attempt, 'uniqueid'); $this->add_question_attempts_sessions($attempt, 'uniqueid'); // Build the tree $quiz->add_child($qinstances); $qinstances->add_child($qinstance); $quiz->add_child($feedbacks); $feedbacks->add_child($feedback); $quiz->add_child($overrides); $overrides->add_child($override); $quiz->add_child($grades); $grades->add_child($grade); $quiz->add_child($attempts); $attempts->add_child($attempt); // Define sources $quiz->set_source_table('quiz', array('id' => backup::VAR_ACTIVITYID)); $qinstance->set_source_table('quiz_question_instances', array('quiz' => backup::VAR_PARENTID)); $feedback->set_source_table('quiz_feedback', array('quizid' => backup::VAR_PARENTID)); // Quiz overrides to backup are different depending of user info $overrideparams = array('quiz' => backup::VAR_PARENTID); if (!$userinfo) { // Without userinfo, skip user overrides $overrideparams['userid'] = backup_helper::is_sqlparam(null); } $override->set_source_table('quiz_overrides', $overrideparams); // All the rest of elements only happen if we are including user info if ($userinfo) { $grade->set_source_table('quiz_grades', array('quiz' => backup::VAR_PARENTID)); $attempt->set_source_table('quiz_attempts', array('quiz' => backup::VAR_PARENTID)); } // Define source alias $quiz->set_source_alias('attempts', 'attempts_number'); $grade->set_source_alias('grade', 'gradeval'); $attempt->set_source_alias('attempt', 'attemptnum'); // Define id annotations $qinstance->annotate_ids('question', 'question'); $override->annotate_ids('user', 'userid'); $override->annotate_ids('group', 'groupid'); $grade->annotate_ids('user', 'userid'); $attempt->annotate_ids('user', 'userid'); // Define file annotations $quiz->annotate_files('mod_quiz', 'intro', null); // This file area hasn't itemid $feedback->annotate_files('mod_quiz', 'feedback', 'id'); // Return the root element (quiz), wrapped into standard activity structure return $this->prepare_activity_structure($quiz); }