MDL-20636 Fix a lot more coding style issues.

This commit is contained in:
Tim Hunt 2011-05-20 20:18:04 +01:00
parent e0736817f0
commit 59a3fcd3eb
9 changed files with 601 additions and 750 deletions

View file

@ -59,7 +59,8 @@ class backup_qtype_multianswer_plugin extends backup_qtype_plugin {
$pluginwrapper->add_child($multianswer);
// set source to populate the data
$multianswer->set_source_table('question_multianswer', array('question' => backup::VAR_PARENTID));
$multianswer->set_source_table('question_multianswer',
array('question' => backup::VAR_PARENTID));
// don't need to annotate ids nor files

View file

@ -38,7 +38,6 @@ class restore_qtype_multianswer_plugin extends restore_qtype_plugin {
* Returns the paths to be handled by the plugin at question level
*/
protected function define_question_plugin_structure() {
$paths = array();
// This qtype uses question_answers, add them
@ -46,10 +45,9 @@ class restore_qtype_multianswer_plugin extends restore_qtype_plugin {
// Add own qtype stuff
$elename = 'multianswer';
$elepath = $this->get_pathfor('/multianswer'); // we used get_recommended_name() so this works
$elepath = $this->get_pathfor('/multianswer');
$paths[] = new restore_path_element($elename, $elepath);
return $paths; // And we return the interesting paths
}
@ -67,7 +65,8 @@ class restore_qtype_multianswer_plugin extends restore_qtype_plugin {
$newquestionid = $this->get_new_parentid('question');
$questioncreated = $this->get_mappingid('question_created', $oldquestionid) ? true : false;
// If the question has been created by restore, we need to create its question_multianswer too
// If the question has been created by restore, we need to create its
// question_multianswer too
if ($questioncreated) {
// Adjust some columns
$data->question = $newquestionid;
@ -79,8 +78,6 @@ class restore_qtype_multianswer_plugin extends restore_qtype_plugin {
$newitemid = $DB->insert_record('question_multianswer', $data);
// Create mapping (need it for after_execute recode of sequence)
$this->set_mapping('question_multianswer', $oldid, $newitemid);
} else {
// Nothing to remap if the question already existed
}
}
@ -97,18 +94,21 @@ class restore_qtype_multianswer_plugin extends restore_qtype_plugin {
global $DB;
// Now that all the questions have been restored, let's process
// the created question_multianswer sequences (list of question ids)
$rs = $DB->get_recordset_sql("SELECT qma.id, qma.sequence
$rs = $DB->get_recordset_sql("
SELECT qma.id, qma.sequence
FROM {question_multianswer} qma
JOIN {backup_ids_temp} bi ON bi.newitemid = qma.question
WHERE bi.backupid = ?
AND bi.itemname = 'question_created'", array($this->get_restoreid()));
AND bi.itemname = 'question_created'",
array($this->get_restoreid()));
foreach ($rs as $rec) {
$sequencearr = explode(',', $rec->sequence);
foreach ($sequencearr as $key => $question) {
$sequencearr[$key] = $this->get_mappingid('question', $question);
}
$sequence = implode(',', $sequencearr);
$DB->set_field('question_multianswer', 'sequence', $sequence, array('id' => $rec->id));
$DB->set_field('question_multianswer', 'sequence', $sequence,
array('id' => $rec->id));
}
$rs->close();
}
@ -127,7 +127,8 @@ class restore_qtype_multianswer_plugin extends restore_qtype_plugin {
$answer = $state->answer;
$resultarr = array();
// Get sequence of questions
$sequence = $DB->get_field('question_multianswer', 'sequence', array('question' => $state->question));
$sequence = $DB->get_field('question_multianswer', 'sequence',
array('question' => $state->question));
$sequencearr = explode(',', $sequence);
// Let's process each pair
foreach (explode(',', $answer) as $pair) {

View file

@ -35,203 +35,238 @@ defined('MOODLE_INTERNAL') || die();
*/
class question_edit_multianswer_form extends question_edit_form {
// $questiondisplay will contain the qtype_multianswer_extract_question from the questiontext
public $questiondisplay ;
// $savedquestiondisplay will contain the qtype_multianswer_extract_question from the questiontext in database
public $savedquestion ;
public $savedquestiondisplay ;
public $used_in_quiz = false ;
public $qtype_change = false ;
public $negative_diff = 0 ;
// $questiondisplay will contain the qtype_multianswer_extract_question from
// the questiontext
public $questiondisplay;
// $savedquestiondisplay will contain the qtype_multianswer_extract_question
// from the questiontext in database
public $savedquestion;
public $savedquestiondisplay;
public $used_in_quiz = false;
public $qtype_change = false;
public $negative_diff = 0;
public $nb_of_quiz = 0;
public $nb_of_attempts = 0;
public $confirm = 0 ;
public $reload = false ;
public $confirm = 0;
public $reload = false;
function question_edit_multianswer_form(&$submiturl, &$question, &$category, &$contexts, $formeditable = true){
global $QTYPES, $SESSION, $CFG, $DB;
public function __construct($submiturl, $question, $category, $contexts, $formeditable = true) {
global $SESSION, $CFG, $DB;
$this->regenerate = true;
if ( "1" == optional_param('reload','', PARAM_INT )) {
$this->reload = true ;
}else {
$this->reload = false ;
if ("1" == optional_param('reload', '', PARAM_INT)) {
$this->reload = true;
} else {
$this->reload = false;
}
// $this->question = $question;
$this->used_in_quiz =false;
// echo "<p> question <pre>";print_r($question);echo "</pre></p>";
if(isset($question->id) && $question->id != 0 ){
$this->savedquestiondisplay =fullclone($question ) ;
if ($list = $DB->get_records('quiz_question_instances', array( 'question'=> $question->id))){
foreach($list as $key => $li){
$this->used_in_quiz = false;
if (isset($question->id) && $question->id != 0) {
$this->savedquestiondisplay = fullclone($question);
if ($list = $DB->get_records('quiz_question_instances',
array('question' => $question->id))) {
foreach ($list as $key => $li) {
$this->nb_of_quiz ++;
if($att = $DB->get_records('quiz_attempts',array( 'quiz'=> $li->quiz, 'preview'=> '0'))){
$this->nb_of_attempts+= count($att);
if ($att = $DB->get_records('quiz_attempts',
array('quiz' => $li->quiz, 'preview' => '0'))) {
$this->nb_of_attempts += count($att);
$this->used_in_quiz = true;
}
}
}
}
parent::question_edit_form($submiturl, $question, $category, $contexts, $formeditable);
parent::__construct($submiturl, $question, $category, $contexts, $formeditable);
}
protected function definition_inner($mform) {
$mform->addElement('hidden', 'reload', 1);
// $mform->addElement('hidden', 'generalfeedback','');
$mform->setType('reload', PARAM_INT);
// Remove meaningless defaultgrade field.
$mform->removeElement('defaultgrade');
$this->confirm = optional_param('confirm','0', PARAM_RAW);
$this->confirm = optional_param('confirm', '0', PARAM_RAW);
// display the questions from questiontext;
if ( "" != optional_param('questiontext','', PARAM_RAW)) {
// echo "<p> optional_param('questiontext' <pre>";print_r(optional_param('questiontext','', PARAM_RAW));echo "</pre></p>";
if ("" != optional_param('questiontext', '', PARAM_RAW)) {
$this->questiondisplay = fullclone(qtype_multianswer_extract_question(
optional_param('questiontext', '', PARAM_RAW)));
$this->questiondisplay = fullclone(qtype_multianswer_extract_question(optional_param('questiontext','', PARAM_RAW))) ;
}else {
if(!$this->reload && !empty($this->savedquestiondisplay->id)){
} else {
if (!$this->reload && !empty($this->savedquestiondisplay->id)) {
// use database data as this is first pass
// question->id == 0 so no stored datasets
$this->questiondisplay = fullclone($this->savedquestiondisplay);
foreach($this->questiondisplay->options->questions as $subquestion){
if (!empty($subquestion)){
foreach ($this->questiondisplay->options->questions as $subquestion) {
if (!empty($subquestion)) {
$subquestion->answer = array('');
foreach($subquestion->options->answers as $ans){
$subquestion->answer[]=$ans->answer ;
}
// $subquestion->answer = fullclone($subquestion->options->answers);
foreach ($subquestion->options->answers as $ans) {
$subquestion->answer[] = $ans->answer;
}
}
}else {
}
} else {
$this->questiondisplay = "";
}
}
if ( isset($this->savedquestiondisplay->options->questions) && is_array($this->savedquestiondisplay->options->questions) ) {
$countsavedsubquestions =0;
foreach($this->savedquestiondisplay->options->questions as $subquestion){
if (!empty($subquestion)){
if (isset($this->savedquestiondisplay->options->questions) &&
is_array($this->savedquestiondisplay->options->questions)) {
$countsavedsubquestions = 0;
foreach ($this->savedquestiondisplay->options->questions as $subquestion) {
if (!empty($subquestion)) {
$countsavedsubquestions++;
}
}
} else {
$countsavedsubquestions =0;
$countsavedsubquestions = 0;
}
if ($this->reload){
if ( isset($this->questiondisplay->options->questions) && is_array($this->questiondisplay->options->questions) ) {
$countsubquestions =0;
foreach($this->questiondisplay->options->questions as $subquestion){
if (!empty($subquestion)){
if ($this->reload) {
if (isset($this->questiondisplay->options->questions) &&
is_array($this->questiondisplay->options->questions)) {
$countsubquestions = 0;
foreach ($this->questiondisplay->options->questions as $subquestion) {
if (!empty($subquestion)) {
$countsubquestions++;
}
}
} else {
$countsubquestions =0;
$countsubquestions = 0;
}
}else{
$countsubquestions =$countsavedsubquestions ;
} else {
$countsubquestions = $countsavedsubquestions;
}
// echo "<p> count subquestion $countsubquestions <pre>";print_r($this->savedquestiondisplay);echo "</pre></p>";
// // echo "<p> saved question $countsubquestions <pre>";print_r($this->questiondisplay);echo "</pre></p>";
$mform->addElement('submit', 'analyzequestion', get_string('decodeverifyquestiontext','qtype_multianswer'));
$mform->addElement('submit', 'analyzequestion',
get_string('decodeverifyquestiontext', 'qtype_multianswer'));
$mform->registerNoSubmitButton('analyzequestion');
if ( $this->reload ){
if ($this->reload) {
$mform->addElement('html', '<div class="ablock clearfix">');
$mform->addElement('html', '<div class=" clearfix">');
for ($sub =1;$sub <=$countsubquestions ;$sub++) {
for ($sub = 1; $sub <= $countsubquestions; $sub++) {
$this->editas[$sub] = 'unknown type';
if (isset( $this->questiondisplay->options->questions[$sub]->qtype) ) {
$this->editas[$sub] = $this->questiondisplay->options->questions[$sub]->qtype ;
if (isset($this->questiondisplay->options->questions[$sub]->qtype)) {
$this->editas[$sub] = $this->questiondisplay->options->questions[$sub]->qtype;
} else if (optional_param('sub_'.$sub."_".'qtype', '', PARAM_RAW) != '') {
$this->editas[$sub] = optional_param('sub_'.$sub."_".'qtype', '', PARAM_RAW);
}
$storemess = '';
if(isset($this->savedquestiondisplay->options->questions[$sub]->qtype) &&
$this->savedquestiondisplay->options->questions[$sub]->qtype != $this->questiondisplay->options->questions[$sub]->qtype ){
$this->qtype_change = true ;
$storemess = "<font class=\"error\"> STORED QTYPE ".question_bank::get_qtype_name($this->savedquestiondisplay->options->questions[$sub]->qtype)."</font >";
if (isset($this->savedquestiondisplay->options->questions[$sub]->qtype) &&
$this->savedquestiondisplay->options->questions[$sub]->qtype !=
$this->questiondisplay->options->questions[$sub]->qtype) {
$this->qtype_change = true;
$storemess = "<font class=\"error\"> STORED QTYPE " .
question_bank::get_qtype_name(
$this->savedquestiondisplay->options->questions[$sub]->qtype).
"</font >";
}
$mform->addElement('header', 'subhdr'.$sub, get_string('questionno', 'question',
'{#'.$sub.'}').'&nbsp;'.question_bank::get_qtype_name($this->questiondisplay->options->questions[$sub]->qtype).$storemess);
'{#'.$sub.'}').'&nbsp;'.question_bank::get_qtype_name(
$this->questiondisplay->options->questions[$sub]->qtype).$storemess);
$mform->addElement('static', 'sub_'.$sub."_".'questiontext', get_string('questiondefinition','qtype_multianswer'),array('cols'=>60, 'rows'=>3));
$mform->addElement('static', 'sub_'.$sub."_".'questiontext',
get_string('questiondefinition', 'qtype_multianswer'),
array('cols' => 60, 'rows' => 3));
if (isset ( $this->questiondisplay->options->questions[$sub]->questiontext)) {
$mform->setDefault('sub_'.$sub."_".'questiontext', $this->questiondisplay->options->questions[$sub]->questiontext['text']);
if (isset ($this->questiondisplay->options->questions[$sub]->questiontext)) {
$mform->setDefault('sub_'.$sub."_".'questiontext',
$this->questiondisplay->options->questions[$sub]->questiontext['text']);
}
$mform->addElement('static', 'sub_'.$sub."_".'defaultgrade', get_string('defaultgrade', 'question'));
$mform->setDefault('sub_'.$sub."_".'defaultgrade',$this->questiondisplay->options->questions[$sub]->defaultgrade);
$mform->addElement('static', 'sub_'.$sub."_".'defaultgrade',
get_string('defaultgrade', 'question'));
$mform->setDefault('sub_'.$sub."_".'defaultgrade',
$this->questiondisplay->options->questions[$sub]->defaultgrade);
if ($this->questiondisplay->options->questions[$sub]->qtype =='shortanswer' ) {
$mform->addElement('static', 'sub_'.$sub."_".'usecase', get_string('casesensitive', 'question'));
if ($this->questiondisplay->options->questions[$sub]->qtype == 'shortanswer') {
$mform->addElement('static', 'sub_'.$sub."_".'usecase',
get_string('casesensitive', 'question'));
}
if ($this->questiondisplay->options->questions[$sub]->qtype =='multichoice' ) {
$mform->addElement('static', 'sub_'.$sub."_".'layout', get_string('layout', 'qtype_multianswer'),array('cols'=>60, 'rows'=>1)) ;//, $gradeoptions);
if ($this->questiondisplay->options->questions[$sub]->qtype == 'multichoice') {
$mform->addElement('static', 'sub_'.$sub."_".'layout',
get_string('layout', 'qtype_multianswer'),
array('cols' => 60, 'rows' => 1));
}
foreach ($this->questiondisplay->options->questions[$sub]->answer as $key =>$ans) {
foreach ($this->questiondisplay->options->questions[$sub]->answer as $key => $ans) {
$mform->addElement('static', 'sub_'.$sub."_".'answer['.$key.']', get_string('answer', 'question'), array('cols'=>60, 'rows'=>1));
$mform->addElement('static', 'sub_'.$sub."_".'answer['.$key.']',
get_string('answer', 'question'), array('cols' => 60, 'rows' => 1));
if ($this->questiondisplay->options->questions[$sub]->qtype =='numerical' && $key == 0 ) {
$mform->addElement('static', 'sub_'.$sub."_".'tolerance['.$key.']', get_string('acceptederror', 'quiz')) ;//, $gradeoptions);
if ($this->questiondisplay->options->questions[$sub]->qtype == 'numerical' &&
$key == 0) {
$mform->addElement('static', 'sub_'.$sub."_".'tolerance['.$key.']',
get_string('acceptederror', 'quiz'));
}
$mform->addElement('static', 'sub_'.$sub."_".'fraction['.$key.']', get_string('grade')) ;//, $gradeoptions);
$mform->addElement('static', 'sub_'.$sub."_".'fraction['.$key.']',
get_string('grade'));
$mform->addElement('static', 'sub_'.$sub."_".'feedback['.$key.']', get_string('feedback', 'question'));
$mform->addElement('static', 'sub_'.$sub."_".'feedback['.$key.']',
get_string('feedback', 'question'));
}
}
$mform->addElement('html', '</div>');
$this->negative_diff =$countsavedsubquestions - $countsubquestions ;
if ( ($this->negative_diff > 0 ) ||$this->qtype_change || ($this->used_in_quiz && $this->negative_diff != 0)){
$mform->addElement('header', 'additemhdr', get_string('warningquestionmodified','qtype_multianswer'));
$this->negative_diff = $countsavedsubquestions - $countsubquestions;
if (($this->negative_diff > 0) ||$this->qtype_change ||
($this->used_in_quiz && $this->negative_diff != 0)) {
$mform->addElement('header', 'additemhdr',
get_string('warningquestionmodified', 'qtype_multianswer'));
}
if($this->negative_diff > 0) {
$mform->addElement('static', 'alert1', "<strong>".get_string('questiondeleted','qtype_multianswer')."</strong>",get_string('questionsless','qtype_multianswer',$this->negative_diff));
if ($this->negative_diff > 0) {
$mform->addElement('static', 'alert1', "<strong>".
get_string('questiondeleted', 'qtype_multianswer')."</strong>",
get_string('questionsless', 'qtype_multianswer', $this->negative_diff));
}
if($this->qtype_change ) {
$mform->addElement('static', 'alert1', "<strong>".get_string('questiontypechanged','qtype_multianswer')."</strong>",get_string('questiontypechangedcomment','qtype_multianswer'));
if ($this->qtype_change) {
$mform->addElement('static', 'alert1', "<strong>".
get_string('questiontypechanged', 'qtype_multianswer')."</strong>",
get_string('questiontypechangedcomment', 'qtype_multianswer'));
}
$mform->addElement('html', '</div>');
}
if( $this->used_in_quiz){
if($this->negative_diff < 0) {
if ($this->used_in_quiz) {
if ($this->negative_diff < 0) {
$diff = $countsubquestions - $countsavedsubquestions;
$mform->addElement('static', 'alert1', "<strong>".get_string('questionsadded','qtype_multianswer')."</strong>","<strong>".get_string('questionsmore','qtype_multianswer',$diff)."</strong>");
$mform->addElement('static', 'alert1', "<strong>".
get_string('questionsadded', 'qtype_multianswer')."</strong>",
"<strong>".get_string('questionsmore', 'qtype_multianswer', $diff).
"</strong>");
}
$a = new stdClass() ;
$a = new stdClass();
$a->nb_of_quiz = $this->nb_of_quiz;
$a->nb_of_attempts = $this->nb_of_attempts;
$mform->addElement('header', 'additemhdr2', get_string('questionusedinquiz','qtype_multianswer',$a));
$mform->addElement('static', 'alertas', get_string('youshouldnot','qtype_multianswer'));
$mform->addElement('header', 'additemhdr2',
get_string('questionusedinquiz', 'qtype_multianswer', $a));
$mform->addElement('static', 'alertas',
get_string('youshouldnot', 'qtype_multianswer'));
}
if ( ($this->negative_diff > 0 || $this->used_in_quiz && ($this->negative_diff > 0 ||$this->negative_diff < 0 || $this->qtype_change ) ) && $this->reload ){
$mform->addElement('header', 'additemhdr', get_string('questionsaveasedited', 'qtype_multianswer'));
$mform->addElement('checkbox', 'confirm','' ,get_string('confirmquestionsaveasedited', 'qtype_multianswer'));
if (($this->negative_diff > 0 || $this->used_in_quiz &&
($this->negative_diff > 0 || $this->negative_diff < 0 || $this->qtype_change)) &&
$this->reload) {
$mform->addElement('header', 'additemhdr',
get_string('questionsaveasedited', 'qtype_multianswer'));
$mform->addElement('checkbox', 'confirm', '',
get_string('confirmquestionsaveasedited', 'qtype_multianswer'));
$mform->setDefault('confirm', 0);
}else {
$mform->addElement('hidden', 'confirm',0);
} else {
$mform->addElement('hidden', 'confirm', 0);
}
}
function set_data($question) {
public function set_data($question) {
global $DB;
$default_values =array();
if (isset($question->id) and $question->id and $question->qtype and $question->questiontext) {
$default_values = array();
if (isset($question->id) and $question->id and $question->qtype &&
$question->questiontext) {
foreach ($question->options->questions as $key => $wrapped) {
if(!empty($wrapped)){
if (!empty($wrapped)) {
// The old way of restoring the definitions is kept to gradually
// update all multianswer questions
if (empty($wrapped->questiontext)) {
@ -247,9 +282,10 @@ class question_edit_multianswer_form extends question_edit_form {
$parsableanswerdef .= 'NUMERICAL:';
break;
default:
print_error('unknownquestiontype', 'question', '', $wrapped->qtype);
print_error('unknownquestiontype', 'question', '',
$wrapped->qtype);
}
$separator= '';
$separator = '';
foreach ($wrapped->options->answers as $subanswer) {
$parsableanswerdef .= $separator
. '%' . round(100*$subanswer->fraction) . '%';
@ -268,168 +304,192 @@ class question_edit_multianswer_form extends question_edit_form {
}
$parsableanswerdef .= '}';
// Fix the questiontext fields of old questions
$DB->set_field('question', 'questiontext', $parsableanswerdef, array('id' => $wrapped->id));
$DB->set_field('question', 'questiontext', $parsableanswerdef,
array('id' => $wrapped->id));
} else {
$parsableanswerdef = str_replace('&#', '&\#', $wrapped->questiontext);
}
$question->questiontext = str_replace("{#$key}", $parsableanswerdef, $question->questiontext);
$question->questiontext = str_replace("{#$key}", $parsableanswerdef,
$question->questiontext);
}
}
}
// set default to $questiondisplay questions elements
if ( $this->reload ){
if ($this->reload) {
if (isset($this->questiondisplay->options->questions)) {
$subquestions = fullclone($this->questiondisplay->options->questions) ;
$subquestions = fullclone($this->questiondisplay->options->questions);
if (count($subquestions)) {
$sub =1;
$sub = 1;
foreach ($subquestions as $subquestion) {
$prefix = 'sub_'.$sub.'_' ;
$prefix = 'sub_'.$sub.'_';
// validate parameters
$answercount = 0;
$maxgrade = false;
$maxfraction = -1;
if ($subquestion->qtype =='shortanswer' ) {
if ($subquestion->qtype == 'shortanswer') {
switch ($subquestion->usecase) {
case '1':
$default_values[$prefix.'usecase']= get_string('caseyes', 'qtype_shortanswer');
$default_values[$prefix.'usecase'] =
get_string('caseyes', 'qtype_shortanswer');
break;
case '0':
default :
$default_values[$prefix.'usecase']= get_string('caseno', 'qtype_shortanswer');
$default_values[$prefix.'usecase'] =
get_string('caseno', 'qtype_shortanswer');
}
}
if ($subquestion->qtype == 'multichoice' ) {
$default_values[$prefix.'layout'] = $subquestion->layout ;
if ($subquestion->qtype == 'multichoice') {
$default_values[$prefix.'layout'] = $subquestion->layout;
switch ($subquestion->layout) {
case '0':
$default_values[$prefix.'layout']= get_string('layoutselectinline', 'qtype_multianswer');
$default_values[$prefix.'layout'] =
get_string('layoutselectinline', 'qtype_multianswer');
break;
case '1':
$default_values[$prefix.'layout']= get_string('layoutvertical', 'qtype_multianswer');
$default_values[$prefix.'layout'] =
get_string('layoutvertical', 'qtype_multianswer');
break;
case '2':
$default_values[$prefix.'layout']= get_string('layouthorizontal', 'qtype_multianswer');
$default_values[$prefix.'layout'] =
get_string('layouthorizontal', 'qtype_multianswer');
break;
default:
$default_values[$prefix.'layout']= get_string('layoutundefined', 'qtype_multianswer');
$default_values[$prefix.'layout'] =
get_string('layoutundefined', 'qtype_multianswer');
}
}
foreach ($subquestion->answer as $key=>$answer) {
if ( $subquestion->qtype == 'numerical' && $key == 0 ) {
$default_values[$prefix.'tolerance['.$key.']'] = $subquestion->tolerance[0] ;
foreach ($subquestion->answer as $key => $answer) {
if ($subquestion->qtype == 'numerical' && $key == 0) {
$default_values[$prefix.'tolerance['.$key.']'] =
$subquestion->tolerance[0];
}
$trimmedanswer = trim($answer);
if ($trimmedanswer !== '') {
$answercount++;
if ($subquestion->qtype == 'numerical' && !(is_numeric($trimmedanswer) || $trimmedanswer == '*')) {
$this->_form->setElementError($prefix.'answer['.$key.']' , get_string('answermustbenumberorstar', 'qtype_numerical'));
if ($subquestion->qtype == 'numerical' &&
!(is_numeric($trimmedanswer) || $trimmedanswer == '*')) {
$this->_form->setElementError($prefix.'answer['.$key.']',
get_string('answermustbenumberorstar',
'qtype_numerical'));
}
if ($subquestion->fraction[$key] == 1) {
$maxgrade = true;
}
if ($subquestion->fraction[$key] > $maxfraction) {
$maxfraction = $subquestion->fraction[$key] ;
$maxfraction = $subquestion->fraction[$key];
}
}
$default_values[$prefix.'answer['.$key.']'] = htmlspecialchars ($answer);
$default_values[$prefix.'answer['.$key.']'] =
htmlspecialchars($answer);
}
if ($answercount == 0) {
if ($subquestion->qtype == 'multichoice' ) {
$this->_form->setElementError($prefix.'answer[0]' , get_string('notenoughanswers', 'qtype_multichoice', 2));
if ($subquestion->qtype == 'multichoice') {
$this->_form->setElementError($prefix.'answer[0]',
get_string('notenoughanswers', 'qtype_multichoice', 2));
} else {
$this->_form->setElementError($prefix.'answer[0]' , get_string('notenoughanswers', 'question', 1));
$this->_form->setElementError($prefix.'answer[0]',
get_string('notenoughanswers', 'question', 1));
}
}
if ($maxgrade == false) {
$this->_form->setElementError($prefix.'fraction[0]' ,get_string('fractionsnomax', 'question'));
$this->_form->setElementError($prefix.'fraction[0]',
get_string('fractionsnomax', 'question'));
}
foreach ($subquestion->feedback as $key=>$answer) {
foreach ($subquestion->feedback as $key => $answer) {
$default_values[$prefix.'feedback['.$key.']'] = htmlspecialchars ($answer['text']);
$default_values[$prefix.'feedback['.$key.']'] =
htmlspecialchars ($answer['text']);
}
foreach ( $subquestion->fraction as $key=>$answer) {
foreach ($subquestion->fraction as $key => $answer) {
$default_values[$prefix.'fraction['.$key.']'] = $answer;
}
$sub++;
}
}
}
}
$default_values['alertas']= "<strong>".get_string('questioninquiz','qtype_multianswer')."</strong>";
$default_values['alertas']= "<strong>".get_string('questioninquiz', 'qtype_multianswer').
"</strong>";
if( $default_values != "") {
if ($default_values != "") {
$question = (object)((array)$question + $default_values);
}
parent::set_data($question);
}
function validation($data, $files) {
public function validation($data, $files) {
$errors = parent::validation($data, $files);
$questiondisplay = qtype_multianswer_extract_question($data['questiontext']);
// echo "<p> questiondisplay ".$data['questiontext']['text']." <pre>";print_r($questiondisplay);echo "</pre></p>";
if (isset($questiondisplay->options->questions)) {
$subquestions = fullclone($questiondisplay->options->questions) ;
$subquestions = fullclone($questiondisplay->options->questions);
if (count($subquestions)) {
$sub =1;
$sub = 1;
foreach ($subquestions as $subquestion) {
$prefix = 'sub_'.$sub.'_' ;
$prefix = 'sub_'.$sub.'_';
$answercount = 0;
$maxgrade = false;
$maxfraction = -1;
if(isset($this->savedquestiondisplay->options->questions[$sub]->qtype) &&
$this->savedquestiondisplay->options->questions[$sub]->qtype != $questiondisplay->options->questions[$sub]->qtype ){
$storemess = " STORED QTYPE ".question_bank::get_qtype_name($this->savedquestiondisplay->options->questions[$sub]->qtype);
if (isset($this->savedquestiondisplay->options->questions[$sub]->qtype) &&
$this->savedquestiondisplay->options->questions[$sub]->qtype !=
$questiondisplay->options->questions[$sub]->qtype) {
$storemess = " STORED QTYPE ".question_bank::get_qtype_name(
$this->savedquestiondisplay->options->questions[$sub]->qtype);
}
foreach ( $subquestion->answer as $key=>$answer) {
foreach ($subquestion->answer as $key => $answer) {
$trimmedanswer = trim($answer);
if ($trimmedanswer !== '') {
$answercount++;
if ($subquestion->qtype =='numerical' && !(is_numeric($trimmedanswer) || $trimmedanswer == '*')) {
$errors[$prefix.'answer['.$key.']']= get_string('answermustbenumberorstar', 'qtype_numerical');
if ($subquestion->qtype == 'numerical' &&
!(is_numeric($trimmedanswer) || $trimmedanswer == '*')) {
$errors[$prefix.'answer['.$key.']'] =
get_string('answermustbenumberorstar', 'qtype_numerical');
}
if ($subquestion->fraction[$key] == 1) {
$maxgrade = true;
}
if ($subquestion->fraction[$key] > $maxfraction) {
$maxfraction = $subquestion->fraction[$key] ;
$maxfraction = $subquestion->fraction[$key];
}
}
}
if ($answercount==0) {
if ( $subquestion->qtype =='multichoice' ) {
$errors[$prefix.'answer[0]']= get_string('notenoughanswers', 'qtype_multichoice', 2);
}else {
$errors[$prefix.'answer[0]'] = get_string('notenoughanswers', 'question', 1);
if ($answercount == 0) {
if ($subquestion->qtype == 'multichoice') {
$errors[$prefix.'answer[0]'] =
get_string('notenoughanswers', 'qtype_multichoice', 2);
} else {
$errors[$prefix.'answer[0]'] =
get_string('notenoughanswers', 'question', 1);
}
}
if ($maxgrade == false) {
$errors[$prefix.'fraction[0]']=get_string('fractionsnomax', 'question');
$errors[$prefix.'fraction[0]'] =
get_string('fractionsnomax', 'question');
}
$sub++;
}
} else {
$errors['questiontext']=get_string('questionsmissing', 'qtype_multianswer');
$errors['questiontext'] = get_string('questionsmissing', 'qtype_multianswer');
}
}
// $question = qtype_multianswer_extract_question($data['questiontext']);
// if (isset $question->options->questions
if (( $this->negative_diff > 0 || $this->used_in_quiz && ($this->negative_diff > 0 ||$this->negative_diff < 0 || $this->qtype_change ))&& $this->confirm == 0 ){
$errors['confirm']=get_string('confirmsave', 'qtype_multianswer',$this->negative_diff);
}
if (($this->negative_diff > 0 || $this->used_in_quiz &&
($this->negative_diff > 0 || $this->negative_diff < 0 ||
$this->qtype_change))&& $this->confirm == 0) {
$errors['confirm'] =
get_string('confirmsave', 'qtype_multianswer', $this->negative_diff);
}
return $errors;
}
function qtype() {
public function qtype() {
return 'multianswer';
}
}

View file

@ -44,7 +44,7 @@ $string['noquestions'] = 'The Cloze(multianswer) question "<strong>{$a}</strong>
$string['qtypenotrecognized'] = 'questiontype {$a} not recognized';
$string['questionnadded'] = 'Question added';
$string['questiondefinition'] = 'Question definition';
$string['questiondeleted'] = 'Question deleted' ;
$string['questiondeleted'] = 'Question deleted';
$string['questioninquiz'] = '
<ul>
@ -61,5 +61,5 @@ $string['questiontypechanged'] = 'Question type changed';
$string['questiontypechangedcomment'] = 'At least one question type has been changed.<br \>Did you add, delete or move a question?<br \>Look ahead.';
$string['questionusedinquiz'] = 'This question is used in {$a->nb_of_quiz} quiz(s), total attempt(s) : {$a->nb_of_attempts} ';
$string['unknownquestiontypeofsubquestion'] = 'Unknown question type: {$a->type} of question part # {$a->sub}';
$string['warningquestionmodified'] = '<b>WARNING</b>' ;
$string['warningquestionmodified'] = '<b>WARNING</b>';
$string['youshouldnot'] = '<b>YOU SHOULD NOT</b>';

View file

@ -35,22 +35,22 @@ defined('MOODLE_INTERNAL') || die();
*/
class embedded_cloze_qtype extends question_type {
function name() {
public function name() {
return 'multianswer';
}
function requires_qtypes() {
public function requires_qtypes() {
return array('shortanswer', 'numerical', 'multichoice');
}
function get_question_options(&$question) {
global $QTYPES, $DB, $OUTPUT;
public function get_question_options($question) {
global $DB, $OUTPUT;
// Get relevant data indexed by positionkey from the multianswers table
if (!$sequence = $DB->get_field('question_multianswer', 'sequence', array('question' => $question->id))) {
echo $OUTPUT->notification(get_string('noquestions','qtype_multianswer',$question->name));
$question->options->questions['1']= '';
return true ;
echo $OUTPUT->notification(get_string('noquestions', 'qtype_multianswer', $question->name));
$question->options->questions['1'] = '';
return true;
}
$wrappedquestions = $DB->get_records_list('question', 'id', explode(',', $sequence), 'id ASC');
@ -63,32 +63,33 @@ class embedded_cloze_qtype extends question_type {
// before using the values.
// first all possible questions from sequence are nulled
// then filled with the data if available in $wrappedquestions
$nbvaliquestion = 0 ;
foreach($sequence as $seq){
$question->options->questions[$seq]= '';
$nbvaliquestion = 0;
foreach ($sequence as $seq) {
$question->options->questions[$seq] = '';
}
if (isset($wrappedquestions) && is_array($wrappedquestions)){
if (isset($wrappedquestions) && is_array($wrappedquestions)) {
foreach ($wrappedquestions as $wrapped) {
if (!$QTYPES[$wrapped->qtype]->get_question_options($wrapped)) {
echo $OUTPUT->notification("Unable to get options for questiontype {$wrapped->qtype} (id={$wrapped->id})");
}else {
} else {
// for wrapped questions the maxgrade is always equal to the defaultgrade,
// there is no entry in the question_instances table for them
$wrapped->maxgrade = $wrapped->defaultgrade;
$nbvaliquestion++ ;
$question->options->questions[$sequence[$wrapped->id]] = clone($wrapped); // ??? Why do we need a clone here?
$nbvaliquestion++;
// ??? Why do we need a clone here?
$question->options->questions[$sequence[$wrapped->id]] = clone($wrapped);
}
}
}
if ($nbvaliquestion == 0 ) {
echo $OUTPUT->notification(get_string('noquestions','qtype_multianswer',$question->name));
if ($nbvaliquestion == 0) {
echo $OUTPUT->notification(get_string('noquestions', 'qtype_multianswer', $question->name));
}
return true;
}
function save_question_options($question) {
global $QTYPES, $DB;
public function save_question_options($question) {
global $DB;
$result = new stdClass();
// This function needs to be able to handle the case where the existing set of wrapped
@ -105,13 +106,13 @@ class embedded_cloze_qtype extends question_type {
$oldwrappedquestions = $DB->get_records_list('question', 'id', explode(',', $oldwrappedids), 'id ASC');
}
$sequence = array();
foreach($question->options->questions as $wrapped) {
if (!empty($wrapped)){
foreach ($question->options->questions as $wrapped) {
if (!empty($wrapped)) {
// if we still have some old wrapped question ids, reuse the next of them
if (is_array($oldwrappedquestions) && $oldwrappedquestion = array_shift($oldwrappedquestions)) {
$wrapped->id = $oldwrappedquestion->id;
if($oldwrappedquestion->qtype != $wrapped->qtype ) {
if ($oldwrappedquestion->qtype != $wrapped->qtype) {
switch ($oldwrappedquestion->qtype) {
case 'multichoice':
$DB->delete_records('question_multichoice', array('question' => $oldwrappedquestion->id));
@ -123,31 +124,31 @@ class embedded_cloze_qtype extends question_type {
$DB->delete_records('question_numerical', array('question' => $oldwrappedquestion->id));
break;
default:
print_error('qtypenotrecognized', 'qtype_multianswer','',$oldwrappedquestion->qtype);
$wrapped->id = 0 ;
print_error('qtypenotrecognized', 'qtype_multianswer', '', $oldwrappedquestion->qtype);
$wrapped->id = 0;
}
}
}else {
$wrapped->id = 0 ;
} else {
$wrapped->id = 0;
}
}
$wrapped->name = $question->name;
$wrapped->parent = $question->id;
$previousid = $wrapped->id ;
$previousid = $wrapped->id;
$wrapped->category = $question->category . ',1'; // save_question strips this extra bit off again.
$wrapped = $QTYPES[$wrapped->qtype]->save_question($wrapped, clone($wrapped));
$sequence[] = $wrapped->id;
if ($previousid != 0 && $previousid != $wrapped->id ) {
if ($previousid != 0 && $previousid != $wrapped->id) {
// for some reasons a new question has been created
// so delete the old one
delete_question($previousid) ;
delete_question($previousid);
}
}
// Delete redundant wrapped questions
if(is_array($oldwrappedquestions) && count($oldwrappedquestions)){
if (is_array($oldwrappedquestions) && count($oldwrappedquestions)) {
foreach ($oldwrappedquestions as $oldwrappedquestion) {
delete_question($oldwrappedquestion->id) ;
delete_question($oldwrappedquestion->id);
}
}
@ -164,7 +165,7 @@ class embedded_cloze_qtype extends question_type {
}
}
function save_question($authorizedquestion, $form) {
public function save_question($authorizedquestion, $form) {
$question = qtype_multianswer_extract_question($form->questiontext);
if (isset($authorizedquestion->id)) {
$question->id = $authorizedquestion->id;
@ -179,7 +180,7 @@ class embedded_cloze_qtype extends question_type {
return parent::save_question($question, $form);
}
function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) {
public function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) {
$state->responses = array();
foreach ($question->options->questions as $key => $wrapped) {
$state->responses[$key] = '';
@ -187,7 +188,7 @@ class embedded_cloze_qtype extends question_type {
return true;
}
function restore_session_and_responses(&$question, &$state) {
public function restore_session_and_responses(&$question, &$state) {
$responses = explode(',', $state->responses['']);
$state->responses = array();
foreach ($responses as $response) {
@ -199,7 +200,7 @@ class embedded_cloze_qtype extends question_type {
return true;
}
function save_session_and_responses(&$question, &$state) {
public function save_session_and_responses(&$question, &$state) {
global $DB;
$responses = $state->responses;
// encode - (hyphen) and , (comma) to &#0045; because they are used as
@ -214,36 +215,17 @@ class embedded_cloze_qtype extends question_type {
return true;
}
function delete_question($questionid, $contextid) {
public function delete_question($questionid, $contextid) {
global $DB;
$DB->delete_records("question_multianswer", array("question" => $questionid));
parent::delete_question($questionid, $contextid);
}
function get_correct_responses(&$question, &$state) {
global $QTYPES;
public function get_possible_responses(&$question) {
$responses = array();
foreach($question->options->questions as $key => $wrapped) {
if (!empty($wrapped)){
if ($correct = $QTYPES[$wrapped->qtype]->get_correct_responses($wrapped, $state)) {
$responses[$key] = $correct[''];
} else {
// if there is no correct answer to this subquestion then there
// can not be a correct answer to the whole question either, so
// we have to return null.
return null;
}
}
}
return $responses;
}
function get_possible_responses(&$question) {
global $QTYPES;
$responses = array();
foreach($question->options->questions as $key => $wrapped) {
if (!empty($wrapped)){
foreach ($question->options->questions as $key => $wrapped) {
if (!empty($wrapped)) {
if ($correct = $QTYPES[$wrapped->qtype]->get_possible_responses($wrapped)) {
$responses += $correct;
} else {
@ -256,28 +238,16 @@ class embedded_cloze_qtype extends question_type {
}
return $responses;
}
function get_actual_response_details($question, $state){
global $QTYPES;
$details = array();
foreach($question->options->questions as $key => $wrapped) {
if (!empty($wrapped)){
$stateforquestion = clone($state);
$stateforquestion->responses[''] = $state->responses[$key];
$details = array_merge($details, $QTYPES[$wrapped->qtype]->get_actual_response_details($wrapped, $stateforquestion));
}
}
return $details;
}
function get_html_head_contributions(&$question, &$state) {
public function get_html_head_contributions(&$question, &$state) {
global $PAGE;
parent::get_html_head_contributions($question, $state);
$PAGE->requires->js('/lib/overlib/overlib.js', true);
$PAGE->requires->js('/lib/overlib/overlib_cssstyle.js', true);
}
function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
global $QTYPES, $CFG, $USER, $OUTPUT, $PAGE;
public function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
global $CFG, $USER, $OUTPUT, $PAGE;
$readonly = empty($options->readonly) ? '' : 'readonly="readonly"';
$disabled = empty($options->readonly) ? '' : 'disabled="disabled"';
@ -290,7 +260,7 @@ class embedded_cloze_qtype extends question_type {
// MDL-7497
if (!empty($USER->screenreader)) {
echo "<img src=\"".$OUTPUT->pix_url('icon', 'qtype_'.$question->qtype)."\" ".
"class=\"icon\" alt=\"".get_string('clozeaid','qtype_multichoice')."\" /> ";
"class=\"icon\" alt=\"".get_string('clozeaid', 'qtype_multichoice')."\" /> ";
}
echo '<div class="ablock clearfix">';
@ -309,10 +279,9 @@ class embedded_cloze_qtype extends question_type {
$qtextremaining = $qtextsplits[1];
$positionkey = $regs[1];
if (isset($question->options->questions[$positionkey]) && $question->options->questions[$positionkey] != ''){
if (isset($question->options->questions[$positionkey]) && $question->options->questions[$positionkey] != '') {
$wrapped = &$question->options->questions[$positionkey];
$answers = &$wrapped->options->answers;
// $correctanswers = $QTYPES[$wrapped->qtype]->get_correct_responses($wrapped, $state);
$inputname = $nameprefix.$positionkey;
if (isset($state->responses[$positionkey])) {
@ -320,13 +289,12 @@ class embedded_cloze_qtype extends question_type {
} else {
$response = null;
}
// echo "<p> multianswer positionkey $positionkey response $response state <pre>";print_r($state);echo "</pre></p>";
// Determine feedback popup if any
$popup = '';
$style = '';
$feedbackimg = '';
$feedback = '' ;
$feedback = '';
$correctanswer = '';
$strfeedbackwrapped = $strfeedback;
$testedstate = clone($state);
@ -335,22 +303,22 @@ class embedded_cloze_qtype extends question_type {
$delimiter = '';
if ($correctanswers) {
foreach ($correctanswers as $ca) {
switch($wrapped->qtype){
switch($wrapped->qtype) {
case 'numerical':
case 'shortanswer':
$correctanswer .= $delimiter.$ca;
break ;
break;
case 'multichoice':
if (isset($answers[$ca])){
if (isset($answers[$ca])) {
$correctanswer .= $delimiter.$answers[$ca]->answer;
}
break ;
break;
}
$delimiter = ', ';
}
}
}
if ($correctanswer != '' ) {
if ($correctanswer != '') {
$feedback = '<div class="correctness">';
$feedback .= get_string('correctansweris', 'question', s($correctanswer));
$feedback .= '</div>';
@ -365,8 +333,7 @@ class embedded_cloze_qtype extends question_type {
$testedstate = clone($state);
$testedstate->responses[''] = $response;
foreach ($answers as $answer) {
if($QTYPES[$wrapped->qtype]
->test_response($wrapped, $testedstate, $answer)) {
if ($QTYPES[$wrapped->qtype]->test_response($wrapped, $testedstate, $answer)) {
$chosenanswer = clone($answer);
break;
}
@ -392,7 +359,7 @@ class embedded_cloze_qtype extends question_type {
$feedback = s(str_replace(array("\\", "'"), array("\\\\", "\\'"), $feedback.$chosenanswer->feedback));
if ($options->readonly && $options->correct_responses) {
$strfeedbackwrapped = get_string('correctanswerandfeedback', 'qtype_multianswer');
}else {
} else {
$strfeedbackwrapped = get_string('feedback', 'question');
}
$popup = " onmouseover=\"return overlib('$feedback', STICKY, MOUSEOFF, CAPTION, '$strfeedbackwrapped', FGCOLOR, '#FFFFFF');\" ".
@ -408,7 +375,7 @@ class embedded_cloze_qtype extends question_type {
$feedbackimg = '';
}
}
if ($feedback !='' && $popup == ''){
if ($feedback != '' && $popup == '') {
$strfeedbackwrapped = get_string('correctanswer', 'qtype_multianswer');
$feedback = s(str_replace(array("\\", "'"), array("\\\\", "\\'"), $feedback));
$popup = " onmouseover=\"return overlib('$feedback', STICKY, MOUSEOFF, CAPTION, '$strfeedbackwrapped', FGCOLOR, '#FFFFFF');\" ".
@ -419,36 +386,18 @@ class embedded_cloze_qtype extends question_type {
switch ($wrapped->qtype) {
case 'shortanswer':
case 'numerical':
$size = 1 ;
$size = 1;
foreach ($answers as $answer) {
if (strlen(trim($answer->answer)) > $size ){
if (strlen(trim($answer->answer)) > $size) {
$size = strlen(trim($answer->answer));
}
}
if (strlen(trim($response))> $size ){
if (strlen(trim($response))> $size) {
$size = strlen(trim($response))+1;
}
$size = $size + rand(0,$size*0.15);
$size = $size + rand(0, $size*0.15);
$size > 60 ? $size = 60 : $size = $size;
$styleinfo = "size=\"$size\"";
/**
* Uncomment the following lines if you want to limit for small sizes.
* Results may vary with browsers see MDL-3274
*/
/*
if ($size < 2) {
$styleinfo = 'style="width: 1.1em;"';
}
if ($size == 2) {
$styleinfo = 'style="width: 1.9em;"';
}
if ($size == 3) {
$styleinfo = 'style="width: 2.3em;"';
}
if ($size == 4) {
$styleinfo = 'style="width: 2.8em;"';
}
*/
echo "<input $style $readonly $popup name=\"$inputname\"";
echo " type=\"text\" value=\"".s($response)."\" ".$styleinfo." /> ";
@ -458,7 +407,7 @@ class embedded_cloze_qtype extends question_type {
echo $feedbackimg;
break;
case 'multichoice':
if ($wrapped->options->layout == 0 ){
if ($wrapped->options->layout == 0) {
$outputoptions = '<option></option>'; // Default empty option
foreach ($answers as $mcanswer) {
$selected = '';
@ -483,8 +432,8 @@ class embedded_cloze_qtype extends question_type {
echo "<img src=\"" . $OUTPUT->pix_url('i/feedback') . "\" alt=\"$feedback\" />";
}
echo $feedbackimg;
}else if ($wrapped->options->layout == 1 || $wrapped->options->layout == 2){
$ordernumber=0;
} else if ($wrapped->options->layout == 1 || $wrapped->options->layout == 2) {
$ordernumber = 0;
$anss = Array();
foreach ($answers as $mcanswer) {
$ordernumber++;
@ -515,11 +464,10 @@ class embedded_cloze_qtype extends question_type {
}
// Print the answer text: no automatic numbering
$a->text = format_text($mcanswer->answer, $mcanswer->answerformat, $formatoptions, $cmoptions->course);
// Print feedback if feedback is on
if (($options->feedback || $options->correct_responses) && ($checked )) { //|| $options->readonly
if (($options->feedback || $options->correct_responses) && ($checked)) { //|| $options->readonly
$a->feedback = format_text($mcanswer->feedback, $mcanswer->feedbackformat, $formatoptions, $cmoptions->course);
} else {
$a->feedback = '';
@ -527,12 +475,11 @@ class embedded_cloze_qtype extends question_type {
$anss[] = clone($a);
}
?>
<?php if ($wrapped->options->layout == 1 ){
?>
<table class="answer">
<?php $row = 1; foreach ($anss as $answer) { ?>
<tr class="<?php echo 'r'.$row = $row ? 0 : 1; ?>">
if ($wrapped->options->layout == 1) {
?><table class="answer"><?php
$row = 1;
foreach ($anss as $answer) {
?><tr class="<?php echo 'r'.$row = $row ? 0 : 1; ?>">
<td class="c0 control">
<?php echo $answer->control; ?>
</td>
@ -545,15 +492,14 @@ class embedded_cloze_qtype extends question_type {
<td class="c0 feedback">
<?php echo $answer->feedback; ?>
</td>
</tr>
<?php } ?>
</table>
<?php }else if ($wrapped->options->layout == 2 ){
?>
<table class="answer">
</tr><?php
}
?></table><?php
} else if ($wrapped->options->layout == 2) {
?><table class="answer">
<tr class="<?php echo 'r'.$row = $row ? 0 : 1; ?>">
<?php $row = 1; foreach ($anss as $answer) { ?>
<?php $row = 1;
foreach ($anss as $answer) { ?>
<td class="c0 control">
<?php echo $answer->control; ?>
</td>
@ -565,31 +511,31 @@ class embedded_cloze_qtype extends question_type {
</td>
<td class="c0 feedback">
<?php echo $answer->feedback; ?>
</td>
<?php } ?>
</td><?php
}
?>
</tr>
</table>
<?php }
</table><?php
}
}else {
} else {
echo "no valid layout";
}
break;
default:
$a = new stdClass();
$a->type = $wrapped->qtype ;
$a->type = $wrapped->qtype;
$a->sub = $positionkey;
print_error('unknownquestiontypeofsubquestion', 'qtype_multianswer','',$a);
print_error('unknownquestiontypeofsubquestion', 'qtype_multianswer', '', $a);
break;
}
echo "</label>"; // MDL-7497
}
else {
if(! isset($question->options->questions[$positionkey])){
} else {
if (! isset($question->options->questions[$positionkey])) {
echo $regs[0]."</label>";
}else {
echo '</label><div class="error" >'.get_string('questionnotfound','qtype_multianswer',$positionkey).'</div>';
} else {
echo '</label><div class="error" >'.get_string('questionnotfound', 'qtype_multianswer', $positionkey).'</div>';
}
}
}
@ -601,8 +547,6 @@ class embedded_cloze_qtype extends question_type {
}
public function compare_responses($question, $state, $teststate) {
global $QTYPES;
foreach ($question->options->questions as $key => $wrapped) {
if (empty($wrapped)) {
continue;
@ -639,21 +583,19 @@ class embedded_cloze_qtype extends question_type {
return true;
}
function grade_responses(&$question, &$state, $cmoptions) {
global $QTYPES;
public function grade_responses(&$question, &$state, $cmoptions) {
$teststate = clone($state);
$state->raw_grade = 0;
foreach($question->options->questions as $key => $wrapped) {
if (!empty($wrapped)){
if(isset($state->responses[$key])){
foreach ($question->options->questions as $key => $wrapped) {
if (!empty($wrapped)) {
if (isset($state->responses[$key])) {
$state->responses[$key] = $state->responses[$key];
}else {
$state->responses[$key] = '' ;
} else {
$state->responses[$key] = '';
}
$teststate->responses = array('' => $state->responses[$key]);
$teststate->raw_grade = 0;
if (false === $QTYPES[$wrapped->qtype]
->grade_responses($wrapped, $teststate, $cmoptions)) {
if (false === $QTYPES[$wrapped->qtype]->grade_responses($wrapped, $teststate, $cmoptions)) {
return false;
}
$state->raw_grade += $teststate->raw_grade;
@ -674,73 +616,21 @@ class embedded_cloze_qtype extends question_type {
return true;
}
function get_actual_response($question, $state) {
global $QTYPES;
$teststate = clone($state);
foreach($question->options->questions as $key => $wrapped) {
$state->responses[$key] = html_entity_decode($state->responses[$key]);
$teststate->responses = array('' => $state->responses[$key]);
$correct = $QTYPES[$wrapped->qtype]
->get_actual_response($wrapped, $teststate);
$responses[$key] = implode(';', $correct);
}
return $responses;
}
/**
* @param object $question
* @return mixed either a integer score out of 1 that the average random
* guess by a student might give or an empty string which means will not
* calculate.
*/
function get_random_guess_score($question) {
public function get_random_guess_score($question) {
$totalfraction = 0;
foreach (array_keys($question->options->questions) as $key){
foreach (array_keys($question->options->questions) as $key) {
$totalfraction += question_get_random_guess_score($question->options->questions[$key]);
}
return $totalfraction / count($question->options->questions);
}
/**
* Runs all the code required to set up and save an essay question for testing purposes.
* Alternate DB table prefix may be used to facilitate data deletion.
*/
function generate_test($name, $courseid = null) {
global $DB;
list($form, $question) = parent::generate_test($name, $courseid);
$question->category = $form->category;
$form->questiontext = "This question consists of some text with an answer embedded right here {1:MULTICHOICE:Wrong answer#Feedback for this wrong answer~Another wrong answer#Feedback for the other wrong answer~=Correct answer#Feedback for correct answer~%50%Answer that gives half the credit#Feedback for half credit answer} and right after that you will have to deal with this short answer {1:SHORTANSWER:Wrong answer#Feedback for this wrong answer~=Correct answer#Feedback for correct answer~%50%Answer that gives half the credit#Feedback for half credit answer} and finally we have a floating point number {2:NUMERICAL:=23.8:0.1#Feedback for correct answer 23.8~%50%23.8:2#Feedback for half credit answer in the nearby region of the correct answer}.
Note that addresses like www.moodle.org and smileys :-) all work as normal:
a) How good is this? {:MULTICHOICE:=Yes#Correct~No#We have a different opinion}
b) What grade would you give it? {3:NUMERICAL:=3:2}
Good luck!
";
$form->feedback = "feedback";
$form->generalfeedback = "General feedback";
$form->fraction = 0;
$form->penalty = 0.1;
$form->versioning = 0;
if ($courseid) {
$course = $DB->get_record('course', array('id' => $courseid));
}
return $this->save_question($question, $form);
}
}
//// END OF CLASS ////
/////////////////////////////////////////////////////////////
//// ADDITIONAL FUNCTIONS
//// The functions below deal exclusivly with editing
//// of questions with question type 'multianswer'.
//// Therefore they are kept in this file.
//// They are not in the class as they are not
//// likely to be subject for overriding.
/////////////////////////////////////////////////////////////
// ANSWER_ALTERNATIVE regexes
define("ANSWER_ALTERNATIVE_FRACTION_REGEX",
@ -783,7 +673,7 @@ define("ANSWER_REGEX",
. '(' . ANSWER_ALTERNATIVE_REGEX
. '(~'
. ANSWER_ALTERNATIVE_REGEX
. ')*)\}' );
. ')*)\}');
// Parenthesis positions for singulars in ANSWER_REGEX
define("ANSWER_REGEX_NORM", 1);
@ -807,12 +697,12 @@ function qtype_multianswer_extract_question($text) {
$question->options->questions = array();
$question->defaultgrade = 0; // Will be increased for each answer norm
for ($positionkey=1; preg_match('/'.ANSWER_REGEX.'/', $question->questiontext['text'], $answerregs); ++$positionkey ) {
for ($positionkey = 1; preg_match('/'.ANSWER_REGEX.'/', $question->questiontext['text'], $answerregs); ++$positionkey) {
$wrapped = new stdClass();
$wrapped->generalfeedback['text'] = '';
$wrapped->generalfeedback['format'] = '1';
$wrapped->generalfeedback['itemid'] = '';
if (isset($answerregs[ANSWER_REGEX_NORM])&& $answerregs[ANSWER_REGEX_NORM]!== ''){
if (isset($answerregs[ANSWER_REGEX_NORM])&& $answerregs[ANSWER_REGEX_NORM]!== '') {
$wrapped->defaultgrade = $answerregs[ANSWER_REGEX_NORM];
} else {
$wrapped->defaultgrade = '1';
@ -824,13 +714,13 @@ function qtype_multianswer_extract_question($text) {
$wrapped->instructions['text'] = '';
$wrapped->instructions['format'] = '1';
$wrapped->instructions['itemid'] = '';
} else if(!empty($answerregs[ANSWER_REGEX_ANSWER_TYPE_SHORTANSWER])) {
} else if (!empty($answerregs[ANSWER_REGEX_ANSWER_TYPE_SHORTANSWER])) {
$wrapped->qtype = 'shortanswer';
$wrapped->usecase = 0;
} else if(!empty($answerregs[ANSWER_REGEX_ANSWER_TYPE_SHORTANSWER_C])) {
} else if (!empty($answerregs[ANSWER_REGEX_ANSWER_TYPE_SHORTANSWER_C])) {
$wrapped->qtype = 'shortanswer';
$wrapped->usecase = 1;
} else if(!empty($answerregs[ANSWER_REGEX_ANSWER_TYPE_MULTICHOICE])) {
} else if (!empty($answerregs[ANSWER_REGEX_ANSWER_TYPE_MULTICHOICE])) {
$wrapped->qtype = 'multichoice';
$wrapped->single = 1;
$wrapped->answernumbering = 0;
@ -844,7 +734,7 @@ function qtype_multianswer_extract_question($text) {
$wrapped->incorrectfeedback['format'] = '1';
$wrapped->incorrectfeedback['itemid'] = '';
$wrapped->layout = 0;
} else if(!empty($answerregs[ANSWER_REGEX_ANSWER_TYPE_MULTICHOICE_REGULAR])) {
} else if (!empty($answerregs[ANSWER_REGEX_ANSWER_TYPE_MULTICHOICE_REGULAR])) {
$wrapped->qtype = 'multichoice';
$wrapped->single = 1;
$wrapped->answernumbering = 0;
@ -858,7 +748,7 @@ function qtype_multianswer_extract_question($text) {
$wrapped->incorrectfeedback['format'] = '1';
$wrapped->incorrectfeedback['itemid'] = '';
$wrapped->layout = 1;
} else if(!empty($answerregs[ANSWER_REGEX_ANSWER_TYPE_MULTICHOICE_HORIZONTAL])) {
} else if (!empty($answerregs[ANSWER_REGEX_ANSWER_TYPE_MULTICHOICE_HORIZONTAL])) {
$wrapped->qtype = 'multichoice';
$wrapped->single = 1;
$wrapped->answernumbering = 0;
@ -885,15 +775,15 @@ function qtype_multianswer_extract_question($text) {
$wrapped->feedback = array();
$wrapped->shuffleanswers = 1;
$wrapped->questiontext['text'] = $answerregs[0];
$wrapped->questiontext['format'] = 0 ;
$wrapped->questiontext['itemid'] = '' ;
$answerindex = 0 ;
$wrapped->questiontext['format'] = 0;
$wrapped->questiontext['itemid'] = '';
$answerindex = 0;
$remainingalts = $answerregs[ANSWER_REGEX_ALTERNATIVES];
while (preg_match('/~?'.ANSWER_ALTERNATIVE_REGEX.'/', $remainingalts, $altregs)) {
if ('=' == $altregs[ANSWER_ALTERNATIVE_REGEX_FRACTION]) {
$wrapped->fraction["$answerindex"] = '1';
} else if ($percentile = $altregs[ANSWER_ALTERNATIVE_REGEX_PERCENTILE_FRACTION]){
} else if ($percentile = $altregs[ANSWER_ALTERNATIVE_REGEX_PERCENTILE_FRACTION]) {
$wrapped->fraction["$answerindex"] = .01 * $percentile;
} else {
$wrapped->fraction["$answerindex"] = '0';
@ -927,17 +817,14 @@ function qtype_multianswer_extract_question($text) {
}
$tmp = explode($altregs[0], $remainingalts, 2);
$remainingalts = $tmp[1];
$answerindex++ ;
$answerindex++;
}
$question->defaultgrade += $wrapped->defaultgrade;
$question->options->questions[$positionkey] = clone($wrapped);
$question->questiontext['text'] = implode("{#$positionkey}",
explode($answerregs[0], $question->questiontext['text'], 2));
// echo"<p>questiontext 2 <pre>";print_r($question->questiontext);echo"<pre></p>";
}
// echo"<p>questiontext<pre>";print_r($question->questiontext);echo"<pre></p>";
$question->questiontext = $question->questiontext;
// echo"<p>question<pre>";print_r($question);echo"<pre></p>";
return $question;
}

View file

@ -55,9 +55,8 @@ class backup_qtype_randomsamatch_plugin extends backup_qtype_plugin {
$pluginwrapper->add_child($randomsamatch);
// set source to populate the data
$randomsamatch->set_source_table('question_randomsamatch', array('question' => backup::VAR_PARENTID));
// don't need to annotate ids nor files
$randomsamatch->set_source_table('question_randomsamatch',
array('question' => backup::VAR_PARENTID));
return $plugin;
}

View file

@ -43,10 +43,9 @@ class restore_qtype_randomsamatch_plugin extends restore_qtype_plugin {
// Add own qtype stuff
$elename = 'randomsamatch';
$elepath = $this->get_pathfor('/randomsamatch'); // we used get_recommended_name() so this works
$elepath = $this->get_pathfor('/randomsamatch');
$paths[] = new restore_path_element($elename, $elepath);
return $paths; // And we return the interesting paths
}
@ -64,7 +63,8 @@ class restore_qtype_randomsamatch_plugin extends restore_qtype_plugin {
$newquestionid = $this->get_new_parentid('question');
$questioncreated = $this->get_mappingid('question_created', $oldquestionid) ? true : false;
// If the question has been created by restore, we need to create its question_randomsamatch too
// If the question has been created by restore, we need to create its
// question_randomsamatch too
if ($questioncreated) {
// Adjust some columns
$data->question = $newquestionid;
@ -72,8 +72,6 @@ class restore_qtype_randomsamatch_plugin extends restore_qtype_plugin {
$newitemid = $DB->insert_record('question_randomsamatch', $data);
// Create mapping
$this->set_mapping('question_randomsamatch', $oldid, $newitemid);
} else {
// Nothing to remap if the question already existed
}
}

View file

@ -33,19 +33,15 @@ defined('MOODLE_INTERNAL') || die();
* @copyright 2007 Jamie Pratt me@jamiep.org
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*/
class question_edit_randomsamatch_form extends question_edit_form {
/**
* Add question-type specific form fields.
*
* @param MoodleQuickForm $mform the form being built.
*/
protected function definition_inner(&$mform) {
class qtype_randomsamatch_edit_form extends question_edit_form {
protected function definition_inner($mform) {
$questionstoselect = array();
for ($i=2; $i<=QUESTION_NUMANS; $i++){
for ($i = 2; $i <= qtype_randomsamatch::MAX_SUBQUESTIONS; $i++) {
$questionstoselect[$i] = $i;
}
$mform->addElement('select', 'choose', get_string("randomsamatchnumber", "quiz"), $questionstoselect);
$mform->addElement('select', 'choose',
get_string('randomsamatchnumber', 'quiz'), $questionstoselect);
$mform->setType('feedback', PARAM_RAW);
$mform->addElement('hidden', 'fraction', 0);
@ -54,11 +50,11 @@ class question_edit_randomsamatch_form extends question_edit_form {
protected function data_preprocessing($question) {
if (empty($question->name)) {
$question->name = get_string("randomsamatch", "quiz");
$question->name = get_string('randomsamatch', 'quiz');
}
if (empty($question->questiontext)) {
$question->questiontext = get_string("randomsamatchintro", "quiz");
$question->questiontext = get_string('randomsamatchintro', 'quiz');
}
return $question;
}
@ -67,22 +63,22 @@ class question_edit_randomsamatch_form extends question_edit_form {
return 'randomsamatch';
}
function validation($data, $files) {
global $QTYPES, $DB;
public function validation($data, $files) {
global $DB;
$errors = parent::validation($data, $files);
if (isset($data->categorymoveto)) {
list($category) = explode(',', $data['categorymoveto']);
} else {
list($category) = explode(',', $data['category']);
}
$saquestions = $QTYPES['randomsamatch']->get_sa_candidates($category);
$saquestions = question_bank::get_qtype('randomsamatch')->get_sa_candidates($category);
$numberavailable = count($saquestions);
if ($saquestions === false){
if ($saquestions === false) {
$a = new stdClass();
$a->catname = $DB->get_field('question_categories', 'name', array('id' => $category));
$errors['choose'] = get_string('nosaincategory', 'qtype_randomsamatch', $a);
} elseif ($numberavailable < $data['choose']){
} else if ($numberavailable < $data['choose']) {
$a = new stdClass();
$a->catname = $DB->get_field('question_categories', 'name', array('id' => $category));
$a->nosaquestions = $numberavailable;

View file

@ -36,27 +36,21 @@ defined('MOODLE_INTERNAL') || die();
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class question_randomsamatch_qtype extends qtype_match {
/// Extends 'match' as there are quite a few simularities...
class qtype_randomsamatch extends question_type {
const MAX_SUBQUESTIONS = 10;
function name() {
return 'randomsamatch';
public function requires_qtypes() {
return array('shortanswer', 'match');
}
function requires_qtypes() {
return array('shortanswer');
}
function is_usable_by_random() {
public function is_usable_by_random() {
return false;
}
function get_question_options(&$question) {
global $DB, $OUTPUT;
if (!$question->options = $DB->get_record('question_randomsamatch', array('question' => $question->id))) {
echo $OUTPUT->notification('Error: Missing question options for random short answer question '.$question->id.'!');
return false;
}
public function get_question_options($question) {
global $DB;
$question->options = $DB->get_record('question_randomsamatch',
array('question' => $question->id), '*', MUST_EXIST);
// This could be included as a flag in the database. It's already
// supported by the code.
@ -66,7 +60,7 @@ class question_randomsamatch_qtype extends qtype_match {
}
function save_question_options($question) {
public function save_question_options($question) {
global $DB;
$options->question = $question->id;
$options->choose = $question->choose;
@ -76,23 +70,24 @@ class question_randomsamatch_qtype extends qtype_match {
return $result;
}
if ($existing = $DB->get_record("question_randomsamatch", array("question" => $options->question))) {
if ($existing = $DB->get_record('question_randomsamatch',
array('question' => $options->question))) {
$options->id = $existing->id;
$DB->update_record("question_randomsamatch", $options);
$DB->update_record('question_randomsamatch', $options);
} else {
$DB->insert_record("question_randomsamatch", $options);
$DB->insert_record('question_randomsamatch', $options);
}
return true;
}
function delete_question($questionid, $contextid) {
public function delete_question($questionid, $contextid) {
global $DB;
$DB->delete_records('question_randomsamatch', array('question' => $questionid));
parent::delete_question($questionid, $contextid);
}
function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) {
public function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) {
// Choose a random shortanswer question from the category:
// We need to make sure that no question is used more than once in the
// quiz. Therfore the following need to be excluded:
@ -190,7 +185,7 @@ class question_randomsamatch_qtype extends qtype_match {
foreach ($responses as $response) {
$wqid = $response[0];
$state->responses[$wqid] = $response[1];
if (!isset($wrappedquestions[$wqid])){
if (!isset($wrappedquestions[$wqid])) {
if (!$wrappedquestions[$wqid] = $DB->get_record('question', array('id' => $wqid))) {
echo $OUTPUT->notification("Couldn't get question (id=$wqid)!");
return false;
@ -231,23 +226,11 @@ class question_randomsamatch_qtype extends qtype_match {
return true;
}
function extract_response($rawresponse, $nameprefix) {
/// Simple implementation that does not check with the database
/// and thus - does not bother to check whether there has been
/// any changes to the question options.
$response = array();
$rawitems = explode(',', $rawresponse->answer);
foreach ($rawitems as $rawitem) {
$splits = explode('-', $rawitem, 2);
$response[$nameprefix.$splits[0]] = $splits[1];
}
return $response;
}
function get_sa_candidates($categorylist, $questionsinuse = 0) {
public function get_sa_candidates($categorylist, $questionsinuse = 0) {
global $DB;
list ($usql, $params) = $DB->get_in_or_equal($categorylist);
list ($ques_usql, $ques_params) = $DB->get_in_or_equal(explode(',', $questionsinuse), SQL_PARAMS_QM, null, false);
list ($ques_usql, $ques_params) = $DB->get_in_or_equal(explode(',', $questionsinuse),
SQL_PARAMS_QM, null, false);
$params = array_merge($params, $ques_params);
return $DB->get_records_select('question',
"qtype = 'shortanswer' " .
@ -256,80 +239,6 @@ class question_randomsamatch_qtype extends qtype_match {
"AND hidden = '0'" .
"AND id $ques_usql", $params);
}
function get_all_responses($question, $state) {
$answers = array();
if (is_array($question->options->subquestions)) {
foreach ($question->options->subquestions as $aid => $answer) {
if ($answer->questiontext) {
foreach($answer->options->answers as $ans ){
$answer->answertext = $ans->answer ;
}
$r = new stdClass();
$r->answer = $answer->questiontext . ": " . $answer->answertext;
$r->credit = 1;
$answers[$aid] = $r;
}
}
}
$result = new stdClass();
$result->id = $question->id;
$result->responses = $answers;
return $result;
}
/**
* The difference between this method an get_all_responses is that this
* method is not passed a state object. It is the possible answers to a
* question no matter what the state.
* This method is not called for random questions.
* @return array of possible answers.
*/
function get_possible_responses(&$question) {
global $QTYPES;
static $answers = array();
if (!isset($answers[$question->id])){
if ($question->options->subcats) {
// recurse into subcategories
$categorylist = question_categorylist($question->category);
} else {
$categorylist = array($question->category);
}
$question->options->subquestions = $this->get_sa_candidates($categorylist);
foreach ($question->options->subquestions as $key => $wrappedquestion) {
if (!$QTYPES[$wrappedquestion->qtype]
->get_question_options($wrappedquestion)) {
return false;
}
// Now we overwrite the $question->options->answers field to only
// *one* (the first) correct answer. This loop can be deleted to
// take all answers into account (i.e. put them all into the
// drop-down menu.
$foundcorrect = false;
foreach ($wrappedquestion->options->answers as $answer) {
if ($foundcorrect || $answer->fraction != 1.0) {
unset($wrappedquestion->options->answers[$answer->id]);
} else if (!$foundcorrect) {
$foundcorrect = true;
}
}
}
$answers[$question->id] = array();
if (is_array($question->options->subquestions)) {
foreach ($question->options->subquestions as $subqid => $answer) {
if ($answer->questiontext) {
$ans = array_shift($answer->options->answers);
$answer->answertext = $ans->answer ;
$r = new stdClass();
$r->answer = $answer->questiontext . ": " . $answer->answertext;
$r->credit = 1;
$answers[$question->id][$subqid] = array($ans->id => $r);
}
}
}
}
return $answers[$question->id];
}
/**
* @param object $question
@ -337,7 +246,7 @@ class question_randomsamatch_qtype extends qtype_match {
* guess by a student might give or an empty string which means will not
* calculate.
*/
function get_random_guess_score($question) {
public function get_random_guess_score($question) {
return 1/$question->options->choose;
}
}