MDL-53638 mod_feedback: structural changes

- add column 'courseid' to the feedback_completed and feedback_completedtmp tables
- drop table feedback_tracking because the same information is present in
  feedback_completed
This commit is contained in:
Marina Glancy 2016-04-09 19:34:30 +08:00
parent cf28c515f3
commit ffee513ef2
7 changed files with 301 additions and 51 deletions

View File

@ -59,7 +59,8 @@ class backup_feedback_activity_structure_step extends backup_activity_structure_
'userid',
'timemodified',
'random_response',
'anonymous_response'));
'anonymous_response',
'courseid'));
$items = new backup_nested_element('items');
@ -76,19 +77,14 @@ class backup_feedback_activity_structure_step extends backup_activity_structure_
'dependvalue',
'options'));
$trackings = new backup_nested_element('trackings');
$tracking = new backup_nested_element('tracking', array('id'), array(
'userid',
'completed'));
$values = new backup_nested_element('values');
$value = new backup_nested_element('value', array('id'), array(
'item',
'template',
'completed',
'value'));
'value',
'course_id'));
// Build the tree
$feedback->add_child($items);
@ -100,9 +96,6 @@ class backup_feedback_activity_structure_step extends backup_activity_structure_
$completed->add_child($values);
$values->add_child($value);
$feedback->add_child($trackings);
$trackings->add_child($tracking);
// Define sources
$feedback->set_source_table('feedback', array('id' => backup::VAR_ACTIVITYID));
@ -117,16 +110,12 @@ class backup_feedback_activity_structure_step extends backup_activity_structure_
array(backup::VAR_PARENTID));
$value->set_source_table('feedback_value', array('completed' => backup::VAR_PARENTID));
$tracking->set_source_table('feedback_tracking', array('feedback' => backup::VAR_PARENTID));
}
// Define id annotations
$completed->annotate_ids('user', 'userid');
$tracking->annotate_ids('user', 'userid');
// Define file annotations
$feedback->annotate_files('mod_feedback', 'intro', null); // This file area hasn't itemid

View File

@ -40,7 +40,6 @@ class restore_feedback_activity_structure_step extends restore_activity_structur
if ($userinfo) {
$paths[] = new restore_path_element('feedback_completed', '/activity/feedback/completeds/completed');
$paths[] = new restore_path_element('feedback_value', '/activity/feedback/completeds/completed/values/value');
$paths[] = new restore_path_element('feedback_tracking', '/activity/feedback/trackings/tracking');
}
// Return the paths wrapped into standard activity structure
@ -86,6 +85,13 @@ class restore_feedback_activity_structure_step extends restore_activity_structur
$data->feedback = $this->get_new_parentid('feedback');
$data->userid = $this->get_mappingid('user', $data->userid);
$data->timemodified = $this->apply_date_offset($data->timemodified);
if ($this->task->is_samesite() && !empty($data->courseid)) {
$data->courseid = $data->courseid;
} else if ($this->get_courseid() == SITEID) {
$data->courseid = SITEID;
} else {
$data->courseid = 0;
}
$newitemid = $DB->insert_record('feedback_completed', $data);
$this->set_mapping('feedback_completed', $oldid, $newitemid);
@ -98,25 +104,18 @@ class restore_feedback_activity_structure_step extends restore_activity_structur
$oldid = $data->id;
$data->completed = $this->get_new_parentid('feedback_completed');
$data->item = $this->get_mappingid('feedback_item', $data->item);
$data->course_id = $this->get_courseid();
if ($this->task->is_samesite() && !empty($data->course_id)) {
$data->course_id = $data->course_id;
} else if ($this->get_courseid() == SITEID) {
$data->course_id = SITEID;
} else {
$data->course_id = 0;
}
$newitemid = $DB->insert_record('feedback_value', $data);
$this->set_mapping('feedback_value', $oldid, $newitemid);
}
protected function process_feedback_tracking($data) {
global $DB;
$data = (object)$data;
$oldid = $data->id;
$data->feedback = $this->get_new_parentid('feedback');
$data->completed = $this->get_mappingid('feedback_completed', $data->completed);
$data->userid = $this->get_mappingid('user', $data->userid);
$newitemid = $DB->insert_record('feedback_tracking', $data);
}
protected function after_execute() {
// Add feedback related files, no need to match by itemname (just internally handled context)
$this->add_related_files('mod_feedback', 'intro', null);

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="mod/feedback/db" VERSION="20120122" COMMENT="XMLDB file for Moodle mod/feedback"
<XMLDB PATH="mod/feedback/db" VERSION="20160326" COMMENT="XMLDB file for Moodle mod/feedback"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
@ -75,6 +75,7 @@
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="random_response" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="anonymous_response" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="Primary key for feedback_completed"/>
@ -93,6 +94,7 @@
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="random_response" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="anonymous_response" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="Primary key for feedback_completedtmp"/>
@ -136,23 +138,6 @@
<INDEX NAME="course_id" UNIQUE="false" FIELDS="course_id"/>
</INDEXES>
</TABLE>
<TABLE NAME="feedback_tracking" COMMENT="feedback trackingdata">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="feedback" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="completed" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="tmp_completed" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="Primary key for feedback_tracking"/>
<KEY NAME="feedback" TYPE="foreign" FIELDS="feedback" REFTABLE="feedback" REFFIELDS="id"/>
<KEY NAME="completed" TYPE="foreign" FIELDS="completed" REFTABLE="feedback_completed" REFFIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="userid" UNIQUE="false" FIELDS="userid"/>
</INDEXES>
</TABLE>
<TABLE NAME="feedback_sitecourse_map" COMMENT="feedback sitecourse map">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
@ -160,7 +145,7 @@
<FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="Primary key for feedback_tracking"/>
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="Primary key for feedback_sitecourse_map"/>
<KEY NAME="feedbackid" TYPE="foreign" FIELDS="feedbackid" REFTABLE="feedback" REFFIELDS="id"/>
</KEYS>
<INDEXES>
@ -168,4 +153,4 @@
</INDEXES>
</TABLE>
</TABLES>
</XMLDB>
</XMLDB>

View File

@ -38,6 +38,9 @@ defined('MOODLE_INTERNAL') || die();
function xmldb_feedback_upgrade($oldversion) {
global $CFG, $DB;
require_once($CFG->dirroot . '/mod/feedback/db/upgradelib.php');
$dbman = $DB->get_manager(); // Loads ddl manager and xmldb classes.
// Moodle v2.8.0 release upgrade line.
// Put any upgrade step following this.
@ -72,5 +75,41 @@ function xmldb_feedback_upgrade($oldversion) {
upgrade_mod_savepoint(true, 2016040100, 'feedback');
}
if ($oldversion < 2016040300) {
// Define field courseid to be added to feedback_completed.
$table = new xmldb_table('feedback_completed');
$field = new xmldb_field('courseid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'anonymous_response');
// Conditionally launch add field courseid.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
// Define field courseid to be added to feedback_completedtmp.
$table = new xmldb_table('feedback_completedtmp');
$field = new xmldb_field('courseid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'anonymous_response');
// Conditionally launch add field courseid.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
// Define table feedback_tracking to be dropped.
$table = new xmldb_table('feedback_tracking');
// Conditionally launch drop table for feedback_tracking.
if ($dbman->table_exists($table)) {
$dbman->drop_table($table);
}
// Run upgrade script to fill the new field courseid with the data from feedback_value* tables.
mod_feedback_upgrade_courseid(false);
mod_feedback_upgrade_courseid(true);
// Feedback savepoint reached.
upgrade_mod_savepoint(true, 2016040300, 'feedback');
}
return true;
}

View File

@ -0,0 +1,63 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Upgrade helper functions
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Fill new field courseid in tables feedback_completed or feedback_completedtmp
*
* @param bool $tmp use for temporary table
*/
function mod_feedback_upgrade_courseid($tmp = false) {
global $DB;
$suffix = $tmp ? 'tmp' : '';
// Part 1. Ensure that each completed record has associated values with only one courseid.
$sql = "SELECT c.id
FROM {feedback_completed$suffix} c, {feedback_value$suffix} v
WHERE c.id = v.completed
GROUP by c.id
having count(DISTINCT v.course_id) > 1";
$problems = $DB->get_fieldset_sql($sql);
foreach ($problems as $problem) {
$courses = $DB->get_fieldset_sql("SELECT DISTINCT course_id "
. "FROM {feedback_value$suffix} WHERE completed = ?", array($problem));
$firstcourse = array_shift($courses);
$record = $DB->get_record('feedback_completed'.$suffix, array('id' => $problem));
unset($record->id);
$DB->update_record('feedback_completed'.$suffix, ['id' => $problem, 'courseid' => $firstcourse]);
foreach ($courses as $courseid) {
$record->courseid = $courseid;
$completedid = $DB->insert_record('feedback_completed'.$suffix, $record);
$DB->execute("UPDATE {feedback_value$suffix} SET completed = ? WHERE completed = ? AND course_id = ?",
array($completedid, $problem, $courseid));
}
}
// Part 2. Update courseid in the completed table.
$sql = "UPDATE {feedback_completed$suffix} c "
. "SET courseid = (SELECT COALESCE(MIN(v.course_id), 0) "
. "FROM {feedback_value$suffix} v WHERE v.completed = c.id)";
$DB->execute($sql);
}

View File

@ -0,0 +1,175 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Tests for functions in db/upgradelib.php
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/mod/feedback/db/upgradelib.php');
/**
* Tests for functions in db/upgradelib.php
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_feedback_upgradelib_testcase extends advanced_testcase {
/** @var string */
protected $testsql = "SELECT COUNT(v.id) FROM {feedback_completed} c, {feedback_value} v
WHERE c.id = v.completed AND c.courseid <> v.course_id";
/** @var string */
protected $testsqltmp = "SELECT COUNT(v.id) FROM {feedback_completedtmp} c, {feedback_valuetmp} v
WHERE c.id = v.completed AND c.courseid <> v.course_id";
/** @var int */
protected $course1;
/** @var int */
protected $course2;
/** @var stdClass */
protected $feedback;
/** @var stdClass */
protected $user;
/**
* Sets up the fixture
* This method is called before a test is executed.
*/
public function setUp() {
parent::setUp();
$this->resetAfterTest(true);
$this->course1 = $this->getDataGenerator()->create_course();
$this->course2 = $this->getDataGenerator()->create_course();
$this->feedback = $this->getDataGenerator()->create_module('feedback', array('course' => SITEID));
$this->user = $this->getDataGenerator()->create_user();
}
public function test_upgrade_courseid_completed() {
global $DB;
// Case 1. No errors in the data.
$completed1 = $DB->insert_record('feedback_completed',
['feedback' => $this->feedback->id, 'userid' => $this->user->id]);
$DB->insert_record('feedback_value',
['completed' => $completed1, 'course_id' => $this->course1->id,
'item' => 1, 'value' => 1]);
$DB->insert_record('feedback_value',
['completed' => $completed1, 'course_id' => $this->course1->id,
'item' => 1, 'value' => 2]);
$this->assertCount(1, $DB->get_records('feedback_completed'));
$this->assertEquals(2, $DB->count_records_sql($this->testsql)); // We have errors!
mod_feedback_upgrade_courseid(true); // Running script for temp tables.
$this->assertCount(1, $DB->get_records('feedback_completed'));
$this->assertEquals(2, $DB->count_records_sql($this->testsql)); // Nothing changed.
mod_feedback_upgrade_courseid();
$this->assertCount(1, $DB->get_records('feedback_completed')); // Number of records is the same.
$this->assertEquals(0, $DB->count_records_sql($this->testsql)); // All errors are fixed!
}
public function test_upgrade_courseid_completed_with_errors() {
global $DB;
// Case 2. Errors in data (same feedback_completed has values for different courses).
$completed1 = $DB->insert_record('feedback_completed',
['feedback' => $this->feedback->id, 'userid' => $this->user->id]);
$DB->insert_record('feedback_value',
['completed' => $completed1, 'course_id' => $this->course1->id,
'item' => 1, 'value' => 1]);
$DB->insert_record('feedback_value',
['completed' => $completed1, 'course_id' => $this->course2->id,
'item' => 1, 'value' => 2]);
$this->assertCount(1, $DB->get_records('feedback_completed'));
$this->assertEquals(2, $DB->count_records_sql($this->testsql)); // We have errors!
mod_feedback_upgrade_courseid(true); // Running script for temp tables.
$this->assertCount(1, $DB->get_records('feedback_completed'));
$this->assertEquals(2, $DB->count_records_sql($this->testsql)); // Nothing changed.
mod_feedback_upgrade_courseid();
$this->assertCount(2, $DB->get_records('feedback_completed')); // Extra record inserted.
$this->assertEquals(0, $DB->count_records_sql($this->testsql)); // All errors are fixed!
}
public function test_upgrade_courseid_completedtmp() {
global $DB;
// Case 1. No errors in the data.
$completed1 = $DB->insert_record('feedback_completedtmp',
['feedback' => $this->feedback->id, 'userid' => $this->user->id]);
$DB->insert_record('feedback_valuetmp',
['completed' => $completed1, 'course_id' => $this->course1->id,
'item' => 1, 'value' => 1]);
$DB->insert_record('feedback_valuetmp',
['completed' => $completed1, 'course_id' => $this->course1->id,
'item' => 1, 'value' => 2]);
$this->assertCount(1, $DB->get_records('feedback_completedtmp'));
$this->assertEquals(2, $DB->count_records_sql($this->testsqltmp)); // We have errors!
mod_feedback_upgrade_courseid(); // Running script for non-temp tables.
$this->assertCount(1, $DB->get_records('feedback_completedtmp'));
$this->assertEquals(2, $DB->count_records_sql($this->testsqltmp)); // Nothing changed.
mod_feedback_upgrade_courseid(true);
$this->assertCount(1, $DB->get_records('feedback_completedtmp')); // Number of records is the same.
$this->assertEquals(0, $DB->count_records_sql($this->testsqltmp)); // All errors are fixed!
}
public function test_upgrade_courseid_completedtmp_with_errors() {
global $DB;
// Case 2. Errors in data (same feedback_completed has values for different courses).
$completed1 = $DB->insert_record('feedback_completedtmp',
['feedback' => $this->feedback->id, 'userid' => $this->user->id]);
$DB->insert_record('feedback_valuetmp',
['completed' => $completed1, 'course_id' => $this->course1->id,
'item' => 1, 'value' => 1]);
$DB->insert_record('feedback_valuetmp',
['completed' => $completed1, 'course_id' => $this->course2->id,
'item' => 1, 'value' => 2]);
$this->assertCount(1, $DB->get_records('feedback_completedtmp'));
$this->assertEquals(2, $DB->count_records_sql($this->testsqltmp)); // We have errors!
mod_feedback_upgrade_courseid(); // Running script for non-temp tables.
$this->assertCount(1, $DB->get_records('feedback_completedtmp'));
$this->assertEquals(2, $DB->count_records_sql($this->testsqltmp)); // Nothing changed.
mod_feedback_upgrade_courseid(true);
$this->assertCount(2, $DB->get_records('feedback_completedtmp')); // Extra record inserted.
$this->assertEquals(0, $DB->count_records_sql($this->testsqltmp)); // All errors are fixed!
}
public function test_upgrade_courseid_empty_completed() {
global $DB;
// Record in 'feedback_completed' does not have corresponding values.
$DB->insert_record('feedback_completed',
['feedback' => $this->feedback->id, 'userid' => $this->user->id]);
$this->assertCount(1, $DB->get_records('feedback_completed'));
$record1 = $DB->get_record('feedback_completed', []);
mod_feedback_upgrade_courseid();
$this->assertCount(1, $DB->get_records('feedback_completed')); // Number of records is the same.
$record2 = $DB->get_record('feedback_completed', []);
$this->assertEquals($record1, $record2);
}
}

View File

@ -24,7 +24,7 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2016040100; // The current module version (Date: YYYYMMDDXX)
$plugin->version = 2016040300; // The current module version (Date: YYYYMMDDXX)
$plugin->requires = 2015111000; // Requires this Moodle version
$plugin->component = 'mod_feedback'; // Full name of the plugin (used for diagnostics)
$plugin->cron = 0;