[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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 /** 19 * Drop down form element to select the grade 20 * 21 * Contains HTML class for a drop down element to select the grade for an activity, 22 * used in mod update form 23 * 24 * @package core_form 25 * @copyright 2006 Jamie Pratt <me@jamiep.org> 26 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 27 */ 28 29 global $CFG; 30 require_once "$CFG->libdir/form/select.php"; 31 require_once("HTML/QuickForm/element.php"); 32 require_once($CFG->dirroot.'/lib/form/group.php'); 33 require_once($CFG->dirroot.'/lib/grade/grade_scale.php'); 34 35 /** 36 * Drop down form element to select the grade 37 * 38 * HTML class for a drop down element to select the grade for an activity, 39 * used in mod update form 40 * 41 * @package core_form 42 * @category form 43 * @copyright 2006 Jamie Pratt <me@jamiep.org> 44 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 45 */ 46 class MoodleQuickForm_modgrade extends MoodleQuickForm_group { 47 48 /** @var boolean $isupdate Is this an add or an update ? */ 49 public $isupdate = false; 50 51 /** @var float $currentgrade The current grademax for the grade_item */ 52 public $currentgrade = false; 53 54 /** @var boolean $hasgrades Has this grade_item got any real grades (with values) */ 55 public $hasgrades = false; 56 57 /** @var boolean $canrescale Does this activity support rescaling grades? */ 58 public $canrescale = false; 59 60 /** @var int $currentscaleid The current scale id */ 61 public $currentscaleid = null; 62 63 /** @var string $currentgradetype The current gradetype - can either be 'none', 'scale', or 'point' */ 64 public $currentgradetype = 'none'; 65 66 /** @var boolean $useratings Set to true if the activity is using ratings, false otherwise */ 67 public $useratings = false; 68 69 /** @var MoodleQuickForm_select $gradetypeformelement */ 70 private $gradetypeformelement; 71 72 /** @var MoodleQuickForm_select $scaleformelement */ 73 private $scaleformelement; 74 75 /** @var MoodleQuickForm_text $maxgradeformelement */ 76 private $maxgradeformelement; 77 78 /** 79 * Constructor 80 * 81 * @param string $elementname Element's name 82 * @param mixed $elementlabel Label(s) for an element 83 * @param array $options Options to control the element's display. Required - must contain the following options: 84 * 'isupdate' - is this a new module or are we editing an existing one? 85 * 'currentgrade' - the current grademax in the database for this gradeitem 86 * 'hasgrades' - whether or not the grade_item has existing grade_grades 87 * 'canrescale' - whether or not the activity supports rescaling grades 88 * @param mixed $attributes Either a typical HTML attribute string or an associative array 89 */ 90 public function __construct($elementname = null, $elementlabel = null, $options = array(), $attributes = null) { 91 // TODO MDL-52313 Replace with the call to parent::__construct(). 92 HTML_QuickForm_element::__construct($elementname, $elementlabel, $attributes); 93 $this->_persistantFreeze = true; 94 $this->_appendName = true; 95 $this->_type = 'modgrade'; 96 $this->isupdate = !empty($options['isupdate']); 97 if (isset($options['currentgrade'])) { 98 $this->currentgrade = $options['currentgrade']; 99 } 100 if (isset($options['currentgradetype'])) { 101 $gradetype = $options['currentgradetype']; 102 switch ($gradetype) { 103 case GRADE_TYPE_NONE : 104 $this->currentgradetype = 'none'; 105 break; 106 case GRADE_TYPE_SCALE : 107 $this->currentgradetype = 'scale'; 108 break; 109 case GRADE_TYPE_VALUE : 110 $this->currentgradetype = 'point'; 111 break; 112 } 113 } 114 if (isset($options['currentscaleid'])) { 115 $this->currentscaleid = $options['currentscaleid']; 116 } 117 $this->hasgrades = !empty($options['hasgrades']); 118 $this->canrescale = !empty($options['canrescale']); 119 $this->useratings = !empty($options['useratings']); 120 } 121 122 /** 123 * Old syntax of class constructor. Deprecated in PHP7. 124 * 125 * @deprecated since Moodle 3.1 126 */ 127 public function MoodleQuickForm_modgrade($elementname = null, $elementlabel = null, $options = array(), $attributes = null) { 128 debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER); 129 self::__construct($elementname, $elementlabel, $options, $attributes); 130 } 131 132 /** 133 * Create elements for this group. 134 */ 135 public function _createElements() { 136 global $COURSE, $CFG, $OUTPUT; 137 $attributes = $this->getAttributes(); 138 if (is_null($attributes)) { 139 $attributes = array(); 140 } 141 142 $this->_elements = array(); 143 144 // Create main elements 145 // We have to create the scale and point elements first, as we need their IDs. 146 147 // Grade scale select box. 148 $scales = get_scales_menu($COURSE->id); 149 $langscale = get_string('modgradetypescale', 'grades'); 150 $this->scaleformelement = @MoodleQuickForm::createElement('select', 'modgrade_scale', $langscale, 151 $scales, $attributes); 152 $this->scaleformelement->setHiddenLabel = false; 153 $scaleformelementid = $this->generate_modgrade_subelement_id('modgrade_scale'); 154 $this->scaleformelement->updateAttributes(array('id' => $scaleformelementid)); 155 156 // Maximum grade textbox. 157 $langmaxgrade = get_string('modgrademaxgrade', 'grades'); 158 $this->maxgradeformelement = @MoodleQuickForm::createElement('text', 'modgrade_point', $langmaxgrade, array()); 159 $this->maxgradeformelement->setHiddenLabel = false; 160 $maxgradeformelementid = $this->generate_modgrade_subelement_id('modgrade_point'); 161 $this->maxgradeformelement->updateAttributes(array('id' => $maxgradeformelementid)); 162 163 // Grade type select box. 164 $gradetype = array( 165 'none' => get_string('modgradetypenone', 'grades'), 166 'scale' => get_string('modgradetypescale', 'grades'), 167 'point' => get_string('modgradetypepoint', 'grades'), 168 ); 169 $langtype = get_string('modgradetype', 'grades'); 170 $this->gradetypeformelement = @MoodleQuickForm::createElement('select', 'modgrade_type', $langtype, $gradetype, 171 $attributes, true); 172 $this->gradetypeformelement->setHiddenLabel = false; 173 $gradetypeformelementid = $this->generate_modgrade_subelement_id('modgrade_type'); 174 $this->gradetypeformelement->updateAttributes(array('id' => $gradetypeformelementid)); 175 176 if ($this->isupdate && $this->hasgrades) { 177 $this->gradetypeformelement->updateAttributes(array('disabled' => 'disabled')); 178 $this->scaleformelement->updateAttributes(array('disabled' => 'disabled')); 179 180 // Check box for options for processing existing grades. 181 if ($this->canrescale) { 182 $langrescalegrades = get_string('modgraderescalegrades', 'grades'); 183 $choices = array(); 184 $choices[''] = get_string('choose'); 185 $choices['no'] = get_string('no'); 186 $choices['yes'] = get_string('yes'); 187 $rescalegradesselect = @MoodleQuickForm::createElement('select', 188 'modgrade_rescalegrades', 189 $langrescalegrades, 190 $choices); 191 $rescalegradesselect->setHiddenLabel = false; 192 $rescalegradesselectid = $this->generate_modgrade_subelement_id('modgrade_rescalegrades'); 193 $rescalegradesselect->updateAttributes(array('id' => $rescalegradesselectid)); 194 } 195 } 196 197 // Add elements. 198 if ($this->isupdate && $this->hasgrades) { 199 // Set a message so the user knows why they can not alter the grade type or scale. 200 if ($this->currentgradetype == 'scale') { 201 $gradesexistmsg = get_string('modgradecantchangegradetyporscalemsg', 'grades'); 202 } else { 203 $gradesexistmsg = get_string('modgradecantchangegradetypemsg', 'grades'); 204 } 205 206 $gradesexisthtml = '<div class=\'alert\'>' . $gradesexistmsg . '</div>'; 207 $this->_elements[] = @MoodleQuickForm::createElement('static', 'gradesexistmsg', '', $gradesexisthtml); 208 } 209 210 // Grade type select box. 211 $label = html_writer::tag('label', $this->gradetypeformelement->getLabel(), 212 array('for' => $this->gradetypeformelement->getAttribute('id'))); 213 $this->_elements[] = @MoodleQuickForm::createElement('static', 'gradetypelabel', '', ' '.$label); 214 $this->_elements[] = $this->gradetypeformelement; 215 $this->_elements[] = @MoodleQuickForm::createElement('static', 'gradetypespacer', '', '<br />'); 216 217 // Only show the grade scale select box when applicable. 218 if (!$this->isupdate || !$this->hasgrades || $this->currentgradetype == 'scale') { 219 $label = html_writer::tag('label', $this->scaleformelement->getLabel(), 220 array('for' => $this->scaleformelement->getAttribute('id'))); 221 $this->_elements[] = @MoodleQuickForm::createElement('static', 'scalelabel', '', $label); 222 $this->_elements[] = $this->scaleformelement; 223 $this->_elements[] = @MoodleQuickForm::createElement('static', 'scalespacer', '', '<br />'); 224 } 225 226 if ($this->isupdate && $this->hasgrades && $this->canrescale && $this->currentgradetype == 'point') { 227 // We need to know how to apply any changes to maxgrade - ie to either update, or don't touch exising grades. 228 $label = html_writer::tag('label', $rescalegradesselect->getLabel(), 229 array('for' => $rescalegradesselect->getAttribute('id'))); 230 $labelhelp = new help_icon('modgraderescalegrades', 'grades'); 231 $this->_elements[] = @MoodleQuickForm::createElement('static', 'scalelabel', '', $label . $OUTPUT->render($labelhelp)); 232 $this->_elements[] = $rescalegradesselect; 233 $this->_elements[] = @MoodleQuickForm::createElement('static', 'scalespacer', '', '<br />'); 234 } 235 236 // Only show the max points form element when applicable. 237 if (!$this->isupdate || !$this->hasgrades || $this->currentgradetype == 'point') { 238 $label = html_writer::tag('label', $this->maxgradeformelement->getLabel(), 239 array('for' => $this->maxgradeformelement->getAttribute('id'))); 240 $this->_elements[] = @MoodleQuickForm::createElement('static', 'pointlabel', '', $label); 241 $this->_elements[] = $this->maxgradeformelement; 242 $this->_elements[] = @MoodleQuickForm::createElement('static', 'pointspacer', '', '<br />'); 243 } 244 } 245 246 /** 247 * Calculate the output value for the element as a whole. 248 * 249 * @param array $submitvalues The incoming values from the form. 250 * @param bool $notused Not used. 251 * @return array Return value for the element, formatted like field name => value. 252 */ 253 public function exportValue(&$submitvalues, $notused = false) { 254 global $COURSE; 255 256 // Get the values from all the child elements. 257 $vals = array(); 258 foreach ($this->_elements as $element) { 259 $thisexport = $element->exportValue($submitvalues[$this->getName()], true); 260 if (!is_null($thisexport)) { 261 $vals += $thisexport; 262 } 263 } 264 265 $type = (isset($vals['modgrade_type'])) ? $vals['modgrade_type'] : 'none'; 266 $point = (isset($vals['modgrade_point'])) ? $vals['modgrade_point'] : null; 267 $scale = (isset($vals['modgrade_scale'])) ? $vals['modgrade_scale'] : null; 268 $rescalegrades = (isset($vals['modgrade_rescalegrades'])) ? $vals['modgrade_rescalegrades'] : null; 269 $return = $this->process_value($type, $scale, $point); 270 return array($this->getName() => $return, $this->getName() . '_rescalegrades' => $rescalegrades); 271 } 272 273 /** 274 * Process the value for the group based on the selected grade type, and the input for the scale and point elements. 275 * 276 * @param string $type The value of the grade type select box. Can be 'none', 'scale', or 'point' 277 * @param string|int $scale The value of the scale select box. 278 * @param string|int $point The value of the point grade textbox. 279 * @return int The resulting value 280 */ 281 protected function process_value($type='none', $scale=null, $point=null) { 282 global $COURSE; 283 $val = 0; 284 switch ($type) { 285 case 'point': 286 if ($this->validate_point($point) === true) { 287 $val = (int)$point; 288 } 289 break; 290 291 case 'scale': 292 if ($this->validate_scale($scale)) { 293 $val = (int)(-$scale); 294 } 295 break; 296 } 297 return $val; 298 } 299 300 /** 301 * Determines whether a given value is a valid scale selection. 302 * 303 * @param string|int $val The value to test. 304 * @return bool Valid or invalid 305 */ 306 protected function validate_scale($val) { 307 global $COURSE; 308 $scales = get_scales_menu($COURSE->id); 309 return (!empty($val) && isset($scales[(int)$val])) ? true : false; 310 } 311 312 /** 313 * Determines whether a given value is a valid point selection. 314 * 315 * @param string|int $val The value to test. 316 * @return bool Valid or invalid 317 */ 318 protected function validate_point($val) { 319 if (empty($val)) { 320 return false; 321 } 322 $maxgrade = (int)get_config('core', 'gradepointmax'); 323 $isintlike = ((string)(int)$val === $val) ? true : false; 324 return ($isintlike === true && $val > 0 && $val <= $maxgrade) ? true : false; 325 } 326 327 /** 328 * Called by HTML_QuickForm whenever form event is made on this element. 329 * 330 * @param string $event Name of event 331 * @param mixed $arg event arguments 332 * @param moodleform $caller calling object 333 * @return mixed 334 */ 335 public function onQuickFormEvent($event, $arg, &$caller) { 336 switch ($event) { 337 case 'createElement': 338 // The first argument is the name. 339 $name = $arg[0]; 340 341 // Set disable actions. 342 $caller->disabledIf($name.'[modgrade_scale]', $name.'[modgrade_type]', 'neq', 'scale'); 343 $caller->disabledIf($name.'[modgrade_point]', $name.'[modgrade_type]', 'neq', 'point'); 344 $caller->disabledIf($name.'[modgrade_rescalegrades]', $name.'[modgrade_type]', 'neq', 'point'); 345 346 // Set validation rules for the sub-elements belonging to this element. 347 // A handy note: the parent scope of a closure is the function in which the closure was declared. 348 // Because of this using $this is safe despite the closures being called statically. 349 // A nasty magic hack! 350 $checkgradetypechange = function($val) { 351 // Nothing is affected by changes to the grade type if there are no grades yet. 352 if (!$this->hasgrades) { 353 return true; 354 } 355 // Check if we are changing the grade type when grades are present. 356 if (isset($val['modgrade_type']) && $val['modgrade_type'] !== $this->currentgradetype) { 357 return false; 358 } 359 return true; 360 }; 361 $checkscalechange = function($val) { 362 // Nothing is affected by changes to the scale if there are no grades yet. 363 if (!$this->hasgrades) { 364 return true; 365 } 366 // Check if we are changing the scale type when grades are present. 367 // If modgrade_type is empty then use currentgradetype. 368 $gradetype = isset($val['modgrade_type']) ? $val['modgrade_type'] : $this->currentgradetype; 369 if ($gradetype === 'scale') { 370 if (isset($val['modgrade_scale']) && ($val['modgrade_scale'] !== $this->currentscaleid)) { 371 return false; 372 } 373 } 374 return true; 375 }; 376 $checkmaxgradechange = function($val) { 377 // Nothing is affected by changes to the max grade if there are no grades yet. 378 if (!$this->hasgrades) { 379 return true; 380 } 381 // If we are not using ratings we can change the max grade. 382 if (!$this->useratings) { 383 return true; 384 } 385 // Check if we are changing the max grade if we are using ratings and there is a grade. 386 // If modgrade_type is empty then use currentgradetype. 387 $gradetype = isset($val['modgrade_type']) ? $val['modgrade_type'] : $this->currentgradetype; 388 if ($gradetype === 'point') { 389 if (isset($val['modgrade_point']) && 390 grade_floats_different($this->currentgrade, $val['modgrade_point'])) { 391 return false; 392 } 393 } 394 return true; 395 }; 396 $checkmaxgrade = function($val) { 397 // Closure to validate a max points value. See the note above about scope if this confuses you. 398 // If modgrade_type is empty then use currentgradetype. 399 $gradetype = isset($val['modgrade_type']) ? $val['modgrade_type'] : $this->currentgradetype; 400 if ($gradetype === 'point') { 401 if (isset($val['modgrade_point'])) { 402 return $this->validate_point($val['modgrade_point']); 403 } 404 } 405 return true; 406 }; 407 $checkvalidscale = function($val) { 408 // Closure to validate a scale value. See the note above about scope if this confuses you. 409 // If modgrade_type is empty then use currentgradetype. 410 $gradetype = isset($val['modgrade_type']) ? $val['modgrade_type'] : $this->currentgradetype; 411 if ($gradetype === 'scale') { 412 if (isset($val['modgrade_scale'])) { 413 return $this->validate_scale($val['modgrade_scale']); 414 } 415 } 416 return true; 417 }; 418 419 $checkrescale = function($val) { 420 // Nothing is affected by changes to grademax if there are no grades yet. 421 if (!$this->isupdate || !$this->hasgrades || !$this->canrescale) { 422 return true; 423 } 424 // Closure to validate a scale value. See the note above about scope if this confuses you. 425 // If modgrade_type is empty then use currentgradetype. 426 $gradetype = isset($val['modgrade_type']) ? $val['modgrade_type'] : $this->currentgradetype; 427 if ($gradetype === 'point' && isset($val['modgrade_point'])) { 428 // Work out if the value was actually changed in the form. 429 if (grade_floats_different($this->currentgrade, $val['modgrade_point'])) { 430 if (empty($val['modgrade_rescalegrades'])) { 431 // This was an "edit", the grademax was changed and the process existing setting was not set. 432 return false; 433 } 434 } 435 } 436 return true; 437 }; 438 439 $cantchangegradetype = get_string('modgradecantchangegradetype', 'grades'); 440 $cantchangemaxgrade = get_string('modgradecantchangeratingmaxgrade', 'grades'); 441 $maxgradeexceeded = get_string('modgradeerrorbadpoint', 'grades', get_config('core', 'gradepointmax')); 442 $invalidscale = get_string('modgradeerrorbadscale', 'grades'); 443 $cantchangescale = get_string('modgradecantchangescale', 'grades'); 444 $mustchooserescale = get_string('mustchooserescaleyesorno', 'grades'); 445 // When creating the rules the sixth arg is $force, we set it to true because otherwise the form 446 // will attempt to validate the existence of the element, we don't want this because the element 447 // is being created right now and doesn't actually exist as a registered element yet. 448 $caller->addRule($name, $cantchangegradetype, 'callback', $checkgradetypechange, 'server', false, true); 449 $caller->addRule($name, $cantchangemaxgrade, 'callback', $checkmaxgradechange, 'server', false, true); 450 $caller->addRule($name, $maxgradeexceeded, 'callback', $checkmaxgrade, 'server', false, true); 451 $caller->addRule($name, $invalidscale, 'callback', $checkvalidscale, 'server', false, true); 452 $caller->addRule($name, $cantchangescale, 'callback', $checkscalechange, 'server', false, true); 453 $caller->addRule($name, $mustchooserescale, 'callback', $checkrescale, 'server', false, true); 454 455 break; 456 457 case 'updateValue': 458 // As this is a group element with no value of its own we are only interested in situations where the 459 // default value or a constant value are being provided to the actual element. 460 // In this case we expect an int that is going to translate to a scale if negative, or to max points 461 // if positive. 462 463 // Set the maximum points field to disabled if the rescale option has not been chosen and there are grades. 464 $caller->disabledIf($this->getName() . '[modgrade_point]', $this->getName() . 465 '[modgrade_rescalegrades]', 'eq', ''); 466 467 // A constant value should be given as an int. 468 // The default value should be an int and be either $CFG->gradepointdefault or whatever was set in set_data(). 469 $value = $this->_findValue($caller->_constantValues); 470 if (null === $value) { 471 if ($caller->isSubmitted() && $this->_findValue($caller->_submitValues) !== null) { 472 // Submitted values are array, one value for each individual element in this group. 473 // When there is submitted data let parent::onQuickFormEvent() process it. 474 break; 475 } 476 $value = $this->_findValue($caller->_defaultValues); 477 } 478 479 if (!is_null($value) && !is_scalar($value)) { 480 // Something unexpected (likely an array of subelement values) has been given - this will be dealt 481 // with somewhere else - where exactly... likely the subelements. 482 debugging('An invalid value (type '.gettype($value).') has arrived at '.__METHOD__, DEBUG_DEVELOPER); 483 break; 484 } 485 486 // Set element state for existing data. 487 // This is really a pretty hacky thing to do, when data is being set the group element is called 488 // with the data first and the subelements called afterwards. 489 // This means that the subelements data (inc const and default values) can be overridden by form code. 490 // So - when we call this code really we can't be sure that will be the end value for the element. 491 if (!empty($this->_elements)) { 492 if (!empty($value)) { 493 if ($value < 0) { 494 $this->gradetypeformelement->setValue('scale'); 495 $this->scaleformelement->setValue(($value * -1)); 496 } else if ($value > 0) { 497 $this->gradetypeformelement->setValue('point'); 498 $this->maxgradeformelement->setValue($value); 499 } 500 } else { 501 $this->gradetypeformelement->setValue('none'); 502 $this->maxgradeformelement->setValue(''); 503 } 504 } 505 break; 506 } 507 508 // Always let the parent do its thing! 509 return parent::onQuickFormEvent($event, $arg, $caller); 510 } 511 512 /** 513 * Generates the id attribute for the subelement of the modgrade group. 514 * 515 * Uses algorithm similar to what {@link HTML_QuickForm_element::_generateId()} 516 * does but takes the name of the wrapping modgrade group into account. 517 * 518 * @param string $subname the name of the HTML_QuickForm_element in this modgrade group 519 * @return string 520 */ 521 protected function generate_modgrade_subelement_id($subname) { 522 $gid = str_replace(array('[', ']'), array('_', ''), $this->getName()); 523 return clean_param('id_'.$gid.'_'.$subname, PARAM_ALPHANUMEXT); 524 } 525 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |