MDL-20636 Fix codechecker issues in the question type base classes.

This commit is contained in:
Tim Hunt
2011-04-08 05:39:16 +01:00
parent dcd69f8d97
commit eaeb6b513a
4 changed files with 279 additions and 188 deletions
+118 -65
View File
@@ -67,10 +67,12 @@ abstract class question_edit_form extends moodleform {
$this->question = $question;
$this->contexts = $contexts;
$record = $DB->get_record('question_categories', array('id' => $question->category), 'contextid');
$record = $DB->get_record('question_categories',
array('id' => $question->category), 'contextid');
$this->context = get_context_instance_by_id($record->contextid);
$this->editoroptions = array('subdirs' => 1,'maxfiles' => EDITOR_UNLIMITED_FILES, 'context' => $this->context);
$this->editoroptions = array('subdirs' => 1, 'maxfiles' => EDITOR_UNLIMITED_FILES,
'context' => $this->context);
$this->fileoptions = array('subdirs' => 1, 'maxfiles' => -1, 'maxbytes' => -1);
$this->category = $category;
@@ -101,38 +103,47 @@ abstract class question_edit_form extends moodleform {
// Adding question
$mform->addElement('questioncategory', 'category', get_string('category', 'question'),
array('contexts' => $this->contexts->having_cap('moodle/question:add')));
} elseif (!($this->question->formoptions->canmove || $this->question->formoptions->cansaveasnew)) {
} else if (!($this->question->formoptions->canmove ||
$this->question->formoptions->cansaveasnew)) {
// Editing question with no permission to move from category.
$mform->addElement('questioncategory', 'category', get_string('category', 'question'),
array('contexts' => array($this->categorycontext)));
} elseif ($this->question->formoptions->movecontext) {
} else if ($this->question->formoptions->movecontext) {
// Moving question to another context.
$mform->addElement('questioncategory', 'categorymoveto', get_string('category', 'question'),
$mform->addElement('questioncategory', 'categorymoveto',
get_string('category', 'question'),
array('contexts' => $this->contexts->having_cap('moodle/question:add')));
} else {
// Editing question with permission to move from category or save as new q
$currentgrp = array();
$currentgrp[0] =& $mform->createElement('questioncategory', 'category', get_string('categorycurrent', 'question'),
$currentgrp[0] = $mform->createElement('questioncategory', 'category',
get_string('categorycurrent', 'question'),
array('contexts' => array($this->categorycontext)));
if ($this->question->formoptions->canedit || $this->question->formoptions->cansaveasnew) {
if ($this->question->formoptions->canedit ||
$this->question->formoptions->cansaveasnew) {
//not move only form
$currentgrp[1] =& $mform->createElement('checkbox', 'usecurrentcat', '', get_string('categorycurrentuse', 'question'));
$currentgrp[1] = $mform->createElement('checkbox', 'usecurrentcat', '',
get_string('categorycurrentuse', 'question'));
$mform->setDefault('usecurrentcat', 1);
}
$currentgrp[0]->freeze();
$currentgrp[0]->setPersistantFreeze(false);
$mform->addGroup($currentgrp, 'currentgrp', get_string('categorycurrent', 'question'), null, false);
$mform->addGroup($currentgrp, 'currentgrp',
get_string('categorycurrent', 'question'), null, false);
$mform->addElement('questioncategory', 'categorymoveto', get_string('categorymoveto', 'question'),
$mform->addElement('questioncategory', 'categorymoveto',
get_string('categorymoveto', 'question'),
array('contexts' => array($this->categorycontext)));
if ($this->question->formoptions->canedit || $this->question->formoptions->cansaveasnew) {
if ($this->question->formoptions->canedit ||
$this->question->formoptions->cansaveasnew) {
//not move only form
$mform->disabledIf('categorymoveto', 'usecurrentcat', 'checked');
}
}
$mform->addElement('text', 'name', get_string('questionname', 'question'), array('size' => 50));
$mform->addElement('text', 'name', get_string('questionname', 'question'),
array('size' => 50));
$mform->setType('name', PARAM_TEXT);
$mform->addRule('name', null, 'required', null, 'client');
@@ -160,21 +171,26 @@ abstract class question_edit_form extends moodleform {
}
if (!empty($this->question->id)) {
$mform->addElement('header', 'createdmodifiedheader', get_string('createdmodifiedheader', 'question'));
$mform->addElement('header', 'createdmodifiedheader',
get_string('createdmodifiedheader', 'question'));
$a = new stdClass();
if (!empty($this->question->createdby)) {
$a->time = userdate($this->question->timecreated);
$a->user = fullname($DB->get_record('user', array('id' => $this->question->createdby)));
$a->user = fullname($DB->get_record(
'user', array('id' => $this->question->createdby)));
} else {
$a->time = get_string('unknown', 'question');
$a->user = get_string('unknown', 'question');
}
$mform->addElement('static', 'created', get_string('created', 'question'), get_string('byandon', 'question', $a));
$mform->addElement('static', 'created', get_string('created', 'question'),
get_string('byandon', 'question', $a));
if (!empty($this->question->modifiedby)) {
$a = new stdClass();
$a->time = userdate($this->question->timemodified);
$a->user = fullname($DB->get_record('user', array('id' => $this->question->modifiedby)));
$mform->addElement('static', 'modified', get_string('modified', 'question'), get_string('byandon', 'question', $a));
$a->user = fullname($DB->get_record(
'user', array('id' => $this->question->modifiedby)));
$mform->addElement('static', 'modified', get_string('modified', 'question'),
get_string('byandon', 'question', $a));
}
}
@@ -218,25 +234,32 @@ abstract class question_edit_form extends moodleform {
if (!empty($this->question->id)) {
//editing / moving question
if ($this->question->formoptions->movecontext) {
$buttonarray[] = &$mform->createElement('submit', 'submitbutton', get_string('moveq', 'question'));
} elseif ($this->question->formoptions->canedit || $this->question->formoptions->canmove ||$this->question->formoptions->movecontext) {
$buttonarray[] = &$mform->createElement('submit', 'submitbutton', get_string('savechanges'));
$buttonarray[] = $mform->createElement('submit', 'submitbutton',
get_string('moveq', 'question'));
} else if ($this->question->formoptions->canedit ||
$this->question->formoptions->canmove ||
$this->question->formoptions->movecontext) {
$buttonarray[] = $mform->createElement('submit', 'submitbutton',
get_string('savechanges'));
}
if ($this->question->formoptions->cansaveasnew) {
$buttonarray[] = &$mform->createElement('submit', 'makecopy', get_string('makecopy', 'question'));
$buttonarray[] = $mform->createElement('submit', 'makecopy',
get_string('makecopy', 'question'));
}
$buttonarray[] = &$mform->createElement('cancel');
$buttonarray[] = $mform->createElement('cancel');
} else {
// adding new question
$buttonarray[] = &$mform->createElement('submit', 'submitbutton', get_string('savechanges'));
$buttonarray[] = &$mform->createElement('cancel');
$buttonarray[] = $mform->createElement('submit', 'submitbutton',
get_string('savechanges'));
$buttonarray[] = $mform->createElement('cancel');
}
$mform->addGroup($buttonarray, 'buttonar', '', array(' '), false);
$mform->closeHeaderBefore('buttonar');
if ($this->question->formoptions->movecontext) {
$mform->hardFreezeAllVisibleExcept(array('categorymoveto', 'buttonar'));
} else if ((!empty($this->question->id)) && (!($this->question->formoptions->canedit || $this->question->formoptions->cansaveasnew))) {
} else if ((!empty($this->question->id)) && (!($this->question->formoptions->canedit ||
$this->question->formoptions->cansaveasnew))) {
$mform->hardFreezeAllVisibleExcept(array('categorymoveto', 'buttonar', 'currentgrp'));
}
}
@@ -256,16 +279,20 @@ abstract class question_edit_form extends moodleform {
* @param $label the label to use for each option.
* @param $gradeoptions the possible grades for each answer.
* @param $repeatedoptions reference to array of repeated options to fill
* @param $answersoption reference to return the name of $question->options field holding an array of answers
* @param $answersoption reference to return the name of $question->options
* field holding an array of answers
* @return array of form fields.
*/
protected function get_per_answer_fields(&$mform, $label, $gradeoptions, &$repeatedoptions, &$answersoption) {
protected function get_per_answer_fields(&$mform, $label, $gradeoptions,
&$repeatedoptions, &$answersoption) {
$repeated = array();
$repeated[] = $mform->createElement('header', 'answerhdr', $label);
$repeated[] = $mform->createElement('text', 'answer', get_string('answer', 'question'), array('size' => 80));
$repeated[] = $mform->createElement('select', 'fraction', get_string('grade'), $gradeoptions);
$repeated[] = $mform->createElement('editor', 'feedback', get_string('feedback', 'question'),
array('rows' => 5), $this->editoroptions);
$repeated[] = $mform->createElement('text', 'answer',
get_string('answer', 'question'), array('size' => 80));
$repeated[] = $mform->createElement('select', 'fraction',
get_string('grade'), $gradeoptions);
$repeated[] = $mform->createElement('editor', 'feedback',
get_string('feedback', 'question'), array('rows' => 5), $this->editoroptions);
$repeatedoptions['answer']['type'] = PARAM_RAW;
$repeatedoptions['fraction']['default'] = 0;
$answersoption = 'answers';
@@ -278,13 +305,16 @@ abstract class question_edit_form extends moodleform {
* @param object $mform the form being built.
* @param $label the label to use for each option.
* @param $gradeoptions the possible grades for each answer.
* @param $minoptions the minimum number of answer blanks to display. Default QUESTION_NUMANS_START.
* @param $minoptions the minimum number of answer blanks to display.
* Default QUESTION_NUMANS_START.
* @param $addoptions the number of answer blanks to add. Default QUESTION_NUMANS_ADD.
*/
protected function add_per_answer_fields(&$mform, $label, $gradeoptions, $minoptions = QUESTION_NUMANS_START, $addoptions = QUESTION_NUMANS_ADD) {
protected function add_per_answer_fields(&$mform, $label, $gradeoptions,
$minoptions = QUESTION_NUMANS_START, $addoptions = QUESTION_NUMANS_ADD) {
$answersoption = '';
$repeatedoptions = array();
$repeated = $this->get_per_answer_fields($mform, $label, $gradeoptions, $repeatedoptions, $answersoption);
$repeated = $this->get_per_answer_fields($mform, $label, $gradeoptions,
$repeatedoptions, $answersoption);
if (isset($this->question->options)) {
$countanswers = count($this->question->options->$answersoption);
@@ -297,21 +327,27 @@ abstract class question_edit_form extends moodleform {
$repeatsatstart = $countanswers;
}
$this->repeat_elements($repeated, $repeatsatstart, $repeatedoptions, 'noanswers', 'addanswers', $addoptions, get_string('addmorechoiceblanks', 'qtype_multichoice'));
$this->repeat_elements($repeated, $repeatsatstart, $repeatedoptions,
'noanswers', 'addanswers', $addoptions,
get_string('addmorechoiceblanks', 'qtype_multichoice'));
}
protected function add_combined_feedback_fields($withshownumpartscorrect = false) {
$mform = $this->_form;
$mform->addElement('header', 'combinedfeedbackhdr', get_string('combinedfeedback', 'question'));
$mform->addElement('header', 'combinedfeedbackhdr',
get_string('combinedfeedback', 'question'));
foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $feedbackname) {
$fields = array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback');
foreach ($fields as $feedbackname) {
$mform->addElement('editor', $feedbackname, get_string($feedbackname, 'question'),
array('rows' => 5), $this->editoroptions);
$mform->setType($feedbackname, PARAM_RAW);
if ($withshownumpartscorrect && $feedbackname == 'partiallycorrectfeedback') {
$mform->addElement('checkbox', 'shownumcorrect', get_string('options', 'question'), get_string('shownumpartscorrect', 'question'));
$mform->addElement('checkbox', 'shownumcorrect',
get_string('options', 'question'),
get_string('shownumpartscorrect', 'question'));
}
}
}
@@ -326,19 +362,23 @@ abstract class question_edit_form extends moodleform {
$repeatedoptions['hint']['type'] = PARAM_RAW;
if ($withclearwrong) {
$repeated[] = $mform->createElement('checkbox', 'hintclearwrong', get_string('options', 'question'), get_string('clearwrongparts', 'question'));
$repeated[] = $mform->createElement('checkbox', 'hintclearwrong',
get_string('options', 'question'), get_string('clearwrongparts', 'question'));
}
if ($withshownumpartscorrect) {
$repeated[] = $mform->createElement('checkbox', 'hintshownumcorrect', '', get_string('shownumpartscorrect', 'question'));
$repeated[] = $mform->createElement('checkbox', 'hintshownumcorrect', '',
get_string('shownumpartscorrect', 'question'));
}
return array($repeated, $repeatedoptions);
}
protected function add_interactive_settings($withclearwrong = false, $withshownumpartscorrect = false) {
protected function add_interactive_settings($withclearwrong = false,
$withshownumpartscorrect = false) {
$mform = $this->_form;
$mform->addElement('header', 'multitriesheader', get_string('settingsformultipletries', 'question'));
$mform->addElement('header', 'multitriesheader',
get_string('settingsformultipletries', 'question'));
$penalties = array(
1.0000000,
@@ -357,8 +397,8 @@ abstract class question_edit_form extends moodleform {
foreach ($penalties as $penalty) {
$penaltyoptions["$penalty"] = (100 * $penalty) . '%';
}
$mform->addElement('select', 'penalty', get_string('penaltyforeachincorrecttry', 'question'),
$penaltyoptions);
$mform->addElement('select', 'penalty',
get_string('penaltyforeachincorrecttry', 'question'), $penaltyoptions);
$mform->addRule('penalty', null, 'required', null, 'client');
$mform->addHelpButton('penalty', 'penaltyforeachincorrecttry', 'question');
$mform->setDefault('penalty', 0.3333333);
@@ -392,11 +432,14 @@ abstract class question_edit_form extends moodleform {
} else {
$questiontext = '';
}
$questiontext = file_prepare_draft_area($draftid, $this->context->id, 'question', 'questiontext', empty($question->id)?null:(int)$question->id, $this->fileoptions, $questiontext);
$questiontext = file_prepare_draft_area($draftid, $this->context->id,
'question', 'questiontext', empty($question->id) ? null : (int) $question->id,
$this->fileoptions, $questiontext);
$question->questiontext = array();
$question->questiontext['text'] = $questiontext;
$question->questiontext['format'] = empty($question->questiontextformat) ? editors_get_preferred_format() : $question->questiontextformat;
$question->questiontext['format'] = empty($question->questiontextformat) ?
editors_get_preferred_format() : $question->questiontextformat;
$question->questiontext['itemid'] = $draftid;
// prepare general feedback
@@ -406,10 +449,13 @@ abstract class question_edit_form extends moodleform {
$question->generalfeedback = '';
}
$feedback = file_prepare_draft_area($draftid, $this->context->id, 'question', 'generalfeedback', empty($question->id)?null:(int)$question->id, $this->fileoptions, $question->generalfeedback);
$feedback = file_prepare_draft_area($draftid, $this->context->id,
'question', 'generalfeedback', empty($question->id) ? null : (int) $question->id,
$this->fileoptions, $question->generalfeedback);
$question->generalfeedback = array();
$question->generalfeedback['text'] = $feedback;
$question->generalfeedback['format'] = empty($question->generalfeedbackformat) ? editors_get_preferred_format() : $question->generalfeedbackformat;
$question->generalfeedback['format'] = empty($question->generalfeedbackformat) ?
editors_get_preferred_format() : $question->generalfeedbackformat;
$question->generalfeedback['itemid'] = $draftid;
// Remove unnecessary trailing 0s form grade fields.
@@ -421,10 +467,10 @@ abstract class question_edit_form extends moodleform {
}
// Set any options.
$extra_question_fields = question_bank::get_qtype($question->qtype)->extra_question_fields();
if (is_array($extra_question_fields) && !empty($question->options)) {
array_shift($extra_question_fields);
foreach ($extra_question_fields as $field) {
$extraquestionfields = question_bank::get_qtype($question->qtype)->extra_question_fields();
if (is_array($extraquestionfields) && !empty($question->options)) {
array_shift($extraquestionfields);
foreach ($extraquestionfields as $field) {
if (isset($question->options->$field)) {
$question->$field = $question->options->$field;
}
@@ -452,18 +498,20 @@ abstract class question_edit_form extends moodleform {
}
$key = 0;
foreach ($question->options->answers as $answer){
foreach ($question->options->answers as $answer) {
$question->answer[$key] = $answer->answer;
$question->fraction[$key] = 0 + $answer->fraction;
$question->feedback[$key] = array();
// Evil hack alert. Formslib can store defaults in two ways for
// repeat elements: ->_defaultValues['fraction[0]'] and
// ->_defaultValues['fraction'][0]. The $repeatedoptions['fraction']['default'] = 0;
// bit above means that ->_defaultValues['fraction[0]'] has already
// been set, but we are using object notation here, so we will be setting
// ->_defaultValues['fraction'][0]. That does not work, so we have to unset
// ->_defaultValues['fraction[0]']
// repeat elements:
// ->_defaultValues['fraction[0]'] and
// ->_defaultValues['fraction'][0].
// The $repeatedoptions['fraction']['default'] = 0 bit above means
// that ->_defaultValues['fraction[0]'] has already been set, but we
// are using object notation here, so we will be setting
// ->_defaultValues['fraction'][0]. That does not work, so we have
// to unset ->_defaultValues['fraction[0]']
unset($this->_form->_defaultValues["fraction[$key]"]);
// Prepare the feedback editor to display files in draft area
@@ -484,12 +532,14 @@ abstract class question_edit_form extends moodleform {
return $question;
}
protected function data_preprocessing_combined_feedback($question, $withshownumcorrect = false) {
protected function data_preprocessing_combined_feedback($question,
$withshownumcorrect = false) {
if (empty($question->options)) {
return $question;
}
foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $feedbackname) {
$fields = array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback');
foreach ($fields as $feedbackname) {
$draftid = file_get_submitted_draft_itemid($feedbackname);
$feedback = array();
$feedback['text'] = file_prepare_draft_area(
@@ -515,13 +565,14 @@ abstract class question_edit_form extends moodleform {
return $question;
}
protected function data_preprocessing_hints($question, $withclearwrong = false, $withshownumpartscorrect = false) {
protected function data_preprocessing_hints($question, $withclearwrong = false,
$withshownumpartscorrect = false) {
if (empty($question->hints)) {
return $question;
}
$key = 0;
foreach ($question->hints as $hint){
foreach ($question->hints as $hint) {
$question->hint[$key] = array();
// prepare feedback editor to display files in draft area
@@ -553,7 +604,8 @@ abstract class question_edit_form extends moodleform {
public function validation($fromform, $files) {
$errors = parent::validation($fromform, $files);
if (empty($fromform->makecopy) && isset($this->question->id)
&& ($this->question->formoptions->canedit || $this->question->formoptions->cansaveasnew)
&& ($this->question->formoptions->canedit ||
$this->question->formoptions->cansaveasnew)
&& empty($fromform->usecurrentcat) && !$this->question->formoptions->canmove) {
$errors['currentgrp'] = get_string('nopermissionmove', 'question');
}
@@ -562,7 +614,8 @@ abstract class question_edit_form extends moodleform {
/**
* Override this in the subclass to question type name.
* @return the question type name, should be the same as the name() method in the question type class.
* @return the question type name, should be the same as the name() method
* in the question type class.
*/
public abstract function qtype();
}
+17 -9
View File
@@ -265,7 +265,8 @@ abstract class question_definition {
* parts of the question do not need to be cleaned, and student input does.
* @return string the text formatted for output by format_text.
*/
public function format_text($text, $format, $qa, $component, $filearea, $itemid, $clean = false) {
public function format_text($text, $format, $qa, $component, $filearea, $itemid,
$clean = false) {
$formatoptions = new stdClass();
$formatoptions->noclean = !$clean;
$formatoptions->para = false;
@@ -371,7 +372,8 @@ interface question_manually_gradable {
* response to the question is complete. That is, whether the question attempt
* should move to the COMPLETE or INCOMPLETE state.
*
* @param array $response responses, as returned by {@link question_attempt_step::get_qt_data()}.
* @param array $response responses, as returned by
* {@link question_attempt_step::get_qt_data()}.
* @return bool whether this response is a complete answer to this question.
*/
public function is_complete_response(array $response);
@@ -456,7 +458,8 @@ interface question_automatically_gradable extends question_manually_gradable {
* has provided enough of an answer for the question to be graded automatically,
* or whether it must be considered aborted.
*
* @param array $response responses, as returned by {@link question_attempt_step::get_qt_data()}.
* @param array $response responses, as returned by
* {@link question_attempt_step::get_qt_data()}.
* @return bool whether this response can be graded.
*/
public function is_gradable_response(array $response);
@@ -469,9 +472,11 @@ interface question_automatically_gradable extends question_manually_gradable {
public function get_validation_error(array $response);
/**
* Grade a response to the question, returning a fraction between get_min_fraction() and 1.0,
* and the corresponding state CORRECT, PARTIALLY_CORRECT or INCORRECT.
* @param array $response responses, as returned by {@link question_attempt_step::get_qt_data()}.
* Grade a response to the question, returning a fraction between
* get_min_fraction() and 1.0, and the corresponding {@link question_state}
* right, partial or wrong.
* @param array $response responses, as returned by
* {@link question_attempt_step::get_qt_data()}.
* @return array (number, integer) the fraction, and the state.
*/
public function grade_response(array $response);
@@ -602,7 +607,8 @@ abstract class question_graded_automatically extends question_with_responses
}
public function format_hint(question_hint $hint, question_attempt $qa) {
return $this->format_text($hint->hint, $hint->hintformat, $qa, 'question', 'hint', $hint->id);
return $this->format_text($hint->hint, $hint->hintformat, $qa,
'question', 'hint', $hint->id);
}
}
@@ -620,7 +626,8 @@ abstract class question_graded_automatically_with_countback
public function make_behaviour(question_attempt $qa, $preferredbehaviour) {
if ($preferredbehaviour == 'interactive') {
return question_engine::make_behaviour('interactivecountback', $qa, $preferredbehaviour);
return question_engine::make_behaviour('interactivecountback',
$qa, $preferredbehaviour);
}
return question_engine::make_archetypal_behaviour($preferredbehaviour, $qa);
}
@@ -674,7 +681,8 @@ abstract class question_graded_by_strategy extends question_graded_automatically
public function grade_response(array $response) {
$answer = $this->get_matching_answer($response);
if ($answer) {
return array($answer->fraction, question_state::graded_state_for_fraction($answer->fraction));
return array($answer->fraction,
question_state::graded_state_for_fraction($answer->fraction));
} else {
return array(0, question_state::$gradedwrong);
}
+143 -112
View File
@@ -173,9 +173,9 @@ class question_type {
}
/**
* If you use extra_question_fields, overload this function to return question id field name
* in case you table use another name for this column
*/
* If you use extra_question_fields, overload this function to return question id field name
* in case you table use another name for this column
*/
protected function questionid_column_name() {
return 'questionid';
}
@@ -211,10 +211,12 @@ class question_type {
* @param string $submiturl passed on to the constructor call.
* @return object an instance of the form definition, or null if one could not be found.
*/
public function create_editing_form($submiturl, $question, $category, $contexts, $formeditable) {
public function create_editing_form($submiturl, $question, $category,
$contexts, $formeditable) {
global $CFG;
require_once("{$CFG->dirroot}/question/type/edit_question_form.php");
$definition_file = $CFG->dirroot.'/question/type/'.$this->name().'/edit_'.$this->name().'_form.php';
$definition_file = $CFG->dirroot . '/question/type/' . $this->name() .
'/edit_' . $this->name() . '_form.php';
if (!(is_readable($definition_file) && is_file($definition_file))) {
return null;
}
@@ -257,21 +259,21 @@ class question_type {
echo $OUTPUT->heading_with_help($heading, $this->name(), $this->plugin_name());
$permissionstrs = array();
if (!empty($question->id)){
if ($question->formoptions->canedit){
if (!empty($question->id)) {
if ($question->formoptions->canedit) {
$permissionstrs[] = get_string('permissionedit', 'question');
}
if ($question->formoptions->canmove){
if ($question->formoptions->canmove) {
$permissionstrs[] = get_string('permissionmove', 'question');
}
if ($question->formoptions->cansaveasnew){
if ($question->formoptions->cansaveasnew) {
$permissionstrs[] = get_string('permissionsaveasnew', 'question');
}
}
if (!$question->formoptions->movecontext && count($permissionstrs)){
if (!$question->formoptions->movecontext && count($permissionstrs)) {
echo $OUTPUT->heading(get_string('permissionto', 'question'), 3);
$html = '<ul>';
foreach ($permissionstrs as $permissionstr){
foreach ($permissionstrs as $permissionstr) {
$html .= '<li>'.$permissionstr.'</li>';
}
$html .= '</ul>';
@@ -281,11 +283,12 @@ class question_type {
}
/**
* Method called by display_question_editing_page and by question.php to get heading for breadcrumbs.
* Method called by display_question_editing_page and by question.php to get
* heading for breadcrumbs.
*
* @return string the heading
*/
public function get_heading($adding = false){
public function get_heading($adding = false) {
if ($adding) {
$action = 'adding';
} else {
@@ -306,29 +309,32 @@ class question_type {
}
/**
* Saves (creates or updates) a question.
*
* Given some question info and some data about the answers
* this function parses, organises and saves the question
* It is used by {@link question.php} when saving new data from
* a form, and also by {@link import.php} when importing questions
* This function in turn calls {@link save_question_options}
* to save question-type specific data.
*
* Whether we are saving a new question or updating an existing one can be
* determined by testing !empty($question->id). If it is not empty, we are updating.
*
* The question will be saved in category $form->category.
*
* @param object $question the question object which should be updated. For a new question will be mostly empty.
* @param object $form the object containing the information to save, as if from the question editing form.
* @param object $course not really used any more.
* @return object On success, return the new question object. On failure,
* return an object as follows. If the error object has an errors field,
* display that as an error message. Otherwise, the editing form will be
* redisplayed with validation errors, from validation_errors field, which
* is itself an object, shown next to the form fields. (I don't think this is accurate any more.)
*/
* Saves (creates or updates) a question.
*
* Given some question info and some data about the answers
* this function parses, organises and saves the question
* It is used by {@link question.php} when saving new data from
* a form, and also by {@link import.php} when importing questions
* This function in turn calls {@link save_question_options}
* to save question-type specific data.
*
* Whether we are saving a new question or updating an existing one can be
* determined by testing !empty($question->id). If it is not empty, we are updating.
*
* The question will be saved in category $form->category.
*
* @param object $question the question object which should be updated. For a
* new question will be mostly empty.
* @param object $form the object containing the information to save, as if
* from the question editing form.
* @param object $course not really used any more.
* @return object On success, return the new question object. On failure,
* return an object as follows. If the error object has an errors field,
* display that as an error message. Otherwise, the editing form will be
* redisplayed with validation errors, from validation_errors field, which
* is itself an object, shown next to the form fields. (I don't think this
* is accurate any more.)
*/
public function save_question($question, $form) {
global $USER, $DB, $OUTPUT;
@@ -349,14 +355,16 @@ class question_type {
} else {
$question->questiontext = trim($form->questiontext['text']);;
}
$question->questiontextformat = !empty($form->questiontext['format'])?$form->questiontext['format']:0;
$question->questiontextformat = !empty($form->questiontext['format']) ?
$form->questiontext['format'] : 0;
if (empty($form->generalfeedback['text'])) {
$question->generalfeedback = '';
} else {
$question->generalfeedback = trim($form->generalfeedback['text']);
}
$question->generalfeedbackformat = !empty($form->generalfeedback['format'])?$form->generalfeedback['format']:0;
$question->generalfeedbackformat = !empty($form->generalfeedback['format']) ?
$form->generalfeedback['format'] : 0;
if (empty($question->name)) {
$question->name = shorten_text(strip_tags($form->questiontext['text']), 15);
@@ -389,10 +397,15 @@ class question_type {
$question->timemodified = time();
if (!empty($question->questiontext) && !empty($form->questiontext['itemid'])) {
$question->questiontext = file_save_draft_area_files($form->questiontext['itemid'], $context->id, 'question', 'questiontext', (int)$question->id, $this->fileoptions, $question->questiontext);
$question->questiontext = file_save_draft_area_files($form->questiontext['itemid'],
$context->id, 'question', 'questiontext', (int)$question->id,
$this->fileoptions, $question->questiontext);
}
if (!empty($question->generalfeedback) && !empty($form->generalfeedback['itemid'])) {
$question->generalfeedback = file_save_draft_area_files($form->generalfeedback['itemid'], $context->id, 'question', 'generalfeedback', (int)$question->id, $this->fileoptions, $question->generalfeedback);
$question->generalfeedback = file_save_draft_area_files(
$form->generalfeedback['itemid'], $context->id,
'question', 'generalfeedback', (int)$question->id,
$this->fileoptions, $question->generalfeedback);
}
$DB->update_record('question', $question);
@@ -416,11 +429,13 @@ class question_type {
}
if (!empty($result->noticeyesno)) {
throw new coding_exception('$result->noticeyesno no longer supported in save_question.');
throw new coding_exception(
'$result->noticeyesno no longer supported in save_question.');
}
// Give the question a unique version stamp determined by question_hash()
$DB->set_field('question', 'version', question_hash($question), array('id' => $question->id));
$DB->set_field('question', 'version', question_hash($question),
array('id' => $question->id));
return $question;
}
@@ -435,20 +450,21 @@ class question_type {
*/
public function save_question_options($question) {
global $DB;
$extra_question_fields = $this->extra_question_fields();
$extraquestionfields = $this->extra_question_fields();
if (is_array($extra_question_fields)) {
$question_extension_table = array_shift($extra_question_fields);
if (is_array($extraquestionfields)) {
$question_extension_table = array_shift($extraquestionfields);
$function = 'update_record';
$questionidcolname = $this->questionid_column_name();
$options = $DB->get_record($question_extension_table, array($questionidcolname => $question->id));
$options = $DB->get_record($question_extension_table,
array($questionidcolname => $question->id));
if (!$options) {
$function = 'insert_record';
$options = new stdClass();
$options->$questionidcolname = $question->id;
}
foreach ($extra_question_fields as $field) {
foreach ($extraquestionfields as $field) {
if (!isset($question->$field)) {
$result = new stdClass();
$result->error = "No data for field $field when saving " .
@@ -466,7 +482,7 @@ class question_type {
}
}
$extra_answer_fields = $this->extra_answer_fields();
$extraanswerfields = $this->extra_answer_fields();
// TODO save the answers, with any extra data.
}
@@ -506,7 +522,8 @@ class question_type {
$shownumcorrect = !empty($formdata->hintshownumcorrect[$i]);
}
if (empty($formdata->hint[$i]['text']) && empty($clearwrong) && empty($shownumcorrect)) {
if (empty($formdata->hint[$i]['text']) && empty($clearwrong) &&
empty($shownumcorrect)) {
continue;
}
@@ -545,13 +562,17 @@ class question_type {
* @param object $context the context the quetsion is being saved into.
* @param bool $withparts whether $options->shownumcorrect should be set.
*/
protected function save_combined_feedback_helper($options, $formdata, $context, $withparts = false) {
protected function save_combined_feedback_helper($options, $formdata,
$context, $withparts = false) {
$options->correctfeedback = $this->import_or_save_files($formdata->correctfeedback,
$context, 'question', 'correctfeedback', $formdata->id);
$options->correctfeedbackformat = $formdata->correctfeedback['format'];
$options->partiallycorrectfeedback = $this->import_or_save_files($formdata->partiallycorrectfeedback,
$options->partiallycorrectfeedback = $this->import_or_save_files(
$formdata->partiallycorrectfeedback,
$context, 'question', 'partiallycorrectfeedback', $formdata->id);
$options->partiallycorrectfeedbackformat = $formdata->partiallycorrectfeedback['format'];
$options->incorrectfeedback = $this->import_or_save_files($formdata->incorrectfeedback,
$context, 'question', 'incorrectfeedback', $formdata->id);
$options->incorrectfeedbackformat = $formdata->incorrectfeedback['format'];
@@ -582,39 +603,44 @@ class question_type {
$question->options = new stdClass();
}
$extra_question_fields = $this->extra_question_fields();
if (is_array($extra_question_fields)) {
$question_extension_table = array_shift($extra_question_fields);
$extra_data = $DB->get_record($question_extension_table, array($this->questionid_column_name() => $question->id), implode(', ', $extra_question_fields));
$extraquestionfields = $this->extra_question_fields();
if (is_array($extraquestionfields)) {
$question_extension_table = array_shift($extraquestionfields);
$extra_data = $DB->get_record($question_extension_table,
array($this->questionid_column_name() => $question->id),
implode(', ', $extraquestionfields));
if ($extra_data) {
foreach ($extra_question_fields as $field) {
foreach ($extraquestionfields as $field) {
$question->options->$field = $extra_data->$field;
}
} else {
echo $OUTPUT->notification("Failed to load question options from the table $question_extension_table for questionid " .
$question->id);
echo $OUTPUT->notification('Failed to load question options from the table ' .
$question_extension_table . ' for questionid ' . $question->id);
return false;
}
}
$extra_answer_fields = $this->extra_answer_fields();
if (is_array($extra_answer_fields)) {
$answer_extension_table = array_shift($extra_answer_fields);
$extraanswerfields = $this->extra_answer_fields();
if (is_array($extraanswerfields)) {
$answer_extension_table = array_shift($extraanswerfields);
$question->options->answers = $DB->get_records_sql("
SELECT qa.*, qax." . implode(', qax.', $extra_answer_fields) . "
SELECT qa.*, qax." . implode(', qax.', $extraanswerfields) . "
FROM {question_answers} qa, {$answer_extension_table} qax
WHERE qa.questionid = ? AND qax.answerid = qa.id", array($question->id));
if (!$question->options->answers) {
echo $OUTPUT->notification("Failed to load question answers from the table $answer_extension_table for questionid " .
$question->id);
echo $OUTPUT->notification('Failed to load question answers from the table ' .
$answer_extension_table . 'for questionid ' . $question->id);
return false;
}
} else {
// Don't check for success or failure because some question types do not use the answers table.
$question->options->answers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC');
// Don't check for success or failure because some question types do
// not use the answers table.
$question->options->answers = $DB->get_records('question_answers',
array('question' => $question->id), 'id ASC');
}
$question->hints = $DB->get_records('question_hints', array('questionid' => $question->id), 'id ASC');
$question->hints = $DB->get_records('question_hints',
array('questionid' => $question->id), 'id ASC');
return true;
}
@@ -704,11 +730,13 @@ class question_type {
* @param object $questiondata the question data loaded from the database.
* @param bool $withparts whether to set the shownumcorrect field.
*/
protected function initialise_combined_feedback(question_definition $question, $questiondata, $withparts = false) {
protected function initialise_combined_feedback(question_definition $question,
$questiondata, $withparts = false) {
$question->correctfeedback = $questiondata->options->correctfeedback;
$question->correctfeedbackformat = $questiondata->options->correctfeedbackformat;
$question->partiallycorrectfeedback = $questiondata->options->partiallycorrectfeedback;
$question->partiallycorrectfeedbackformat = $questiondata->options->partiallycorrectfeedbackformat;
$question->partiallycorrectfeedbackformat =
$questiondata->options->partiallycorrectfeedbackformat;
$question->incorrectfeedback = $questiondata->options->incorrectfeedback;
$question->incorrectfeedbackformat = $questiondata->options->incorrectfeedbackformat;
if ($withparts) {
@@ -742,18 +770,19 @@ class question_type {
$this->delete_files($questionid, $contextid);
$extra_question_fields = $this->extra_question_fields();
if (is_array($extra_question_fields)) {
$question_extension_table = array_shift($extra_question_fields);
$extraquestionfields = $this->extra_question_fields();
if (is_array($extraquestionfields)) {
$question_extension_table = array_shift($extraquestionfields);
$DB->delete_records($question_extension_table,
array($this->questionid_column_name() => $questionid));
}
$extra_answer_fields = $this->extra_answer_fields();
if (is_array($extra_answer_fields)) {
$answer_extension_table = array_shift($extra_answer_fields);
$extraanswerfields = $this->extra_answer_fields();
if (is_array($extraanswerfields)) {
$answer_extension_table = array_shift($extraanswerfields);
$DB->delete_records_select($answer_extension_table,
"answerid IN (SELECT qa.id FROM {question_answers} qa WHERE qa.question = ?)", array($questionid));
'answerid IN (SELECT qa.id FROM {question_answers} qa WHERE qa.question = ?)',
array($questionid));
}
$DB->delete_records('question_answers', array('question' => $questionid));
@@ -762,18 +791,18 @@ class question_type {
}
/**
* Returns the number of question numbers which are used by the question
*
* This function returns the number of question numbers to be assigned
* to the question. Most question types will have length one; they will be
* assigned one number. The 'description' type, however does not use up a
* number and so has a length of zero. Other question types may wish to
* handle a bundle of questions and hence return a number greater than one.
* @return int The number of question numbers which should be
* assigned to the question.
* @param object $question The question whose length is to be determined.
* Question type specific information is included.
*/
* Returns the number of question numbers which are used by the question
*
* This function returns the number of question numbers to be assigned
* to the question. Most question types will have length one; they will be
* assigned one number. The 'description' type, however does not use up a
* number and so has a length of zero. Other question types may wish to
* handle a bundle of questions and hence return a number greater than one.
* @return int The number of question numbers which should be
* assigned to the question.
* @param object $question The question whose length is to be determined.
* Question type specific information is included.
*/
public function actual_number_of_questions($question) {
// By default, each question is given one number
return 1;
@@ -852,27 +881,27 @@ class question_type {
}
/**
* Returns true if the editing wizard is finished, false otherwise.
*
* The default implementation returns true, which is suitable for all question-
* types that only use one editing form. This function is used in
* question.php to decide whether we can regrade any states of the edited
* question and redirect to edit.php.
*
* The dataset dependent question-type, which is extended by the calculated
* question-type, overwrites this method because it uses multiple pages (i.e.
* a wizard) to set up the question and associated datasets.
*
* @param object $form The data submitted by the previous page.
*
* @return bool Whether the wizard's last page was submitted or not.
*/
* Returns true if the editing wizard is finished, false otherwise.
*
* The default implementation returns true, which is suitable for all question-
* types that only use one editing form. This function is used in
* question.php to decide whether we can regrade any states of the edited
* question and redirect to edit.php.
*
* The dataset dependent question-type, which is extended by the calculated
* question-type, overwrites this method because it uses multiple pages (i.e.
* a wizard) to set up the question and associated datasets.
*
* @param object $form The data submitted by the previous page.
*
* @return bool Whether the wizard's last page was submitted or not.
*/
public function finished_edit_wizard($form) {
//In the default case there is only one edit page.
return true;
}
/// IMPORT/EXPORT FUNCTIONS /////////////////
/// IMPORT/EXPORT FUNCTIONS /////////////////
/*
* Imports question from the Moodle XML format
@@ -897,7 +926,7 @@ class question_type {
$qo->qtype = $question_type;
foreach ($extraquestionfields as $field) {
$qo->$field = $format->getpath($data, array('#',$field,0,'#'), $qo->$field);
$qo->$field = $format->getpath($data, array('#', $field, 0, '#'), $qo->$field);
}
// run through the answers
@@ -905,7 +934,7 @@ class question_type {
$a_count = 0;
$extraasnwersfields = $this->extra_answer_fields();
if (is_array($extraasnwersfields)) {
//TODO import the answers, with any extra data.
// TODO import the answers, with any extra data.
} else {
foreach ($answers as $answer) {
$ans = $format->import_answer($answer);
@@ -943,7 +972,7 @@ class question_type {
$extraasnwersfields = $this->extra_answer_fields();
if (is_array($extraasnwersfields)) {
//TODO export answers with any extra data
// TODO export answers with any extra data
} else {
foreach ($question->options->answers as $answer) {
$percent = 100 * $answer->fraction;
@@ -1003,7 +1032,8 @@ class question_type {
* importing, it will be an array with keys 'text', 'format' and 'files'
* @param object $context the context the question is in.
* @param string $component indentifies the file area question.
* @param string $filearea indentifies the file area questiontext, generalfeedback,answerfeedback.
* @param string $filearea indentifies the file area questiontext,
* generalfeedback, answerfeedback, etc.
* @param int $itemid identifies the file area.
*
* @return string the text for this field, after files have been processed.
@@ -1046,7 +1076,8 @@ class question_type {
* @param bool $answerstoo whether there is an 'answer' question area,
* as well as an 'answerfeedback' one. Default false.
*/
protected function move_files_in_answers($questionid, $oldcontextid, $newcontextid, $answerstoo = false) {
protected function move_files_in_answers($questionid, $oldcontextid,
$newcontextid, $answerstoo = false) {
global $DB;
$fs = get_file_storage();
@@ -1112,9 +1143,9 @@ class question_type {
protected function decode_file($file) {
switch ($file->encoding) {
case 'base64':
default:
return base64_decode($file->content);
case 'base64':
default:
return base64_decode($file->content);
}
}
}
+1 -2
View File
@@ -207,8 +207,7 @@ abstract class qtype_renderer extends plugin_renderer_base {
}
protected function feedback_class($fraction) {
return question_state::graded_state_for_fraction($fraction)
->get_feedback_class();
return question_state::graded_state_for_fraction($fraction)->get_feedback_class();
}
/**