MDL-20636 make syncronised datasets work for calculated* questions.
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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. */
|
||||
|
||||
Reference in New Issue
Block a user