diff --git a/question/format.php b/question/format.php index 9520ae17d76..e2292e0a0c2 100644 --- a/question/format.php +++ b/question/format.php @@ -357,6 +357,7 @@ class qformat_default { $count = 0; foreach ($questions as $question) { // Process and store each question + $transaction = $DB->start_delegated_transaction(); // reset the php timeout set_time_limit(0); @@ -429,9 +430,14 @@ class qformat_default { if (!empty($result->error)) { echo $OUTPUT->notification($result->error); + // Can't use $transaction->rollback(); since it requires an exception, + // and I don't want to rewrite this code to change the error handling now. + $DB->force_transaction_rollback(); return false; } + $transaction->allow_commit(); + if (!empty($result->notice)) { echo $OUTPUT->notification($result->notice); return true; diff --git a/question/format/webct/format.php b/question/format/webct/format.php index 9bc4f3a4672..fd6c411b736 100644 --- a/question/format/webct/format.php +++ b/question/format/webct/format.php @@ -606,12 +606,9 @@ class qformat_webct extends qformat_default { // Calculated Question. $question = $this->defaultquestion(); $question->qtype = 'calculated'; - $question->answers = array(); // No problem as they go as :FORMULA: from webct. + $question->answer = array(); // No problem as they go as :FORMULA: from webct. $question->units = array(); $question->dataset = array(); - - // To make us pass the end-of-question sanity checks. - $question->answer = array('dummy'); $question->fraction = array('1.0'); $question->feedback = array(); @@ -737,7 +734,7 @@ class qformat_webct extends qformat_default { if (preg_match('~^:FORMULA:(.*)~i', $line, $webctoptions)) { // Answer for a calculated question. ++$currentchoice; - $question->answers[$currentchoice] = + $question->answer[$currentchoice] = qformat_webct_convert_formula($webctoptions[1]); // Default settings. diff --git a/question/format/xml/format.php b/question/format/xml/format.php index 1005f5a653d..60c0cef552c 100644 --- a/question/format/xml/format.php +++ b/question/format/xml/format.php @@ -780,7 +780,7 @@ class qformat_xml extends qformat_default { // get answers array $answers = $question['#']['answer']; - $qo->answers = array(); + $qo->answer = array(); $qo->feedback = array(); $qo->fraction = array(); $qo->tolerance = array(); @@ -794,7 +794,7 @@ class qformat_xml extends qformat_default { if (empty($ans->answer['text'])) { $ans->answer['text'] = '*'; } - $qo->answers[] = $ans->answer; + $qo->answer[] = $ans->answer['text']; $qo->feedback[] = $ans->feedback; $qo->tolerance[] = $answer['#']['tolerance'][0]['#']; // fraction as a tag is deprecated diff --git a/question/type/calculated/questiontype.php b/question/type/calculated/questiontype.php index 9ae35362780..81c15664341 100644 --- a/question/type/calculated/questiontype.php +++ b/question/type/calculated/questiontype.php @@ -131,11 +131,13 @@ class qtype_calculated extends question_type { public function save_question_options($question) { global $CFG, $DB; + + // Make it impossible to save bad formulas anywhere. + $this->validate_question_data($question); + // The code is used for calculated, calculatedsimple and calculatedmulti qtypes. $context = $question->context; - if (isset($question->answer) && !isset($question->answers)) { - $question->answers = $question->answer; - } + // Calculated options. $update = true; $options = $DB->get_record('question_calculated_options', @@ -185,14 +187,7 @@ class qtype_calculated extends question_type { $units = $result->units; } - // Insert all the new answers. - if (isset($question->answer) && !isset($question->answers)) { - $question->answers = $question->answer; - } - foreach ($question->answers as $key => $answerdata) { - if (is_array($answerdata)) { - $answerdata = $answerdata['text']; - } + foreach ($question->answer as $key => $answerdata) { if (trim($answerdata) == '') { continue; } @@ -471,6 +466,25 @@ class qtype_calculated extends question_type { } } + /** + * Validate data before save. + * @param stdClass $question data from the form / import file. + */ + protected function validate_question_data($question) { + $this->validate_text($question->questiontext); // Yes, really no ['text']. + + if (isset($question->generalfeedback['text'])) { + $this->validate_text($question->generalfeedback['text']); + } else if (isset($question->generalfeedback)) { + $this->validate_text($question->generalfeedback); // Because question import is weird. + } + + foreach ($question->answer as $key => $answer) { + $this->validate_answer($answer); + $this->validate_text($question->feedback[$key]['text']); + } + } + /** * This method prepare the $datasets in a format similar to dadatesetdefinitions_form.php * so that they can be saved @@ -483,13 +497,13 @@ class qtype_calculated extends question_type { * @param object $form * @param int $questionfromid default = '0' */ - public function preparedatasets($form , $questionfromid = '0') { + public function preparedatasets($form, $questionfromid = '0') { // The dataset names present in the edit_question_form and edit_calculated_form // are retrieved. $possibledatasets = $this->find_dataset_names($form->questiontext); $mandatorydatasets = array(); - foreach ($form->answers as $key => $answer) { + foreach ($form->answer as $key => $answer) { $mandatorydatasets += $this->find_dataset_names($answer); } // If there are identical datasetdefs already saved in the original question @@ -579,12 +593,6 @@ class qtype_calculated extends question_type { public function save_question($question, $form) { global $DB; - if (isset($form->correctfeedback)) { - $this->validate_text($form->correctfeedback['text']); - $this->validate_text($form->partiallycorrectfeedback['text']); - $this->validate_text($form->incorrectfeedback['text']); - } - if ($this->wizardpagesnumber() == 1 || $question->qtype == 'calculatedsimple') { $question = parent::save_question($question, $form); return $question; @@ -605,14 +613,6 @@ class qtype_calculated extends question_type { case '' : case 'question': // Coming from the first page, creating the second. if (empty($form->id)) { // or a new question $form->id is empty. - // Make it impossible to save bad formulas anywhere. - $this->validate_text($form->questiontext['text']); - $this->validate_text($form->generalfeedback['text']); - foreach ($form->answer as $key => $answer) { - $this->validate_answer($answer); - $this->validate_text($form->feedback[$key]['text']); - } - $question = parent::save_question($question, $form); // Prepare the datasets using default $questionfromid. $this->preparedatasets($form); diff --git a/question/type/calculatedmulti/questiontype.php b/question/type/calculatedmulti/questiontype.php index 1cd1348d4bb..62e51571e04 100644 --- a/question/type/calculatedmulti/questiontype.php +++ b/question/type/calculatedmulti/questiontype.php @@ -42,6 +42,9 @@ class qtype_calculatedmulti extends qtype_calculated { global $CFG, $DB; $context = $question->context; + // Make it impossible to save bad formulas anywhere. + $this->validate_question_data($question); + // Calculated options. $update = true; $options = $DB->get_record('question_calculated_options', @@ -72,10 +75,7 @@ class qtype_calculatedmulti extends qtype_calculated { } // Insert all the new answers. - if (isset($question->answer) && !isset($question->answers)) { - $question->answers = $question->answer; - } - foreach ($question->answers as $key => $answerdata) { + foreach ($question->answer as $key => $answerdata) { if (is_array($answerdata)) { $answerdata = $answerdata['text']; } @@ -163,6 +163,13 @@ class qtype_calculatedmulti extends qtype_calculated { } } + protected function validate_question_data($question) { + parent::validate_question_data($question); + $this->validate_text($question->correctfeedback['text']); + $this->validate_text($question->partiallycorrectfeedback['text']); + $this->validate_text($question->incorrectfeedback['text']); + } + protected function make_question_instance($questiondata) { question_bank::load_question_definition_classes($this->name()); if ($questiondata->options->single) { diff --git a/question/type/calculatedsimple/questiontype.php b/question/type/calculatedsimple/questiontype.php index c98f307dbe8..0b19ca8dc5a 100644 --- a/question/type/calculatedsimple/questiontype.php +++ b/question/type/calculatedsimple/questiontype.php @@ -43,11 +43,9 @@ class qtype_calculatedsimple extends qtype_calculated { public function save_question_options($question) { global $CFG, $DB; $context = $question->context; - // Get old answers. - if (isset($question->answer) && !isset($question->answers)) { - $question->answers = $question->answer; - } + // Make it impossible to save bad formulas anywhere. + $this->validate_question_data($question); // Get old versions of the objects. if (!$oldanswers = $DB->get_records('question_answers', @@ -69,10 +67,7 @@ class qtype_calculatedsimple extends qtype_calculated { $units = &$result->units; } // Insert all the new answers. - if (isset($question->answer) && !isset($question->answers)) { - $question->answers = $question->answer; - } - foreach ($question->answers as $key => $answerdata) { + foreach ($question->answer as $key => $answerdata) { if (is_array($answerdata)) { $answerdata = $answerdata['text']; }