47a0a6b80bba51c8faf355a3094a9d2e6482cca6
[moodle.git] / question / type / calculated / datasetitems_form.php
1 <?php
2 class question_dataset_dependent_items_form extends moodleform {
3     /**
4      * Question object with options and answers already loaded by get_question_options
5      * Be careful how you use this it is needed sometimes to set up the structure of the
6      * form in definition_inner but data is always loaded into the form with set_defaults.
7      *
8      * @var object
9      */
10     public $question;
11     /**
12      * Reference to question type object
13      *
14      * @var question_dataset_dependent_questiontype
15      */
16     public $qtypeobj;
18     public $datasetdefs;
20     public $maxnumber = -1;
22     public $regenerate;
24     public $noofitems;
25     
26     public $outsidelimit = false ;
27     
28     public $commentanswers = array();
29     /**
30      * Add question-type specific form fields.
31      *
32      * @param MoodleQuickForm $mform the form being built.
33      */
34     function question_dataset_dependent_items_form($submiturl, $question, $regenerate){
35         global $QTYPES, $SESSION, $CFG, $DB;
36         $this->regenerate = $regenerate;
37         $this->question = $question;
38         $this->qtypeobj =& $QTYPES[$this->question->qtype];
39                                 // Validate the question category.
40                                 if (!$category = $DB->get_record('question_categories', array('id' => $question->category))) {
41                                     print_error('categorydoesnotexist', 'question', $returnurl);
42                                 }
43         $this->category = $category;
44         $this->categorycontext = get_context_instance_by_id($category->contextid);
45         //get the dataset defintions for this question
46         if (empty($question->id)) {
47             $this->datasetdefs = $this->qtypeobj->get_dataset_definitions($question->id, $SESSION->calculated->definitionform->dataset);
48         } else {
49             if (empty($question->options)) {
50                 $this->get_question_options($question);
51             }
52             $this->datasetdefs = $this->qtypeobj->get_dataset_definitions($question->id, array());
53         }
55         foreach ($this->datasetdefs as $datasetdef) {
57             // Get maxnumber
58             if ($this->maxnumber == -1 || $datasetdef->itemcount < $this->maxnumber) {
59                 $this->maxnumber = $datasetdef->itemcount;
60             }
61         }
62         foreach ($this->datasetdefs as $defid => $datasetdef) {
63             if (isset($datasetdef->id)) {
64                 $this->datasetdefs[$defid]->items = $this->qtypeobj->get_database_dataset_items($datasetdef->id);
65             }
66         }
67         parent::moodleform($submiturl);
68     }
69     function definition() {
70         $mform =& $this->_form;
71         $strquestionlabel = $this->qtypeobj->comment_header($this->question);
72         if ($this->maxnumber != -1){
73             $this->noofitems = $this->maxnumber;
74         } else {
75             $this->noofitems = 0;
76         }
77 //------------------------------------------------------------------------------------------------------------------------------
78         $mform->addElement('submit', 'updatedatasets', get_string('updatedatasetparam', 'qtype_datasetdependent'));
79         $mform->registerNoSubmitButton('updatedatasets');
80         $mform->addElement('header', 'additemhdr', get_string('itemtoadd', 'qtype_datasetdependent'));
81         $idx = 1;
82         $j = (($this->noofitems) * count($this->datasetdefs))+1;
83         foreach ($this->datasetdefs as $defkey => $datasetdef){
84             $mform->addElement('text', "number[$j]", get_string('param', 'qtype_datasetdependent', $datasetdef->name));
85             $mform->setType("number[$j]", PARAM_NUMBER);
86             $this->qtypeobj->custom_generator_tools_part($mform, $idx, $j);
87             $idx++;
88             $mform->addElement('hidden', "definition[$j]");
89             $mform->addElement('hidden', "itemid[$j]");
90             $mform->addElement('static', "divider[$j]", '', '<hr />');
91             $j++;
92         }
93         $mform->addElement('header', 'updateanswershdr', get_string('answerstoleranceparam', 'qtype_datasetdependent'));
94         $mform->addElement('submit', 'updateanswers', get_string('updatetolerancesparam', 'qtype_datasetdependent'));
95         $mform->setAdvanced('updateanswers',true);
96         $mform->registerNoSubmitButton('updateanswers');
97  
98         $answers = fullclone($this->question->options->answers);
99         $key1 =1;
100         foreach ($answers as $key => $answer) {
101             if ('' === $answer->answer){
102             }else if ('*' === $answer->answer){
103                 $mform->addElement('static', 'answercomment['.($this->noofitems+$key1).']', $answer->answer);
104                 $mform->addElement('hidden', 'tolerance['.$key.']', '');
105                 $mform->setAdvanced('tolerance['.$key.']',true);
106                 $mform->addElement('hidden', 'tolerancetype['.$key.']', '');
107                 $mform->setAdvanced('tolerancetype['.$key.']',true);
108                 $mform->addElement('hidden', 'correctanswerlength['.$key.']', '');
109                 $mform->setAdvanced('correctanswerlength['.$key.']',true);
110                 $mform->addElement('hidden', 'correctanswerformat['.$key.']', '');
111                 $mform->setAdvanced('correctanswerformat['.$key.']',true);
112             }else {
113                 $mform->addElement('static', 'answercomment['.($this->noofitems+$key1).']', $answer->answer);
114                 $mform->addElement('text', 'tolerance['.$key.']', get_string('tolerance', 'qtype_calculated'));
115                 $mform->setAdvanced('tolerance['.$key.']',true);
116                 $mform->addElement('select', 'tolerancetype['.$key.']', get_string('tolerancetype', 'quiz'), $this->qtypeobj->tolerance_types());
117                 $mform->setAdvanced('tolerancetype['.$key.']',true);
118         
119                 $mform->addElement('select', 'correctanswerlength['.$key.']', get_string('correctanswershows', 'qtype_calculated'), range(0, 9));
120                 $mform->setAdvanced('correctanswerlength['.$key.']',true);
121         
122                 $answerlengthformats = array('1' => get_string('decimalformat', 'quiz'), '2' => get_string('significantfiguresformat', 'quiz'));
123                 $mform->addElement('select', 'correctanswerformat['.$key.']', get_string('correctanswershowsformat', 'qtype_calculated'), $answerlengthformats);
124                 $mform->setAdvanced('correctanswerformat['.$key.']',true);
125                 $mform->addElement('static', 'dividertolerance', '', '<hr />');
126                 $mform->setAdvanced('dividertolerance',true);
127             }
128             $key1++;
129         }    
131         $addremoveoptions = array();
132         $addremoveoptions['1']='1';
133         for ($i=10; $i<=100 ; $i+=10){
134              $addremoveoptions["$i"]="$i";
135         }
136         $mform->addElement('header', 'additemhdr', get_string('add', 'moodle'));
137         $mform->closeHeaderBefore('additemhdr');
139         if ($this->qtypeobj->supports_dataset_item_generation()){
140             $radiogrp = array();
141             $radiogrp[] =& $mform->createElement('radio', 'nextpageparam[forceregeneration]', null, get_string('reuseifpossible', 'qtype_datasetdependent'), 0);
142             $radiogrp[] =& $mform->createElement('radio', 'nextpageparam[forceregeneration]', null, get_string('forceregeneration', 'qtype_datasetdependent'), 1);
143             $mform->addGroup($radiogrp, 'forceregenerationgrp', get_string('nextitemtoadd', 'qtype_calculated'), "<br/>", false);
144         }
146         $mform->addElement('submit', 'getnextbutton', get_string('getnextnow', 'qtype_datasetdependent'));
147         $mform->addElement('static', "dividera", '', '<hr />');
148         $addgrp = array();
149         $addgrp[] =& $mform->createElement('submit', 'addbutton', get_string('add', 'moodle'));
150         $addgrp[] =& $mform->createElement('select', "selectadd", get_string('additem', 'qtype_datasetdependent'), $addremoveoptions);
151         $addgrp[] = & $mform->createElement('static',"stat","Items",get_string('item(s)', 'qtype_datasetdependent'));
152         $mform->addGroup($addgrp, 'addgrp', '', '   ', false);
153         $mform->addElement('static', "divideradd", '', '');
154     //     $mform->closeHeaderBefore('divideradd');
155         if ($this->noofitems > 0) {
156             $mform->addElement('header', 'additemhdr', get_string('delete', 'moodle'));
157             $deletegrp = array();
158             $deletegrp[] =& $mform->createElement('submit', 'deletebutton', get_string('delete', 'moodle'));
159             $deletegrp[] =& $mform->createElement('select', "selectdelete", get_string('deleteitem', 'qtype_datasetdependent')."1", $addremoveoptions);
160             $deletegrp[] = & $mform->createElement('static',"stat","Items",get_string('lastitem(s)', 'qtype_datasetdependent'));
161             $mform->addGroup($deletegrp, 'deletegrp', '', '   ', false);
162    //      $mform->addElement('static', "dividerdelete", '', '<hr />');
163    //      $mform->closeHeaderBefore('dividerdelete');
164         } else {
165             $mform->addElement('static','warning','','<span class="error">'.get_string('youmustaddatleastoneitem', 'qtype_datasetdependent').'</span>');
166         }
168 //------------------------------------------------------------------------------------------------------------------------------
169         $j = $this->noofitems * count($this->datasetdefs);
170         for ($i = $this->noofitems; $i >= 1 ; $i--){
171             $mform->addElement('header', '', get_string('itemno', 'qtype_datasetdependent', $i));
172             foreach ($this->datasetdefs as $defkey => $datasetdef){
173                 $mform->addElement('text', "number[$j]", get_string('param', 'qtype_datasetdependent', $datasetdef->name));
174                 $mform->setType("number[$j]", PARAM_NUMBER);
175                 $mform->addElement('hidden', "itemid[$j]");
176                 $mform->setType("itemid[$j]", PARAM_INT);
178                 $mform->addElement('hidden', "definition[$j]");
179                 $mform->setType("definition[$j]", PARAM_NOTAGS);
181                 $j--;
182             }
183             if ('' != $strquestionlabel){
184                 $repeated[] =& $mform->addElement('static', "answercomment[$i]", $strquestionlabel);
185             }
186         }
187       //  if ($this->outsidelimit){
188             $mform->addElement('static','outsidelimit','','');
189       //  }
190 //------------------------------------------------------------------------------------------------------------------------------
191         //non standard name for button element needed so not using add_action_buttons
192         if ( !($this->noofitems==0) ){
193         $mform->addElement('submit', 'backtoquiz', get_string('savechanges'));
194         $mform->closeHeaderBefore('backtoquiz');
195         }
196         //hidden elements
197         $mform->addElement('hidden', 'id');
198         $mform->setType('id', PARAM_INT);
200         $mform->addElement('hidden', 'courseid');
201         $mform->setType('courseid', PARAM_INT);
202         $mform->setDefault('courseid', 0);
204         $mform->addElement('hidden', 'category');
205         $mform->setType('category', PARAM_RAW);
206         $mform->setDefault('category', array('contexts' => array($this->categorycontext)));
207               
208         $mform->addElement('hidden', 'cmid');
209         $mform->setType('cmid', PARAM_INT);
210         $mform->setDefault('cmid', 0);
212         $mform->addElement('hidden', 'wizard', 'datasetitems');
213         $mform->setType('wizard', PARAM_ALPHA);
215         $mform->addElement('hidden', 'returnurl');
216         $mform->setType('returnurl', PARAM_LOCALURL);
217         $mform->setDefault('returnurl', 0);
218     }
220     function set_data($question){
221         $formdata = array();
222         $fromform = new stdClass();
223         if (isset($question->options)){
224             $answers = $question->options->answers;
225             if (count($answers)) {
226                 if ( optional_param('updateanswers', '', PARAM_RAW) != '' || optional_param('updatedatasets', '', PARAM_RAW) != ''){
227                     foreach ($answers as $key => $answer){
228                         $fromform->tolerance[$key]= $this->_form->getElementValue('tolerance['.$key.']');
229                         $answer->tolerance = $fromform->tolerance[$key];
230                         $fromform->tolerancetype[$key]= $this->_form->getElementValue('tolerancetype['.$key.']');
231                         if( is_array($fromform->tolerancetype[$key])) $fromform->tolerancetype[$key]= $fromform->tolerancetype[$key][0];
232                         $answer->tolerancetype = $fromform->tolerancetype[$key];
233                         $fromform->correctanswerlength[$key]= $this->_form->getElementValue('correctanswerlength['.$key.']');
234                         if( is_array($fromform->correctanswerlength[$key])) $fromform->correctanswerlength[$key]= $fromform->correctanswerlength[$key][0];
235                         $answer->correctanswerlength = $fromform->correctanswerlength[$key];
236                         $fromform->correctanswerformat[$key]= $this->_form->getElementValue('correctanswerformat['.$key.']');
237                         if( is_array($fromform->correctanswerformat[$key])) $fromform->correctanswerformat[$key]= $fromform->correctanswerformat[$key][0];
238                         $answer->correctanswerformat = $fromform->correctanswerformat[$key];
239                     }
240                     $this->qtypeobj->save_question_calculated($question,$fromform); 
241                 }else {             
242                 foreach ($answers as $key => $answer){
243                   
244                     $formdata['tolerance['.$key.']'] = $answer->tolerance;
245                     $formdata['tolerancetype['.$key.']'] = $answer->tolerancetype;
246                     $formdata['correctanswerlength['.$key.']'] = $answer->correctanswerlength;
247                     $formdata['correctanswerformat['.$key.']'] = $answer->correctanswerformat;
248                }
249             }
250         }
251     }
252         //fill out all data sets and also the fields for the next item to add.
253         $j = $this->noofitems * count($this->datasetdefs);
254          for ($itemnumber = $this->noofitems; $itemnumber >= 1; $itemnumber--){
255             $data = array();
256             foreach ($this->datasetdefs as $defid => $datasetdef){
257                 if (isset($datasetdef->items[$itemnumber])){
258                     $formdata["number[$j]"] = $datasetdef->items[$itemnumber]->value;
259                     $formdata["definition[$j]"] = $defid;
260                     $formdata["itemid[$j]"] = $datasetdef->items[$itemnumber]->id;
261                     $data[$datasetdef->name] = $datasetdef->items[$itemnumber]->value;
262                 }
263                 $j--;
264             }
265             if($question->options->multichoice == 1 ){
266                 $comment = $this->qtypeobj->multichoice_comment_on_datasetitems($question->id,$answers, $data, $itemnumber);
267             }else {
268             $comment = $this->qtypeobj->comment_on_datasetitems($question->id,$answers, $data, $itemnumber);
269              if ($comment->outsidelimit) {
270                  $this->outsidelimit=$comment->outsidelimit ;
271             }
272         }
273             $totalcomment='';
274             foreach ($question->options->answers as $key => $answer) {
275                 $totalcomment .= $comment->stranswers[$key].'<br/>';
276             }
278             $formdata['answercomment['.$itemnumber.']'] = $totalcomment ;
279         }
281         $formdata['nextpageparam[forceregeneration]'] = $this->regenerate;
282         $formdata['selectdelete'] = '1';
283         $formdata['selectadd'] = '1';
284         $j = $this->noofitems * count($this->datasetdefs)+1;
285         $data = array(); // data for comment_on_datasetitems later
286         //dataset generation dafaults
287         if ($this->qtypeobj->supports_dataset_item_generation()) {
288             $itemnumber = $this->noofitems+1;
289             foreach ($this->datasetdefs as $defid => $datasetdef){
290                 if( optional_param('updatedatasets', '', PARAM_RAW) == '' && optional_param('updateanswers', '', PARAM_RAW)== ''){
291                 $formdata["number[$j]"] = $this->qtypeobj->generate_dataset_item($datasetdef->options);
292             }else {
293                 $formdata["number[$j]"] = $this->_form->getElementValue("number[$j]") ;
294             }
295                 $formdata["definition[$j]"] = $defid;
296                 $formdata["itemid[$j]"] =
297                         isset($datasetdef->items[$itemnumber])?$datasetdef->items[$itemnumber]->id:0;
298                 $data[$datasetdef->name] = $formdata["number[$j]"];
299                 $j++;
300             }
301         }
303         //existing records override generated data depending on radio element
304         $j = $this->noofitems * count($this->datasetdefs)+1;
305         if (!$this->regenerate && (optional_param('updatedatasets', '', PARAM_RAW) == '' && optional_param('updateanswers', '', PARAM_RAW)== '')){
306             $idx = 1;
307             $itemnumber = $this->noofitems+1;
308             foreach ($this->datasetdefs as $defid => $datasetdef){
309                 if (isset($datasetdef->items[$itemnumber])){
310                     $formdata["number[$j]"] = $datasetdef->items[$itemnumber]->value;
311                     $formdata["definition[$j]"] = $defid;
312                     $formdata["itemid[$j]"] = $datasetdef->items[$itemnumber]->id;
313                     $data[$datasetdef->name] = $datasetdef->items[$itemnumber]->value;
314                 }
315                 $j++;
316             }
318         }
319         //default answercomment will get ignored if answer element is not in the form.
320                     if($question->options->multichoice == 1 ){
321                 $comment = $this->qtypeobj->multichoice_comment_on_datasetitems($question->id,$answers, $data, $itemnumber);
322             }else {
324             $comment = $this->qtypeobj->comment_on_datasetitems($question->id,$answers, $data, ($this->noofitems+1));
325             if ($comment->outsidelimit) {
326                  $this->outsidelimit=$comment->outsidelimit ;
327             }
328         }
329             $key1 = 1;
330             foreach ($question->options->answers as $key => $answer) {
331                 $formdata['answercomment['.($this->noofitems+$key1).']'] = $comment->stranswers[$key];
332                 $key1++;
333             }
335         if ($this->outsidelimit){
336             $formdata['outsidelimit']= '<span class="error">'.get_string('oneanswertrueansweroutsidelimits', 'qtype_datasetdependent').'</span>';
337         }
338         $formdata = $this->qtypeobj->custom_generator_set_data($this->datasetdefs, $formdata);
340         parent::set_data((object)($formdata + (array)$question));
341     }
343     function validation($data, $files) {
344         $errors = array();
345         if (isset($data['backtoquiz']) && ($this->noofitems==0) ){
346             $errors['warning'] = get_string('warning', 'mnet');
347         } 
348         if ($this->outsidelimit){
349          //   if(!isset($errors['warning'])) $errors['warning']=' ';
350            $errors['outsidelimits'] = get_string('oneanswertrueansweroutsidelimits','qtype_calculated');
351         }
352         $numbers = $data['number'];
353         foreach ($numbers as $key => $number){
354             if(! is_numeric($number)){
355                 if (stristr($number,',')){
356                     $errors['number['.$key.']'] = get_string('The , cannot be used, use . as in 0.013 or 1.3e-2', 'qtype_datasetdependent');
357                 }else {    
358                     $errors['number['.$key.']'] = get_string('This is not a valid number', 'qtype_datasetdependent');
359                 }
360             }else if( stristr($number,'x')){
361                 $errors['number['.$key.']'] = get_string('Hexadecimal format (i.e. 0X12d) is not allowed', 'qtype_datasetdependent');
362             } else if( is_nan($number)){
363                 $errors['number['.$key.']'] = get_string('is a NAN number', 'qtype_datasetdependent');
364             }        
365         }
366         return $errors;
367     }
371 ?>