MDL-20636 make syncronised datasets work for calculated* questions.

This commit is contained in:
Tim Hunt
2011-05-19 19:06:07 +01:00
parent 0eb253f7f6
commit e35ba43c91
7 changed files with 58 additions and 70 deletions
+1 -1
View File
@@ -145,7 +145,7 @@ if (!($quiz->attemptonlast && $lastattempt)) {
}
// Start all the quetsions.
$quba->start_all_questions();
$quba->start_all_questions(time(), null);
// Update attempt layout.
$newlayout = array();
+3 -1
View File
@@ -419,8 +419,10 @@ class question_usage_by_activity {
/**
* Start the attempt at all questions that has been added to this usage.
* @param int $timestamp optional, the timstamp to record for this action. Defaults to now.
* @param int $userid optional, the user to attribute this action to. Defaults to the current user.
*/
public function start_all_questions() {
public function start_all_questions($timestamp = null, $userid = null) {
foreach ($this->questionattempts as $qa) {
$qa->start($this->preferredbehaviour);
$this->observer->notify_attempt_modified($qa);
+33 -2
View File
@@ -37,11 +37,19 @@ require_once($CFG->dirroot . '/question/type/numerical/question.php');
*/
class qtype_calculated_question extends qtype_numerical_question
implements qtype_calculated_question_with_expressions {
/** @var qtype_calculated_dataset_loader helper for loading the dataset. */
public $datasetloader;
/** @var qtype_calculated_variable_substituter stores the dataset we are using. */
public $vs;
/**
* @var bool wheter the dataset item to use should be chose based on attempt
* start time, rather than randomly.
*/
public $synchronised;
public function start_attempt(question_attempt_step $step) {
qtype_calculated_question_helper::start_attempt($this, $step);
parent::start_attempt($step);
@@ -103,9 +111,16 @@ interface qtype_calculated_question_with_expressions {
abstract class qtype_calculated_question_helper {
public static function start_attempt(
qtype_calculated_question_with_expressions $question, question_attempt_step $step) {
$maxnumber = $question->datasetloader->get_number_of_items();
$setnumber = rand(1, $maxnumber);
// TODO implement the $synchronizecalculated bit from create_session_and_responses.
if (!empty($question->synchronised) &&
$question->datasetloader->datasets_are_synchronised($question->category)) {
$setnumber = ($step->get_timecreated() % $maxnumber) + 1;
} else {
$setnumber = rand(1, $maxnumber);
}
$question->vs = new qtype_calculated_variable_substituter(
$question->datasetloader->get_values($setnumber),
@@ -211,6 +226,22 @@ class qtype_calculated_dataset_loader {
return $this->load_values($itemnumber);
}
public function datasets_are_synchronised($category) {
global $DB;
// We need to ensure that there are synchronised datasets, and that they
// all use the right category.
$categories = $DB->get_record_sql('
SELECT MAX(qdd.category) AS max,
MIN(qdd.category) AS min
FROM {question_dataset_definitions} qdd
JOIN {question_datasets} qd ON qdd.id = qd.datasetdefinition
WHERE qd.question = ?
AND qdd.category <> 0
', array($this->questionid));
return $categories && $categories->max == $category && $categories->min == $category;
}
}
+4 -65
View File
@@ -352,6 +352,8 @@ class qtype_calculated extends question_type {
$question->answers[$a->id]->correctanswerformat = $a->correctanswerformat;
}
$question->synchronised = $questiondata->options->synchronize;
$question->unitdisplay = $questiondata->options->showunits;
$question->unitgradingtype = $questiondata->options->unitgradingtype;
$question->unitpenalty = $questiondata->options->unitpenalty;
@@ -362,67 +364,6 @@ class qtype_calculated extends question_type {
$question->datasetloader = new qtype_calculated_dataset_loader($questiondata->id);
}
public function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) {
// Find out how many datasets are available
global $CFG, $DB, $OUTPUT;
if (!$maxnumber = (int)$DB->get_field_sql(
"SELECT MIN(a.itemcount)
FROM {question_dataset_definitions} a, {question_datasets} b
WHERE b.question = ? AND a.id = b.datasetdefinition", array($question->id))) {
print_error('cannotgetdsforquestion', 'question', '', $question->id);
}
$sql = "SELECT i.*
FROM {question_datasets} d, {question_dataset_definitions} i
WHERE d.question = ? AND d.datasetdefinition = i.id AND i.category != 0";
if (!$question->options->synchronize ||
!$records = $DB->get_records_sql($sql, array($question->id))) {
$synchronizecalculated = false;
} else {
// i.e records is true so test coherence
$coherence = true;
$a = new stdClass();
$a->qid = $question->id;
$a->qcat = $question->category;
foreach ($records as $def) {
if ($def->category != $question->category) {
$a->name = $def->name;
$a->sharedcat = $def->category;
$coherence = false;
break;
}
}
if (!$coherence) {
echo $OUTPUT->notification(get_string(
'nocoherencequestionsdatyasetcategory', 'qtype_calculated', $a));
}
$synchronizecalculated = true;
}
// Choose a random dataset
// maxnumber sould not be breater than 100
if ($maxnumber > self::MAX_DATASET_ITEMS) {
$maxnumber = self::MAX_DATASET_ITEMS;
}
if ($synchronizecalculated === false) {
$state->options->datasetitem = rand(1, $maxnumber);
} else {
$state->options->datasetitem =
intval($maxnumber * substr($attempt->timestart, -2) /100);
if ($state->options->datasetitem < 1) {
$state->options->datasetitem = 1;
} else if ($state->options->datasetitem > $maxnumber) {
$state->options->datasetitem = $maxnumber;
}
};
$state->options->dataset =
$this->pick_question_dataset($question, $state->options->datasetitem);
$virtualqtype = $this->get_virtual_qtype();
return $virtualqtype->create_session_and_responses($question, $state, $cmoptions, $attempt);
}
public function validate_form($form) {
switch($form->wizardpage) {
case 'question':
@@ -920,8 +861,6 @@ class qtype_calculated extends question_type {
public function save_dataset_items($question, $fromform) {
global $CFG, $DB;
// max datasets = 100 items
$max100 = self::MAX_DATASET_ITEMS;
$synchronize = false;
if (isset($fromform->nextpageparam['forceregeneration'])) {
$regenerate = $fromform->nextpageparam['forceregeneration'];
@@ -997,8 +936,8 @@ class qtype_calculated extends question_type {
if (isset($fromform->addbutton) && $fromform->selectadd > 0 &&
$maxnumber < self::MAX_DATASET_ITEMS) {
$numbertoadd = $fromform->selectadd;
if ($max100 - $maxnumber < $numbertoadd) {
$numbertoadd = $max100 - $maxnumber;
if (self::MAX_DATASET_ITEMS - $maxnumber < $numbertoadd) {
$numbertoadd = self::MAX_DATASET_ITEMS - $maxnumber;
}
//add the other items.
// Generate a new dataset item (or reuse an old one)
@@ -38,12 +38,19 @@ require_once($CFG->dirroot . '/question/type/calculated/question.php');
*/
class qtype_calculatedmulti_single_question extends qtype_multichoice_single_question
implements qtype_calculated_question_with_expressions {
/** @var qtype_calculated_dataset_loader helper for loading the dataset. */
public $datasetloader;
/** @var qtype_calculated_variable_substituter stores the dataset we are using. */
public $vs;
/**
* @var bool wheter the dataset item to use should be chose based on attempt
* start time, rather than randomly.
*/
public $synchronised;
public function start_attempt(question_attempt_step $step) {
qtype_calculated_question_helper::start_attempt($this, $step);
parent::start_attempt($step);
@@ -68,12 +75,19 @@ class qtype_calculatedmulti_single_question extends qtype_multichoice_single_que
*/
class qtype_calculatedmulti_multi_question extends qtype_multichoice_multi_question
implements qtype_calculated_question_with_expressions {
/** @var qtype_calculated_dataset_loader helper for loading the dataset. */
public $datasetloader;
/** @var qtype_calculated_variable_substituter stores the dataset we are using. */
public $vs;
/**
* @var bool wheter the dataset item to use should be chose based on attempt
* start time, rather than randomly.
*/
public $synchronised;
public function start_attempt(question_attempt_step $step) {
qtype_calculated_question_helper::start_attempt($this, $step);
parent::start_attempt($step);
@@ -214,6 +214,8 @@ class qtype_calculatedmulti extends qtype_calculated {
$question->layout = qtype_multichoice_single_question::LAYOUT_VERTICAL;
}
$question->synchronised = $questiondata->options->synchronize;
$this->initialise_combined_feedback($question, $questiondata, true);
$this->initialise_question_answers($question, $questiondata);
+1 -1
View File
@@ -46,7 +46,7 @@ abstract class question_definition {
/** @var integer question category id. */
public $category;
/** @var integer question category id. */
/** @var integer question context id. */
public $contextid;
/** @var integer parent question id. */