AutorÃa | Ultima modificación | Ver Log |
<?php// This file is part of Moodle - http://moodle.org///// Moodle is free software: you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// Moodle is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with Moodle. If not, see <http://www.gnu.org/licenses/>./*** Defines the editing form for the numerical question type.** @package qtype* @subpackage numerical* @copyright 2007 Jamie Pratt me@jamiep.org* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/defined('MOODLE_INTERNAL') || die();require_once($CFG->dirroot . '/question/type/edit_question_form.php');require_once($CFG->dirroot . '/question/type/numerical/questiontype.php');/*** numerical editing form definition.** @copyright 2007 Jamie Pratt me@jamiep.org* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/class qtype_numerical_edit_form extends question_edit_form {/** @var int we always show at least this many sets of unit fields. */const UNITS_MIN_REPEATS = 1;const UNITS_TO_ADD = 2;protected $ap = null;protected function definition_inner($mform) {$this->add_per_answer_fields($mform, get_string('answerno', 'qtype_numerical', '{no}'),question_bank::fraction_options());$this->add_unit_options($mform);$this->add_unit_fields($mform);$this->add_interactive_settings();}protected function get_per_answer_fields($mform, $label, $gradeoptions,&$repeatedoptions, &$answersoption) {$repeated = parent::get_per_answer_fields($mform, $label, $gradeoptions,$repeatedoptions, $answersoption);$tolerance = $mform->createElement('float', 'tolerance',get_string('answererror', 'qtype_numerical'), array('size' => 15));$repeatedoptions['tolerance']['default'] = 0;$elements = $repeated[0]->getElements();$elements[0]->setSize(15);array_splice($elements, 1, 0, array($tolerance));$repeated[0]->setElements($elements);return $repeated;}protected function get_more_choices_string() {return get_string('addmoreanswerblanks', 'qtype_numerical');}/*** Add the unit handling options to the form.* @param object $mform the form being built.*/protected function add_unit_options($mform) {$mform->addElement('header', 'unithandling',get_string('unithandling', 'qtype_numerical'));$unitoptions = array(qtype_numerical::UNITNONE => get_string('onlynumerical', 'qtype_numerical'),qtype_numerical::UNITOPTIONAL => get_string('manynumerical', 'qtype_numerical'),qtype_numerical::UNITGRADED => get_string('unitgraded', 'qtype_numerical'),);$mform->addElement('select', 'unitrole',get_string('unithandling', 'qtype_numerical'), $unitoptions);$mform->setDefault('unitrole', $this->get_default_value('unitrole', qtype_numerical::UNITNONE));$penaltygrp = array();$penaltygrp[] = $mform->createElement('float', 'unitpenalty',get_string('unitpenalty', 'qtype_numerical'), array('size' => 6));$mform->setDefault('unitpenalty', $this->get_default_value('unitpenalty', 0.1000000));$unitgradingtypes = array(qtype_numerical::UNITGRADEDOUTOFMARK =>get_string('decfractionofresponsegrade', 'qtype_numerical'),qtype_numerical::UNITGRADEDOUTOFMAX =>get_string('decfractionofquestiongrade', 'qtype_numerical'),);$penaltygrp[] = $mform->createElement('select', 'unitgradingtypes', '', $unitgradingtypes);$mform->setDefault('unitgradingtypes',$this->get_default_value('unitgradingtypes', qtype_numerical::UNITGRADEDOUTOFMARK));$mform->addGroup($penaltygrp, 'penaltygrp',get_string('unitpenalty', 'qtype_numerical'), ' ', false);$mform->addHelpButton('penaltygrp', 'unitpenalty', 'qtype_numerical');$unitinputoptions = array(qtype_numerical::UNITINPUT => get_string('editableunittext', 'qtype_numerical'),qtype_numerical::UNITRADIO => get_string('unitchoice', 'qtype_numerical'),qtype_numerical::UNITSELECT => get_string('unitselect', 'qtype_numerical'),);$mform->addElement('select', 'multichoicedisplay',get_string('studentunitanswer', 'qtype_numerical'), $unitinputoptions);$mform->setDefault('multichoicedisplay',$this->get_default_value('multichoicedisplay', qtype_numerical::UNITINPUT));$unitsleftoptions = array(0 => get_string('rightexample', 'qtype_numerical'),1 => get_string('leftexample', 'qtype_numerical'));$mform->addElement('select', 'unitsleft',get_string('unitposition', 'qtype_numerical'), $unitsleftoptions);$mform->setDefault('unitsleft', $this->get_default_value('unitsleft', 0));$mform->disabledIf('penaltygrp', 'unitrole', 'eq', qtype_numerical::UNITNONE);$mform->disabledIf('penaltygrp', 'unitrole', 'eq', qtype_numerical::UNITOPTIONAL);$mform->disabledIf('unitsleft', 'unitrole', 'eq', qtype_numerical::UNITNONE);$mform->disabledIf('multichoicedisplay', 'unitrole', 'eq', qtype_numerical::UNITNONE);$mform->disabledIf('multichoicedisplay', 'unitrole', 'eq', qtype_numerical::UNITOPTIONAL);}/*** Add the input areas for each unit.* @param object $mform the form being built.*/protected function add_unit_fields($mform) {$mform->addElement('header', 'unithdr',get_string('units', 'qtype_numerical'), '');$unitfields = array($mform->createElement('group', 'units',get_string('unitx', 'qtype_numerical'), $this->unit_group($mform), null, false));$repeatedoptions['unit']['disabledif'] = array('unitrole', 'eq', qtype_numerical::UNITNONE);$repeatedoptions['unit']['type'] = PARAM_NOTAGS;$repeatedoptions['multiplier']['disabledif'] = array('unitrole', 'eq', qtype_numerical::UNITNONE);$mform->disabledIf('addunits', 'unitrole', 'eq', qtype_numerical::UNITNONE);if (isset($this->question->options->units)) {$repeatsatstart = max(count($this->question->options->units), self::UNITS_MIN_REPEATS);} else {$repeatsatstart = self::UNITS_MIN_REPEATS;}$this->repeat_elements($unitfields, $repeatsatstart, $repeatedoptions, 'nounits','addunits', self::UNITS_TO_ADD, get_string('addmoreunitblanks', 'qtype_numerical', '{no}'), true);// The following strange-looking if statement is to do with when the// form is used to move questions between categories. See MDL-15159.if ($mform->elementExists('units[0]')) {$firstunit = $mform->getElement('units[0]');$elements = $firstunit->getElements();foreach ($elements as $element) {if ($element->getName() != 'multiplier[0]') {continue;}$element->freeze();$element->setValue('1.0');$element->setPersistantFreeze(true);}$mform->addHelpButton('units[0]', 'numericalmultiplier', 'qtype_numerical');}}/*** Get the form fields needed to edit one unit.* @param MoodleQuickForm $mform the form being built.* @return array of form fields.*/protected function unit_group($mform) {$grouparray = array();$grouparray[] = $mform->createElement('text', 'unit', get_string('unit', 'qtype_numerical'), array('size'=>10));$grouparray[] = $mform->createElement('float', 'multiplier',get_string('multiplier', 'qtype_numerical'), array('size'=>10));return $grouparray;}protected function data_preprocessing($question) {$question = parent::data_preprocessing($question);$question = $this->data_preprocessing_answers($question);$question = $this->data_preprocessing_hints($question);$question = $this->data_preprocessing_units($question);$question = $this->data_preprocessing_unit_options($question);return $question;}protected function data_preprocessing_answers($question, $withanswerfiles = false) {$question = parent::data_preprocessing_answers($question, $withanswerfiles);if (empty($question->options->answers)) {return $question;}$key = 0;foreach ($question->options->answers as $answer) {// See comment in the parent method about this hack.unset($this->_form->_defaultValues["tolerance[{$key}]"]);$question->tolerance[$key] = $answer->tolerance;if (is_numeric($question->answer[$key])) {$question->answer[$key] = format_float($question->answer[$key], -1);}$key++;}return $question;}/*** Perform the necessary preprocessing for the fields added by* {@link add_unit_fields()}.* @param object $question the data being passed to the form.* @return object $question the modified data.*/protected function data_preprocessing_units($question) {if (empty($question->options->units)) {return $question;}foreach ($question->options->units as $key => $unit) {$question->unit[$key] = $unit->unit;$question->multiplier[$key] = $unit->multiplier;}return $question;}/*** Perform the necessary preprocessing for the fields added by* {@link add_unit_options()}.* @param object $question the data being passed to the form.* @return object $question the modified data.*/protected function data_preprocessing_unit_options($question) {if (empty($question->options)) {return $question;}$question->unitpenalty = $question->options->unitpenalty;$question->unitsleft = $question->options->unitsleft;if ($question->options->unitgradingtype) {$question->unitgradingtypes = $question->options->unitgradingtype;$question->multichoicedisplay = $question->options->showunits;$question->unitrole = qtype_numerical::UNITGRADED;} else {$question->unitrole = $question->options->showunits;}return $question;}public function validation($data, $files) {$errors = parent::validation($data, $files);$errors = $this->validate_answers($data, $errors);$errors = $this->validate_numerical_options($data, $errors);return $errors;}/*** Validate the answers.* @param array $data the submitted data.* @param array $errors the errors array to add to.* @return array the updated errors array.*/protected function validate_answers($data, $errors) {// Check the answers.$answercount = 0;$maxgrade = false;$answers = $data['answer'];foreach ($answers as $key => $answer) {$trimmedanswer = trim($answer);if ($trimmedanswer != '') {$answercount++;if (!$this->is_valid_answer($trimmedanswer, $data)) {$errors['answeroptions[' . $key . ']'] = $this->valid_answer_message($trimmedanswer);}if ($data['fraction'][$key] == 1) {$maxgrade = true;}if ($answer !== '*' && $data['tolerance'][$key] === false) {$errors['answeroptions['.$key.']'] =get_string('xmustbenumeric', 'qtype_numerical',get_string('acceptederror', 'qtype_numerical'));}} else if ($data['fraction'][$key] != 0 ||!html_is_blank($data['feedback'][$key]['text'])) {$errors['answeroptions[' . $key . ']'] = $this->valid_answer_message($trimmedanswer);$answercount++;}}if ($answercount == 0) {$errors['answeroptions[0]'] = get_string('notenoughanswers', 'qtype_numerical');}if ($maxgrade == false) {$errors['answeroptions[0]'] = get_string('fractionsnomax', 'question');}return $errors;}/*** Validate a particular answer.* @param string $answer an answer to validate. Known to be non-blank and already trimmed.* @param array $data the submitted data.* @return bool whether this is a valid answer.*/protected function is_valid_answer($answer, $data) {return $answer == '*' || qtype_numerical::is_valid_number($answer);}/*** @return string erre describing what an answer should be.*/protected function valid_answer_message($answer) {return get_string('answermustbenumberorstar', 'qtype_numerical');}/*** Validate the answers.* @param array $data the submitted data.* @param array $errors the errors array to add to.* @return array the updated errors array.*/protected function validate_numerical_options($data, $errors) {if ($data['unitrole'] != qtype_numerical::UNITNONE && trim($data['unit'][0]) == '') {$errors['units[0]'] = get_string('unitonerequired', 'qtype_numerical');}if (empty($data['unit']) || $data['unitrole'] == qtype_numerical::UNITNONE) {return $errors;}// Basic unit validation.foreach ($data['unit'] as $key => $unit) {if (is_numeric($unit)) {$errors['units[' . $key . ']'] =get_string('xmustnotbenumeric', 'qtype_numerical',get_string('unit', 'qtype_numerical'));}$trimmedunit = trim($unit);if (empty($trimmedunit)) {continue;}$trimmedmultiplier = trim($data['multiplier'][$key]);if (empty($trimmedmultiplier)) {$errors['units[' . $key . ']'] =get_string('youmustenteramultiplierhere', 'qtype_numerical');} else if ($trimmedmultiplier === false) {$errors['units[' . $key . ']'] =get_string('xmustbenumeric', 'qtype_numerical',get_string('multiplier', 'qtype_numerical'));}}// Check for repeated units.$alreadyseenunits = array();foreach ($data['unit'] as $key => $unit) {$trimmedunit = trim($unit);if ($trimmedunit == '') {continue;}if (in_array($trimmedunit, $alreadyseenunits)) {$errors['units[' . $key . ']'] =get_string('errorrepeatedunit', 'qtype_numerical');} else {$alreadyseenunits[] = $trimmedunit;}}return $errors;}public function qtype() {return 'numerical';}}