Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/question/type/multianswer/edit_multianswer_form.php
Go to the documentation of this file.
00001 <?php
00002 // This file is part of Moodle - http://moodle.org/
00003 //
00004 // Moodle is free software: you can redistribute it and/or modify
00005 // it under the terms of the GNU General Public License as published by
00006 // the Free Software Foundation, either version 3 of the License, or
00007 // (at your option) any later version.
00008 //
00009 // Moodle is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
00016 
00027 defined('MOODLE_INTERNAL') || die();
00028 
00029 
00036 class qtype_multianswer_edit_form extends question_edit_form {
00037 
00038     //  $questiondisplay will contain the qtype_multianswer_extract_question from
00039     // the questiontext
00040     public $questiondisplay;
00041     //  $savedquestiondisplay will contain the qtype_multianswer_extract_question
00042     // from the questiontext in database
00043     public $savedquestion;
00044     public $savedquestiondisplay;
00045     public $used_in_quiz = false;
00046     public $qtype_change = false;
00047     public $negative_diff = 0;
00048     public $nb_of_quiz = 0;
00049     public $nb_of_attempts = 0;
00050     public $confirm = 0;
00051     public $reload = false;
00052 
00053     public function __construct($submiturl, $question, $category, $contexts, $formeditable = true) {
00054         global $SESSION, $CFG, $DB;
00055         $this->regenerate = true;
00056         $this->reload = optional_param('reload', false, PARAM_BOOL);
00057 
00058         $this->used_in_quiz = false;
00059 
00060         if (isset($question->id) && $question->id != 0) {
00061             $this->savedquestiondisplay = fullclone($question);
00062             if ($list = $DB->get_records('quiz_question_instances',
00063                     array('question' => $question->id))) {
00064                 foreach ($list as $key => $li) {
00065                     $this->nb_of_quiz ++;
00066                     if ($att = $DB->get_records('quiz_attempts',
00067                             array('quiz' => $li->quiz, 'preview' => '0'))) {
00068                         $this->nb_of_attempts += count($att);
00069                         $this->used_in_quiz = true;
00070                     }
00071                 }
00072             }
00073         }
00074 
00075         parent::__construct($submiturl, $question, $category, $contexts, $formeditable);
00076     }
00077 
00078     protected function definition_inner($mform) {
00079         $mform->addElement('hidden', 'reload', 1);
00080         $mform->setType('reload', PARAM_INT);
00081 
00082         // Remove meaningless defaultmark field.
00083         $mform->removeElement('defaultmark');
00084         $this->confirm = optional_param('confirm', false, PARAM_BOOL);
00085 
00086         // Make questiontext a required field for this question type.
00087         $mform->addRule('questiontext', null, 'required', null, 'client');
00088 
00089         // display the questions from questiontext;
00090         if ($questiontext = optional_param_array('questiontext', false, PARAM_RAW)) {
00091             $this->questiondisplay = fullclone(qtype_multianswer_extract_question($questiontext));
00092 
00093         } else {
00094             if (!$this->reload && !empty($this->savedquestiondisplay->id)) {
00095                 // use database data as this is first pass
00096                 // question->id == 0 so no stored datasets
00097                 $this->questiondisplay = fullclone($this->savedquestiondisplay);
00098                 foreach ($this->questiondisplay->options->questions as $subquestion) {
00099                     if (!empty($subquestion)) {
00100                         $subquestion->answer = array('');
00101                         foreach ($subquestion->options->answers as $ans) {
00102                             $subquestion->answer[] = $ans->answer;
00103                         }
00104                     }
00105                 }
00106             } else {
00107                 $this->questiondisplay = "";
00108             }
00109         }
00110 
00111         if (isset($this->savedquestiondisplay->options->questions) &&
00112                 is_array($this->savedquestiondisplay->options->questions)) {
00113             $countsavedsubquestions = 0;
00114             foreach ($this->savedquestiondisplay->options->questions as $subquestion) {
00115                 if (!empty($subquestion)) {
00116                     $countsavedsubquestions++;
00117                 }
00118             }
00119         } else {
00120             $countsavedsubquestions = 0;
00121         }
00122         if ($this->reload) {
00123             if (isset($this->questiondisplay->options->questions) &&
00124                     is_array($this->questiondisplay->options->questions)) {
00125                 $countsubquestions = 0;
00126                 foreach ($this->questiondisplay->options->questions as $subquestion) {
00127                     if (!empty($subquestion)) {
00128                         $countsubquestions++;
00129                     }
00130                 }
00131             } else {
00132                 $countsubquestions = 0;
00133             }
00134         } else {
00135             $countsubquestions = $countsavedsubquestions;
00136         }
00137 
00138         $mform->addElement('submit', 'analyzequestion',
00139                 get_string('decodeverifyquestiontext', 'qtype_multianswer'));
00140         $mform->registerNoSubmitButton('analyzequestion');
00141         if ($this->reload) {
00142             for ($sub = 1; $sub <= $countsubquestions; $sub++) {
00143 
00144                 if (isset($this->questiondisplay->options->questions[$sub]->qtype)) {
00145                     $this->editas[$sub] = $this->questiondisplay->options->questions[$sub]->qtype;
00146                 } else {
00147                     $this->editas[$sub] = optional_param('sub_'.$sub.'_qtype', 'unknown type', PARAM_PLUGIN);
00148                 }
00149 
00150                 $storemess = '';
00151                 if (isset($this->savedquestiondisplay->options->questions[$sub]->qtype) &&
00152                         $this->savedquestiondisplay->options->questions[$sub]->qtype !=
00153                                 $this->questiondisplay->options->questions[$sub]->qtype) {
00154                     $this->qtype_change = true;
00155                     $storemess = ' ' . html_writer::tag('span', get_string(
00156                             'storedqtype', 'qtype_multianswer', question_bank::get_qtype_name(
00157                                     $this->savedquestiondisplay->options->questions[$sub]->qtype)),
00158                             array('class' => 'error'));
00159                 }
00160 
00161                 $mform->addElement('header', 'subhdr'.$sub, get_string('questionno', 'question',
00162                        '{#'.$sub.'}').'&nbsp;'.question_bank::get_qtype_name(
00163                         $this->questiondisplay->options->questions[$sub]->qtype).$storemess);
00164 
00165                 $mform->addElement('static', 'sub_'.$sub.'_questiontext',
00166                         get_string('questiondefinition', 'qtype_multianswer'));
00167 
00168                 if (isset ($this->questiondisplay->options->questions[$sub]->questiontext)) {
00169                     $mform->setDefault('sub_'.$sub.'_questiontext',
00170                             $this->questiondisplay->options->questions[$sub]->questiontext['text']);
00171                 }
00172 
00173                 $mform->addElement('static', 'sub_'.$sub.'_defaultmark',
00174                         get_string('defaultmark', 'question'));
00175                 $mform->setDefault('sub_'.$sub.'_defaultmark',
00176                         $this->questiondisplay->options->questions[$sub]->defaultmark);
00177 
00178                 if ($this->questiondisplay->options->questions[$sub]->qtype == 'shortanswer') {
00179                     $mform->addElement('static', 'sub_'.$sub.'_usecase',
00180                             get_string('casesensitive', 'qtype_shortanswer'));
00181                 }
00182 
00183                 if ($this->questiondisplay->options->questions[$sub]->qtype == 'multichoice') {
00184                     $mform->addElement('static', 'sub_'.$sub.'_layout',
00185                             get_string('layout', 'qtype_multianswer'));
00186                 }
00187 
00188                 foreach ($this->questiondisplay->options->questions[$sub]->answer as $key => $ans) {
00189                     $mform->addElement('static', 'sub_'.$sub.'_answer['.$key.']',
00190                             get_string('answer', 'question'));
00191 
00192                     if ($this->questiondisplay->options->questions[$sub]->qtype == 'numerical' &&
00193                             $key == 0) {
00194                         $mform->addElement('static', 'sub_'.$sub.'_tolerance['.$key.']',
00195                                 get_string('acceptederror', 'qtype_numerical'));
00196                     }
00197 
00198                     $mform->addElement('static', 'sub_'.$sub.'_fraction['.$key.']',
00199                             get_string('grade'));
00200 
00201                     $mform->addElement('static', 'sub_'.$sub.'_feedback['.$key.']',
00202                             get_string('feedback', 'question'));
00203                 }
00204             }
00205 
00206             $this->negative_diff = $countsavedsubquestions - $countsubquestions;
00207             if (($this->negative_diff > 0) ||$this->qtype_change ||
00208                     ($this->used_in_quiz && $this->negative_diff != 0)) {
00209                 $mform->addElement('header', 'additemhdr',
00210                         get_string('warningquestionmodified', 'qtype_multianswer'));
00211             }
00212             if ($this->negative_diff > 0) {
00213                 $mform->addElement('static', 'alert1', "<strong>".
00214                         get_string('questiondeleted', 'qtype_multianswer')."</strong>",
00215                         get_string('questionsless', 'qtype_multianswer', $this->negative_diff));
00216             }
00217             if ($this->qtype_change) {
00218                 $mform->addElement('static', 'alert1', "<strong>".
00219                         get_string('questiontypechanged', 'qtype_multianswer')."</strong>",
00220                         get_string('questiontypechangedcomment', 'qtype_multianswer'));
00221             }
00222         }
00223         if ($this->used_in_quiz) {
00224             if ($this->negative_diff < 0) {
00225                 $diff = $countsubquestions - $countsavedsubquestions;
00226                 $mform->addElement('static', 'alert1', "<strong>".
00227                         get_string('questionsadded', 'qtype_multianswer')."</strong>",
00228                         "<strong>".get_string('questionsmore', 'qtype_multianswer', $diff).
00229                         "</strong>");
00230             }
00231             $a = new stdClass();
00232             $a->nb_of_quiz = $this->nb_of_quiz;
00233             $a->nb_of_attempts = $this->nb_of_attempts;
00234             $mform->addElement('header', 'additemhdr2',
00235                     get_string('questionusedinquiz', 'qtype_multianswer', $a));
00236             $mform->addElement('static', 'alertas',
00237                     get_string('youshouldnot', 'qtype_multianswer'));
00238         }
00239         if (($this->negative_diff > 0 || $this->used_in_quiz &&
00240                 ($this->negative_diff > 0 || $this->negative_diff < 0 || $this->qtype_change)) &&
00241                         $this->reload) {
00242             $mform->addElement('header', 'additemhdr',
00243                     get_string('questionsaveasedited', 'qtype_multianswer'));
00244             $mform->addElement('checkbox', 'confirm', '',
00245                     get_string('confirmquestionsaveasedited', 'qtype_multianswer'));
00246             $mform->setDefault('confirm', 0);
00247         } else {
00248             $mform->addElement('hidden', 'confirm', 0);
00249         }
00250 
00251         $this->add_interactive_settings();
00252     }
00253 
00254 
00255     public function set_data($question) {
00256         global $DB;
00257         $default_values = array();
00258         if (isset($question->id) and $question->id and $question->qtype &&
00259                 $question->questiontext) {
00260 
00261             foreach ($question->options->questions as $key => $wrapped) {
00262                 if (!empty($wrapped)) {
00263                     // The old way of restoring the definitions is kept to gradually
00264                     // update all multianswer questions
00265                     if (empty($wrapped->questiontext)) {
00266                         $parsableanswerdef = '{' . $wrapped->defaultmark . ':';
00267                         switch ($wrapped->qtype) {
00268                             case 'multichoice':
00269                                 $parsableanswerdef .= 'MULTICHOICE:';
00270                                 break;
00271                             case 'shortanswer':
00272                                 $parsableanswerdef .= 'SHORTANSWER:';
00273                                 break;
00274                             case 'numerical':
00275                                 $parsableanswerdef .= 'NUMERICAL:';
00276                                 break;
00277                             default:
00278                                 print_error('unknownquestiontype', 'question', '',
00279                                         $wrapped->qtype);
00280                         }
00281                         $separator = '';
00282                         foreach ($wrapped->options->answers as $subanswer) {
00283                             $parsableanswerdef .= $separator
00284                                 . '%' . round(100*$subanswer->fraction) . '%';
00285                             if (is_array($subanswer->answer)) {
00286                                 $parsableanswerdef .= $subanswer->answer['text'];
00287                             } else {
00288                                 $parsableanswerdef .= $subanswer->answer;
00289                             }
00290                             if (!empty($wrapped->options->tolerance)) {
00291                                 // Special for numerical answers:
00292                                 $parsableanswerdef .= ":{$wrapped->options->tolerance}";
00293                                 // We only want tolerance for the first alternative, it will
00294                                 // be applied to all of the alternatives.
00295                                 unset($wrapped->options->tolerance);
00296                             }
00297                             if ($subanswer->feedback) {
00298                                 $parsableanswerdef .= "#$subanswer->feedback";
00299                             }
00300                             $separator = '~';
00301                         }
00302                         $parsableanswerdef .= '}';
00303                         // Fix the questiontext fields of old questions
00304                         $DB->set_field('question', 'questiontext', $parsableanswerdef,
00305                                 array('id' => $wrapped->id));
00306                     } else {
00307                         $parsableanswerdef = str_replace('&#', '&\#', $wrapped->questiontext);
00308                     }
00309                     $question->questiontext = str_replace("{#$key}", $parsableanswerdef,
00310                             $question->questiontext);
00311                 }
00312             }
00313         }
00314 
00315         // set default to $questiondisplay questions elements
00316         if ($this->reload) {
00317             if (isset($this->questiondisplay->options->questions)) {
00318                 $subquestions = fullclone($this->questiondisplay->options->questions);
00319                 if (count($subquestions)) {
00320                     $sub = 1;
00321                     foreach ($subquestions as $subquestion) {
00322                         $prefix = 'sub_'.$sub.'_';
00323 
00324                         // validate parameters
00325                         $answercount = 0;
00326                         $maxgrade = false;
00327                         $maxfraction = -1;
00328                         if ($subquestion->qtype == 'shortanswer') {
00329                             switch ($subquestion->usecase) {
00330                                 case '1':
00331                                     $default_values[$prefix.'usecase'] =
00332                                             get_string('caseyes', 'qtype_shortanswer');
00333                                     break;
00334                                 case '0':
00335                                 default :
00336                                     $default_values[$prefix.'usecase'] =
00337                                             get_string('caseno', 'qtype_shortanswer');
00338                             }
00339                         }
00340 
00341                         if ($subquestion->qtype == 'multichoice') {
00342                             $default_values[$prefix.'layout'] = $subquestion->layout;
00343                             switch ($subquestion->layout) {
00344                                 case '0':
00345                                     $default_values[$prefix.'layout'] =
00346                                             get_string('layoutselectinline', 'qtype_multianswer');
00347                                     break;
00348                                 case '1':
00349                                     $default_values[$prefix.'layout'] =
00350                                             get_string('layoutvertical', 'qtype_multianswer');
00351                                     break;
00352                                 case '2':
00353                                     $default_values[$prefix.'layout'] =
00354                                             get_string('layouthorizontal', 'qtype_multianswer');
00355                                     break;
00356                                 default:
00357                                     $default_values[$prefix.'layout'] =
00358                                             get_string('layoutundefined', 'qtype_multianswer');
00359                             }
00360                         }
00361                         foreach ($subquestion->answer as $key => $answer) {
00362                             if ($subquestion->qtype == 'numerical' && $key == 0) {
00363                                 $default_values[$prefix.'tolerance['.$key.']'] =
00364                                         $subquestion->tolerance[0];
00365                             }
00366                             if (is_array($answer)) {
00367                                 $answer = $answer['text'];
00368                             }
00369                             $trimmedanswer = trim($answer);
00370                             if ($trimmedanswer !== '') {
00371                                 $answercount++;
00372                                 if ($subquestion->qtype == 'numerical' &&
00373                                         !(is_numeric($trimmedanswer) || $trimmedanswer == '*')) {
00374                                     $this->_form->setElementError($prefix.'answer['.$key.']',
00375                                             get_string('answermustbenumberorstar',
00376                                                     'qtype_numerical'));
00377                                 }
00378                                 if ($subquestion->fraction[$key] == 1) {
00379                                     $maxgrade = true;
00380                                 }
00381                                 if ($subquestion->fraction[$key] > $maxfraction) {
00382                                     $maxfraction = $subquestion->fraction[$key];
00383                                 }
00384                             }
00385 
00386                             $default_values[$prefix.'answer['.$key.']'] =
00387                                     htmlspecialchars($answer);
00388                         }
00389                         if ($answercount == 0) {
00390                             if ($subquestion->qtype == 'multichoice') {
00391                                 $this->_form->setElementError($prefix.'answer[0]',
00392                                         get_string('notenoughanswers', 'qtype_multichoice', 2));
00393                             } else {
00394                                 $this->_form->setElementError($prefix.'answer[0]',
00395                                         get_string('notenoughanswers', 'question', 1));
00396                             }
00397                         }
00398                         if ($maxgrade == false) {
00399                             $this->_form->setElementError($prefix.'fraction[0]',
00400                                     get_string('fractionsnomax', 'question'));
00401                         }
00402                         foreach ($subquestion->feedback as $key => $answer) {
00403 
00404                             $default_values[$prefix.'feedback['.$key.']'] =
00405                                     htmlspecialchars ($answer['text']);
00406                         }
00407                         foreach ($subquestion->fraction as $key => $answer) {
00408                             $default_values[$prefix.'fraction['.$key.']'] = $answer;
00409                         }
00410 
00411                         $sub++;
00412                     }
00413                 }
00414             }
00415         }
00416         $default_values['alertas']= "<strong>".get_string('questioninquiz', 'qtype_multianswer').
00417                 "</strong>";
00418 
00419         if ($default_values != "") {
00420             $question = (object)((array)$question + $default_values);
00421         }
00422         $question = $this->data_preprocessing_hints($question);
00423         parent::set_data($question);
00424     }
00425 
00426     public function validation($data, $files) {
00427         $errors = parent::validation($data, $files);
00428 
00429         $questiondisplay = qtype_multianswer_extract_question($data['questiontext']);
00430 
00431         if (isset($questiondisplay->options->questions)) {
00432             $subquestions = fullclone($questiondisplay->options->questions);
00433             if (count($subquestions)) {
00434                 $sub = 1;
00435                 foreach ($subquestions as $subquestion) {
00436                     $prefix = 'sub_'.$sub.'_';
00437                     $answercount = 0;
00438                     $maxgrade = false;
00439                     $maxfraction = -1;
00440                     if (isset($this->savedquestiondisplay->options->questions[$sub]->qtype) &&
00441                             $this->savedquestiondisplay->options->questions[$sub]->qtype !=
00442                                     $questiondisplay->options->questions[$sub]->qtype) {
00443                         $storemess = " STORED QTYPE ".question_bank::get_qtype_name(
00444                                 $this->savedquestiondisplay->options->questions[$sub]->qtype);
00445                     }
00446                     foreach ($subquestion->answer as $key => $answer) {
00447                         if (is_array($answer)) {
00448                             $answer = $answer['text'];
00449                         }
00450                         $trimmedanswer = trim($answer);
00451                         if ($trimmedanswer !== '') {
00452                             $answercount++;
00453                             if ($subquestion->qtype == 'numerical' &&
00454                                     !(is_numeric($trimmedanswer) || $trimmedanswer == '*')) {
00455                                 $errors[$prefix.'answer['.$key.']'] =
00456                                         get_string('answermustbenumberorstar', 'qtype_numerical');
00457                             }
00458                             if ($subquestion->fraction[$key] == 1) {
00459                                 $maxgrade = true;
00460                             }
00461                             if ($subquestion->fraction[$key] > $maxfraction) {
00462                                 $maxfraction = $subquestion->fraction[$key];
00463                             }
00464                         }
00465                     }
00466                     if ($answercount == 0) {
00467                         if ($subquestion->qtype == 'multichoice') {
00468                             $errors[$prefix.'answer[0]'] =
00469                                     get_string('notenoughanswers', 'qtype_multichoice', 2);
00470                         } else {
00471                             $errors[$prefix.'answer[0]'] =
00472                                     get_string('notenoughanswers', 'question', 1);
00473                         }
00474                     }
00475                     if ($maxgrade == false) {
00476                         $errors[$prefix.'fraction[0]'] =
00477                                 get_string('fractionsnomax', 'question');
00478                     }
00479                     $sub++;
00480                 }
00481             } else {
00482                 $errors['questiontext'] = get_string('questionsmissing', 'qtype_multianswer');
00483             }
00484         }
00485 
00486         if (($this->negative_diff > 0 || $this->used_in_quiz &&
00487                 ($this->negative_diff > 0 || $this->negative_diff < 0 ||
00488                         $this->qtype_change)) && !$this->confirm) {
00489             $errors['confirm'] =
00490                     get_string('confirmsave', 'qtype_multianswer', $this->negative_diff);
00491         }
00492 
00493         return $errors;
00494     }
00495 
00496     public function qtype() {
00497         return 'multianswer';
00498     }
00499 }
 All Data Structures Namespaces Files Functions Variables Enumerations