PageRenderTime 27ms CodeModel.GetById 2ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 1ms

/question/type/calculated/datasetitems_form.php

https://bitbucket.org/synergylearning/campusconnect
PHP | 503 lines | 405 code | 41 blank | 57 comment | 67 complexity | b4a5b64aed03b8f06563bac0e0ff3075 MD5 | raw file
  1<?php
  2// This file is part of Moodle - http://moodle.org/
  3//
  4// Moodle is free software: you can redistribute it and/or modify
  5// it under the terms of the GNU General Public License as published by
  6// the Free Software Foundation, either version 3 of the License, or
  7// (at your option) any later version.
  8//
  9// Moodle is distributed in the hope that it will be useful,
 10// but WITHOUT ANY WARRANTY; without even the implied warranty of
 11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12// GNU General Public License for more details.
 13//
 14// You should have received a copy of the GNU General Public License
 15// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 16
 17/**
 18 * Defines the editing form for the calculated question data set items.
 19 *
 20 * @package    qtype
 21 * @subpackage calculated
 22 * @copyright  2007 Jamie Pratt me@jamiep.org
 23 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 24 */
 25
 26
 27defined('MOODLE_INTERNAL') || die();
 28
 29require_once($CFG->dirroot . '/question/type/edit_question_form.php');
 30
 31
 32/**
 33 * Calculated question data set items editing form definition.
 34 *
 35 * @copyright  2007 Jamie Pratt me@jamiep.org
 36 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 37 */
 38class question_dataset_dependent_items_form extends question_wizard_form {
 39    /**
 40     * Question object with options and answers already loaded by get_question_options
 41     * Be careful how you use this it is needed sometimes to set up the structure of the
 42     * form in definition_inner but data is always loaded into the form with set_defaults.
 43     *
 44     * @var object
 45     */
 46    public $question;
 47    /**
 48     * Reference to question type object
 49     *
 50     * @var question_dataset_dependent_questiontype
 51     */
 52    public $qtypeobj;
 53
 54    public $datasetdefs;
 55
 56    public $maxnumber = -1;
 57
 58    public $regenerate;
 59
 60    public $noofitems;
 61
 62    public $outsidelimit = false;
 63
 64    public $commentanswers = array();
 65
 66    /**
 67     * Add question-type specific form fields.
 68     *
 69     * @param MoodleQuickForm $mform the form being built.
 70     */
 71    public function __construct($submiturl, $question, $regenerate) {
 72        global $SESSION, $CFG, $DB;
 73        $this->regenerate = $regenerate;
 74        $this->question = $question;
 75        $this->qtypeobj = question_bank::get_qtype($this->question->qtype);
 76        // Validate the question category.
 77        if (!$category = $DB->get_record('question_categories',
 78                array('id' => $question->category))) {
 79            print_error('categorydoesnotexist', 'question', $returnurl);
 80        }
 81        $this->category = $category;
 82        $this->categorycontext = context::instance_by_id($category->contextid);
 83        // Get the dataset defintions for this question.
 84        if (empty($question->id)) {
 85            $this->datasetdefs = $this->qtypeobj->get_dataset_definitions(
 86                    $question->id, $SESSION->calculated->definitionform->dataset);
 87        } else {
 88            if (empty($question->options)) {
 89                $this->get_question_options($question);
 90            }
 91            $this->datasetdefs = $this->qtypeobj->get_dataset_definitions(
 92                    $question->id, array());
 93        }
 94
 95        foreach ($this->datasetdefs as $datasetdef) {
 96            // Get maxnumber.
 97            if ($this->maxnumber == -1 || $datasetdef->itemcount < $this->maxnumber) {
 98                $this->maxnumber = $datasetdef->itemcount;
 99            }
100        }
101        foreach ($this->datasetdefs as $defid => $datasetdef) {
102            if (isset($datasetdef->id)) {
103                $this->datasetdefs[$defid]->items =
104                        $this->qtypeobj->get_database_dataset_items($datasetdef->id);
105            }
106        }
107        parent::__construct($submiturl);
108    }
109
110    protected function definition() {
111        $labelsharedwildcard = get_string("sharedwildcard", "qtype_calculated");
112        $mform =& $this->_form;
113        $mform->setDisableShortforms();
114
115        $strquestionlabel = $this->qtypeobj->comment_header($this->question);
116        if ($this->maxnumber != -1 ) {
117            $this->noofitems = $this->maxnumber;
118        } else {
119            $this->noofitems = 0;
120        }
121        $label = get_string("sharedwildcards", "qtype_calculated");
122
123        $html2 = $this->qtypeobj->print_dataset_definitions_category_shared(
124                $this->question, $this->datasetdefs);
125        $mform->addElement('static', 'listcategory', $label, $html2);
126        // ...----------------------------------------------------------------------.
127        $mform->addElement('submit', 'updatedatasets',
128                get_string('updatedatasetparam', 'qtype_calculated'));
129        $mform->registerNoSubmitButton('updatedatasets');
130        $mform->addElement('header', 'additemhdr',
131                get_string('itemtoadd', 'qtype_calculated'));
132        $idx = 1;
133        $data = array();
134        $j = (($this->noofitems) * count($this->datasetdefs))+1;
135        foreach ($this->datasetdefs as $defkey => $datasetdef) {
136            if ($datasetdef->category |= 0 ) {
137                $name = get_string('sharedwildcard', 'qtype_calculated', $datasetdef->name);
138            } else {
139                $name = get_string('wildcard', 'qtype_calculated', $datasetdef->name);
140            }
141            $mform->addElement('text', "number[$j]", $name);
142            $mform->setType("number[$j]", PARAM_RAW); // This parameter will be validated in validation().
143            $this->qtypeobj->custom_generator_tools_part($mform, $idx, $j);
144            $idx++;
145            $mform->addElement('hidden', "definition[$j]");
146            $mform->setType("definition[$j]", PARAM_RAW);
147            $mform->addElement('hidden', "itemid[$j]");
148            $mform->setType("itemid[$j]", PARAM_RAW);
149            $mform->addElement('static', "divider[$j]", '', '<hr />');
150            $mform->setType("divider[$j]", PARAM_RAW);
151            $j++;
152        }
153
154        $mform->addElement('header', 'updateanswershdr',
155                get_string('answerstoleranceparam', 'qtype_calculated'));
156        $mform->addElement('submit', 'updateanswers',
157                get_string('updatetolerancesparam', 'qtype_calculated'));
158        $mform->setAdvanced('updateanswers', true);
159        $mform->registerNoSubmitButton('updateanswers');
160
161        $answers = fullclone($this->question->options->answers);
162        $key1 =1;
163        foreach ($answers as $key => $answer) {
164            $ans = shorten_text($answer->answer, 17, true);
165            if ($ans === '*') {
166                $mform->addElement('static',
167                        'answercomment[' . ($this->noofitems+$key1) . ']', $ans);
168                $mform->addElement('hidden', 'tolerance['.$key.']', '');
169                $mform->setType('tolerance['.$key.']', PARAM_RAW);
170                $mform->setAdvanced('tolerance['.$key.']', true);
171                $mform->addElement('hidden', 'tolerancetype['.$key.']', '');
172                $mform->setType('tolerancetype['.$key.']', PARAM_RAW);
173                $mform->setAdvanced('tolerancetype['.$key.']', true);
174                $mform->addElement('hidden', 'correctanswerlength['.$key.']', '');
175                $mform->setType('correctanswerlength['.$key.']', PARAM_RAW);
176                $mform->setAdvanced('correctanswerlength['.$key.']', true);
177                $mform->addElement('hidden', 'correctanswerformat['.$key.']', '');
178                $mform->setType('correctanswerformat['.$key.']', PARAM_RAW);
179                $mform->setAdvanced('correctanswerformat['.$key.']', true);
180            } else if ( $ans !== '' ) {
181                $mform->addElement('static', 'answercomment[' . ($this->noofitems+$key1) . ']',
182                        $ans);
183                $mform->addElement('text', 'tolerance['.$key.']',
184                        get_string('tolerance', 'qtype_calculated'));
185                $mform->setType('tolerance['.$key.']', PARAM_RAW);
186                $mform->setAdvanced('tolerance['.$key.']', true);
187                $mform->addElement('select', 'tolerancetype['.$key.']',
188                        get_string('tolerancetype', 'qtype_numerical'),
189                        $this->qtypeobj->tolerance_types());
190                $mform->setAdvanced('tolerancetype['.$key.']', true);
191
192                $mform->addElement('select', 'correctanswerlength['.$key.']',
193                        get_string('correctanswershows', 'qtype_calculated'), range(0, 9));
194                $mform->setAdvanced('correctanswerlength['.$key.']', true);
195
196                $answerlengthformats = array(
197                    '1' => get_string('decimalformat', 'qtype_numerical'),
198                    '2' => get_string('significantfiguresformat', 'qtype_calculated')
199                );
200                $mform->addElement('select', 'correctanswerformat['.$key.']',
201                        get_string('correctanswershowsformat', 'qtype_calculated'),
202                        $answerlengthformats);
203                $mform->setAdvanced('correctanswerformat['.$key.']', true);
204                $mform->addElement('static', 'dividertolerance', '', '<hr />');
205                $mform->setAdvanced('dividertolerance', true);
206            }
207            $key1++;
208        }
209
210        $addremoveoptions = array();
211        $addremoveoptions['1']='1';
212        for ($i=10; $i<=100; $i+=10) {
213             $addremoveoptions["$i"]="$i";
214        }
215        $showoptions = Array();
216        $showoptions['1']='1';
217        $showoptions['2']='2';
218        $showoptions['5']='5';
219        for ($i=10; $i<=100; $i+=10) {
220             $showoptions["$i"]="$i";
221        }
222        $mform->addElement('header', 'addhdr', get_string('add', 'moodle'));
223        $mform->closeHeaderBefore('addhdr');
224
225        if ($this->qtypeobj->supports_dataset_item_generation()) {
226            $radiogrp = array();
227            $radiogrp[] =& $mform->createElement('radio', 'nextpageparam[forceregeneration]',
228                    null, get_string('reuseifpossible', 'qtype_calculated'), 0);
229            $radiogrp[] =& $mform->createElement('radio', 'nextpageparam[forceregeneration]',
230                    null, get_string('forceregenerationshared', 'qtype_calculated'), 1);
231            $radiogrp[] =& $mform->createElement('radio', 'nextpageparam[forceregeneration]',
232                    null, get_string('forceregenerationall', 'qtype_calculated'), 2);
233            $mform->addGroup($radiogrp, 'forceregenerationgrp',
234                    get_string('nextitemtoadd', 'qtype_calculated'), "<br/>", false);
235        }
236
237        $mform->addElement('submit', 'getnextbutton', get_string('getnextnow', 'qtype_calculated'));
238        $mform->addElement('static', "dividera", '', '<hr />');
239        $addgrp = array();
240        $addgrp[] =& $mform->createElement('submit', 'addbutton', get_string('add', 'moodle'));
241        $addgrp[] =& $mform->createElement('select', "selectadd",
242                get_string('additem', 'qtype_calculated'), $addremoveoptions);
243        $addgrp[] = & $mform->createElement('static', "stat", "Items",
244                get_string('newsetwildcardvalues', 'qtype_calculatedsimple'));
245        $mform->addGroup($addgrp, 'addgrp', get_string('additem', 'qtype_calculated'), ' ', false);
246        $mform->addElement('static', "divideradd", '', '');
247        if ($this->noofitems > 0) {
248            $mform->addElement('header', 'deleteitemhdr', get_string('delete', 'moodle'));
249            $deletegrp = array();
250            $deletegrp[] = $mform->createElement('submit', 'deletebutton',
251                    get_string('delete', 'moodle'));
252            $deletegrp[] = $mform->createElement('select', 'selectdelete',
253                    get_string('deleteitem', 'qtype_calculated')."1", $addremoveoptions);
254            $deletegrp[] = $mform->createElement('static', "stat", "Items",
255                    get_string('setwildcardvalues', 'qtype_calculatedsimple'));
256            $mform->addGroup($deletegrp, 'deletegrp', '', '   ', false);
257        } else {
258            $mform->addElement('static', 'warning', '', '<span class="error">' .
259                    get_string('youmustaddatleastoneitem', 'qtype_calculated').'</span>');
260        }
261
262        $addgrp1 = array();
263        $addgrp1[] = $mform->createElement('submit', 'showbutton',
264                get_string('showitems', 'qtype_calculated'));
265        $addgrp1[] = $mform->createElement('select', "selectshow", '' , $showoptions);
266        $addgrp1[] = $mform->createElement('static', "stat", '',
267                get_string('setwildcardvalues', 'qtype_calculated'));
268        $mform->addGroup($addgrp1, 'addgrp1', '', '   ', false);
269        $mform->registerNoSubmitButton('showbutton');
270        $mform->closeHeaderBefore('addgrp1');
271        // ...----------------------------------------------------------------------.
272        $j = $this->noofitems * count($this->datasetdefs);
273        $k = optional_param('selectshow', 1, PARAM_INT);
274        for ($i = $this->noofitems; $i >= 1; $i--) {
275            if ($k > 0) {
276                $mform->addElement('header', 'setnoheader' . $i, "<b>" .
277                        get_string('setno', 'qtype_calculated', $i)."</b>&nbsp;&nbsp;");
278            }
279            foreach ($this->datasetdefs as $defkey => $datasetdef) {
280                if ($k > 0) {
281                    if ($datasetdef->category == 0 ) {
282                        $mform->addElement('text', "number[$j]",
283                                get_string('wildcard', 'qtype_calculated', $datasetdef->name));
284                    } else {
285                        $mform->addElement('text', "number[$j]", get_string(
286                                'sharedwildcard', 'qtype_calculated', $datasetdef->name));
287                    }
288
289                } else {
290                    $mform->addElement('hidden', "number[$j]" , '');
291                }
292                $mform->setType("number[$j]", PARAM_RAW); // This parameter will be validated in validation().
293                $mform->addElement('hidden', "itemid[$j]");
294                $mform->setType("itemid[$j]", PARAM_INT);
295
296                $mform->addElement('hidden', "definition[$j]");
297                $mform->setType("definition[$j]", PARAM_NOTAGS);
298                $data[$datasetdef->name] =$datasetdef->items[$i]->value;
299
300                $j--;
301            }
302            if ('' != $strquestionlabel && ($k > 0 )) {
303                // ... $this->outsidelimit || !empty($this->numbererrors ).
304                $repeated[] = $mform->addElement('static', "answercomment[$i]", $strquestionlabel);
305                // Decode equations in question text.
306                $qtext = $this->qtypeobj->substitute_variables(
307                        $this->question->questiontext, $data);
308                $textequations = $this->qtypeobj->find_math_equations($qtext);
309                if ($textequations != '' && count($textequations) > 0 ) {
310                    $mform->addElement('static', "divider1[$j]", '',
311                            'Formulas {=..} in question text');
312                    foreach ($textequations as $key => $equation) {
313                        if ($formulaerrors = qtype_calculated_find_formula_errors($equation)) {
314                            $str = $formulaerrors;
315                        } else {
316                            eval('$str = '.$equation.';');
317                        }
318                        $equation = shorten_text($equation, 17, true);
319                        $mform->addElement('static', "textequation", "{=$equation}", "=".$str);
320                    }
321                }
322
323            }
324            $k--;
325
326        }
327        $mform->addElement('static', 'outsidelimit', '', '');
328        // ...----------------------------------------------------------------------
329        // Non standard name for button element needed so not using add_action_buttons.
330        if (!($this->noofitems==0) ) {
331            $mform->addElement('submit', 'savechanges', get_string('savechanges'));
332            $mform->closeHeaderBefore('savechanges');
333        }
334
335        $this->add_hidden_fields();
336
337        $mform->addElement('hidden', 'category');
338        $mform->setType('category', PARAM_SEQUENCE);
339
340        $mform->addElement('hidden', 'wizard', 'datasetitems');
341        $mform->setType('wizard', PARAM_ALPHA);
342    }
343
344    public function set_data($question) {
345        $formdata = array();
346        $fromform = new stdClass();
347        if (isset($question->options)) {
348            $answers = $question->options->answers;
349            if (count($answers)) {
350                if (optional_param('updateanswers', false, PARAM_BOOL) ||
351                        optional_param('updatedatasets', false, PARAM_BOOL)) {
352                    foreach ($answers as $key => $answer) {
353                        $fromform->tolerance[$key]= $this->_form->getElementValue(
354                                'tolerance['.$key.']');
355                        $answer->tolerance = $fromform->tolerance[$key];
356                        $fromform->tolerancetype[$key]= $this->_form->getElementValue(
357                                'tolerancetype['.$key.']');
358                        if (is_array($fromform->tolerancetype[$key])) {
359                            $fromform->tolerancetype[$key]= $fromform->tolerancetype[$key][0];
360                        }
361                        $answer->tolerancetype = $fromform->tolerancetype[$key];
362                        $fromform->correctanswerlength[$key]= $this->_form->getElementValue(
363                                'correctanswerlength['.$key.']');
364                        if (is_array($fromform->correctanswerlength[$key])) {
365                            $fromform->correctanswerlength[$key] =
366                                    $fromform->correctanswerlength[$key][0];
367                        }
368                        $answer->correctanswerlength = $fromform->correctanswerlength[$key];
369                        $fromform->correctanswerformat[$key] = $this->_form->getElementValue(
370                                'correctanswerformat['.$key.']');
371                        if (is_array($fromform->correctanswerformat[$key])) {
372                            $fromform->correctanswerformat[$key] =
373                                    $fromform->correctanswerformat[$key][0];
374                        }
375                        $answer->correctanswerformat = $fromform->correctanswerformat[$key];
376                    }
377                    $this->qtypeobj->save_question_calculated($question, $fromform);
378
379                } else {
380                    foreach ($answers as $key => $answer) {
381                        $formdata['tolerance['.$key.']'] = $answer->tolerance;
382                        $formdata['tolerancetype['.$key.']'] = $answer->tolerancetype;
383                        $formdata['correctanswerlength['.$key.']'] = $answer->correctanswerlength;
384                        $formdata['correctanswerformat['.$key.']'] = $answer->correctanswerformat;
385                    }
386                }
387            }
388        }
389        // Fill out all data sets and also the fields for the next item to add.
390        $j = $this->noofitems * count($this->datasetdefs);
391        for ($itemnumber = $this->noofitems; $itemnumber >= 1; $itemnumber--) {
392            $data = array();
393            foreach ($this->datasetdefs as $defid => $datasetdef) {
394                if (isset($datasetdef->items[$itemnumber])) {
395                    $formdata["number[$j]"] = $datasetdef->items[$itemnumber]->value;
396                    $formdata["definition[$j]"] = $defid;
397                    $formdata["itemid[$j]"] = $datasetdef->items[$itemnumber]->id;
398                    $data[$datasetdef->name] = $datasetdef->items[$itemnumber]->value;
399                }
400                $j--;
401            }
402            $comment = $this->qtypeobj->comment_on_datasetitems($this->qtypeobj, $question->id,
403                    $question->questiontext, $answers, $data, $itemnumber);
404            if ($comment->outsidelimit) {
405                $this->outsidelimit=$comment->outsidelimit;
406            }
407            $totalcomment='';
408            foreach ($question->options->answers as $key => $answer) {
409                $totalcomment .= $comment->stranswers[$key].'<br/>';
410            }
411            $formdata['answercomment['.$itemnumber.']'] = $totalcomment;
412        }
413
414        $formdata['nextpageparam[forceregeneration]'] = $this->regenerate;
415        $formdata['selectdelete'] = '1';
416        $formdata['selectadd'] = '1';
417        $j = $this->noofitems * count($this->datasetdefs)+1;
418        $data = array(); // Data for comment_on_datasetitems later.
419        // Dataset generation defaults.
420        if ($this->qtypeobj->supports_dataset_item_generation()) {
421            $itemnumber = $this->noofitems+1;
422            foreach ($this->datasetdefs as $defid => $datasetdef) {
423                if (!optional_param('updatedatasets', false, PARAM_BOOL) &&
424                        !optional_param('updateanswers', false, PARAM_BOOL)) {
425                    $formdata["number[$j]"] = $this->qtypeobj->generate_dataset_item(
426                            $datasetdef->options);
427                } else {
428                    $formdata["number[$j]"] = $this->_form->getElementValue("number[$j]");
429                }
430                $formdata["definition[$j]"] = $defid;
431                $formdata["itemid[$j]"] = isset($datasetdef->items[$itemnumber]) ?
432                        $datasetdef->items[$itemnumber]->id : 0;
433                $data[$datasetdef->name] = $formdata["number[$j]"];
434                $j++;
435            }
436        }
437
438        // Existing records override generated data depending on radio element.
439        $j = $this->noofitems * count($this->datasetdefs) + 1;
440        if (!$this->regenerate && !optional_param('updatedatasets', false, PARAM_BOOL) &&
441                !optional_param('updateanswers', false, PARAM_BOOL)) {
442            $idx = 1;
443            $itemnumber = $this->noofitems + 1;
444            foreach ($this->datasetdefs as $defid => $datasetdef) {
445                if (isset($datasetdef->items[$itemnumber])) {
446                    $formdata["number[$j]"] = $datasetdef->items[$itemnumber]->value;
447                    $formdata["definition[$j]"] = $defid;
448                    $formdata["itemid[$j]"] = $datasetdef->items[$itemnumber]->id;
449                    $data[$datasetdef->name] = $datasetdef->items[$itemnumber]->value;
450                }
451                $j++;
452            }
453        }
454
455        $comment = $this->qtypeobj->comment_on_datasetitems($this->qtypeobj, $question->id,
456                $question->questiontext, $answers, $data, ($this->noofitems + 1));
457        if (isset($comment->outsidelimit) && $comment->outsidelimit) {
458            $this->outsidelimit=$comment->outsidelimit;
459        }
460        $key1 = 1;
461        foreach ($question->options->answers as $key => $answer) {
462            $formdata['answercomment['.($this->noofitems+$key1).']'] = $comment->stranswers[$key];
463            $key1++;
464        }
465
466        if ($this->outsidelimit) {
467            $formdata['outsidelimit']= '<span class="error">' .
468                    get_string('oneanswertrueansweroutsidelimits', 'qtype_calculated') . '</span>';
469        }
470        $formdata = $this->qtypeobj->custom_generator_set_data($this->datasetdefs, $formdata);
471
472        parent::set_data((object)($formdata + (array)$question));
473    }
474
475    public function validation($data, $files) {
476        $errors = array();
477        if (isset($data['savechanges']) && ($this->noofitems==0) ) {
478            $errors['warning'] = get_string('warning', 'mnet');
479        }
480        if ($this->outsidelimit) {
481            $errors['outsidelimits'] =
482                    get_string('oneanswertrueansweroutsidelimits', 'qtype_calculated');
483        }
484        $numbers = $data['number'];
485        foreach ($numbers as $key => $number) {
486            if (! is_numeric($number)) {
487                if (stristr($number, ',')) {
488                    $errors['number['.$key.']'] = get_string('nocommaallowed', 'qtype_calculated');
489                } else {
490                    $errors['number['.$key.']'] = get_string('notvalidnumber', 'qtype_calculated');
491                }
492            } else if (stristr($number, 'x')) {
493                $a = new stdClass();
494                $a->name = '';
495                $a->value = $number;
496                $errors['number['.$key.']'] = get_string('hexanotallowed', 'qtype_calculated', $a);
497            } else if (is_nan($number)) {
498                $errors['number['.$key.']'] = get_string('notvalidnumber', 'qtype_calculated');
499            }
500        }
501        return $errors;
502    }
503}