MDL-16223, MDL-16222 - error string improvements
[moodle.git] / course / moodleform_mod.php
CommitLineData
e24b7f85 1<?php
2require_once ($CFG->libdir.'/formslib.php');
3/**
4 * This class adds extra methods to form wrapper specific to be used for module
7cac0c4b 5 * add / update forms (mod/{modname}.mod_form.php replaces deprecated mod/{modname}/mod_form.php
e24b7f85 6 *
7 */
8class moodleform_mod extends moodleform {
9 /**
10 * Instance of the module that is being updated. This is the id of the {prefix}{modulename}
11 * record. Can be used in form definition. Will be "" if this is an 'add' form and not an
12 * update one.
13 *
14 * @var mixed
15 */
16 var $_instance;
17 /**
18 * Section of course that module instance will be put in or is in.
24f41672 19 * This is always the section number itself (column 'section' from 'course_sections' table).
e24b7f85 20 *
21 * @var mixed
22 */
23 var $_section;
24 /**
25 * Coursemodle record of the module that is being updated. Will be null if this is an 'add' form and not an
26 * update one.
27 *
28 * @var mixed
29 */
30 var $_cm;
4b86bb08 31 /**
32 * List of modform features
33 */
34 var $_features;
4e781c7b 35
36 /**
37 * @var array Custom completion-rule elements, if enabled
38 */
39 var $_customcompletionelements;
e24b7f85 40
41 function moodleform_mod($instance, $section, $cm) {
42 $this->_instance = $instance;
43 $this->_section = $section;
44 $this->_cm = $cm;
45 parent::moodleform('modedit.php');
46 }
71ee4471 47
e24b7f85 48 /**
a7f7e52f 49 * Only available on moodleform_mod.
e24b7f85 50 *
51 * @param array $default_values passed by reference
52 */
a7f7e52f 53 function data_preprocessing(&$default_values){
e24b7f85 54 }
71ee4471 55
4b86bb08 56 /**
57 * Each module which defines definition_after_data() must call this method using parent::definition_after_data();
58 */
71ee4471 59 function definition_after_data() {
4b86bb08 60 global $CFG, $COURSE;
71ee4471 61 $mform =& $this->_form;
62
63 if ($id = $mform->getElementValue('update')) {
64 $modulename = $mform->getElementValue('modulename');
65 $instance = $mform->getElementValue('instance');
66
4b86bb08 67 if ($this->_features->gradecat) {
68 $gradecat = false;
69 if (!empty($CFG->enableoutcomes) and $this->_features->outcomes) {
70 if ($outcomes = grade_outcome::fetch_all_available($COURSE->id)) {
71 $gradecat = true;
72 }
73 }
74 if ($items = grade_item::fetch_all(array('itemtype'=>'mod', 'itemmodule'=>$modulename,
75 'iteminstance'=>$instance, 'courseid'=>$COURSE->id))) {
76 foreach ($items as $item) {
77 if (!empty($item->outcomeid)) {
78 $elname = 'outcome_'.$item->outcomeid;
79 if ($mform->elementExists($elname)) {
80 $mform->hardFreeze($elname); // prevent removing of existing outcomes
81 }
82 }
83 }
84 foreach ($items as $item) {
85 if (is_bool($gradecat)) {
86 $gradecat = $item->categoryid;
87 continue;
71ee4471 88 }
4b86bb08 89 if ($gradecat != $item->categoryid) {
90 //mixed categories
91 $gradecat = false;
92 break;
93 }
94 }
95 }
96
97 if ($gradecat === false) {
98 // items and outcomes in different categories - remove the option
99 // TODO: it might be better to add a "Mixed categories" text instead
100 if ($mform->elementExists('gradecat')) {
101 $mform->removeElement('gradecat');
71ee4471 102 }
103 }
104 }
105 }
24f41672 106
a78890d5 107 if ($COURSE->groupmodeforce) {
108 if ($mform->elementExists('groupmode')) {
24f41672 109 $mform->hardFreeze('groupmode'); // groupmode can not be changed if forced from course settings
110 }
111 }
a104debf 112
f2fdc8eb 113 if ($mform->elementExists('groupmode') and !$mform->elementExists('groupmembersonly') and empty($COURSE->groupmodeforce)) {
114 $mform->disabledIf('groupingid', 'groupmode', 'eq', NOGROUPS);
115
116 } else if (!$mform->elementExists('groupmode') and $mform->elementExists('groupmembersonly')) {
117 $mform->disabledIf('groupingid', 'groupmembersonly', 'notchecked');
4b86bb08 118
f2fdc8eb 119 } else if (!$mform->elementExists('groupmode') and !$mform->elementExists('groupmembersonly')) {
120 // groupings have no use without groupmode or groupmembersonly
a104debf 121 if ($mform->elementExists('groupingid')) {
122 $mform->removeElement('groupingid');
123 }
124 }
4e781c7b 125
126 // Completion: If necessary, freeze fields
127 $completion=new completion_info($COURSE);
128 if($completion->is_enabled()) {
129 // If anybody has completed the activity, these options will be 'locked'
130 $completedcount = empty($this->_cm)
131 ? 0
132 : $completion->count_user_data($this->_cm);
133
134 $freeze=false;
135 if(!$completedcount) {
136 if($mform->elementExists('unlockcompletion')) {
137 $mform->removeElement('unlockcompletion');
138 }
139 } else {
140 // Has the element been unlocked?
141 if($mform->exportValue('unlockcompletion')) {
142 // Yes, add in warning text and set the hidden variable
143 $mform->insertElementBefore(
144 $mform->createElement('static','completedunlocked',
145 get_string('completedunlocked','completion'),
146 get_string('completedunlockedtext','completion')),
147 'unlockcompletion');
148 $mform->removeElement('unlockcompletion');
149 $mform->getElement('completionunlocked')->setValue(1);
150 } else {
151 // No, add in the warning text with the count (now we know
152 // it) before the unlock button
153 $mform->insertElementBefore(
154 $mform->createElement('static','completedwarning',
155 get_string('completedwarning','completion'),
156 get_string('completedwarningtext','completion',$completedcount)),
157 'unlockcompletion');
158 $mform->setHelpButton('completedwarning', array('completionlocked', get_string('help_completionlocked', 'completion'), 'completion'));
159
160 $freeze=true;
161 }
162 }
163
164 if($freeze) {
165 $mform->freeze('completion');
166 if($mform->elementExists('completionview')) {
167 $mform->freeze('completionview'); // don't use hardFreeze or checkbox value gets lost
168 }
169 if($mform->elementExists('completionusegrade')) {
170 $mform->freeze('completionusegrade');
171 }
172 $mform->freeze($this->_customcompletionelements);
173 }
174 }
71ee4471 175 }
176
60243313 177 // form verification
a78890d5 178 function validation($data, $files) {
32648682 179 global $COURSE, $DB;
a78890d5 180 $errors = parent::validation($data, $files);
60243313 181
273eb2f5 182 $mform =& $this->_form;
183
60243313 184 $errors = array();
185
273eb2f5 186 if ($mform->elementExists('name')) {
187 $name = trim($data['name']);
188 if ($name == '') {
189 $errors['name'] = get_string('required');
190 }
e04ff2d5 191 }
192
60243313 193 $grade_item = grade_item::fetch(array('itemtype'=>'mod', 'itemmodule'=>$data['modulename'],
194 'iteminstance'=>$data['instance'], 'itemnumber'=>0, 'courseid'=>$COURSE->id));
195 if ($data['coursemodule']) {
32648682 196 $cm = $DB->get_record('course_modules', array('id'=>$data['coursemodule']));
60243313 197 } else {
198 $cm = null;
199 }
200
273eb2f5 201 if ($mform->elementExists('cmidnumber')) {
202 // verify the idnumber
204175c5 203 if (!grade_verify_idnumber($data['cmidnumber'], $COURSE->id, $grade_item, $cm)) {
273eb2f5 204 $errors['cmidnumber'] = get_string('idnumbertaken');
205 }
60243313 206 }
4e781c7b 207
208 // Completion: Don't let them choose automatic completion without turning
209 // on some conditions
210 if(array_key_exists('completion',$data) && $data['completion']==COMPLETION_TRACKING_AUTOMATIC) {
211 if(empty($data['completionview']) && empty($data['completionusegrade']) &&
212 !$this->completion_rule_enabled($data)) {
213 $errors['completion']=get_string('badautocompletion','completion');
214 }
215 }
60243313 216
a78890d5 217 return $errors;
60243313 218 }
219
e24b7f85 220 /**
221 * Load in existing data as form defaults. Usually new entry defaults are stored directly in
222 * form definition (new entry form); this function is used to load in data where values
223 * already exist and data is being edited (edit entry form).
224 *
225 * @param mixed $default_values object or array of default values
226 */
32db0d42 227 function set_data($default_values) {
e24b7f85 228 if (is_object($default_values)) {
229 $default_values = (array)$default_values;
230 }
ab6803a9 231 $this->data_preprocessing($default_values);
24f41672 232 parent::set_data($default_values); //never slashed for moodleform_mod
e24b7f85 233 }
71ee4471 234
e24b7f85 235 /**
236 * Adds all the standard elements to a form to edit the settings for an activity module.
237 *
4e781c7b 238 * @param mixed $features array or object describing supported features - groups, groupings, groupmembersonly, etc.
239 * @param string $modname Name of module e.g. 'label'
e24b7f85 240 */
4e781c7b 241 function standard_coursemodule_elements($features=null,$modname=null){
c18269c7 242 global $COURSE, $CFG, $DB;
e24b7f85 243 $mform =& $this->_form;
f3b783f4 244
4e781c7b 245 // Guess module name if not supplied
246 if(!$modname) {
247 $matches=array();
248 if(!preg_match('/^mod_([^_]+)_mod_form$/',$this->_formname,$matches)) {
249 debugging('Use $modname parameter or rename form to mod_xx_mod_form, where xx is name of your module');
250 error('Unknown module name for form');
251 }
252 $modname=$matches[1];
253 }
254
e04ff2d5 255 // deal with legacy $supportgroups param
256 if ($features === true or $features === false) {
257 $groupmode = $features;
4b86bb08 258 $this->_features = new object();
259 $this->_features->groups = $groupmode;
e04ff2d5 260
261 } else if (is_array($features)) {
4b86bb08 262 $this->_features = (object)$features;
e04ff2d5 263
264 } else if (empty($features)) {
4b86bb08 265 $this->_features = new object();
266
267 } else {
268 $this->_features = $features;
e04ff2d5 269 }
270
4b86bb08 271 if (!isset($this->_features->groups)) {
272 $this->_features->groups = true;
e04ff2d5 273 }
274
4b86bb08 275 if (!isset($this->_features->groupings)) {
276 $this->_features->groupings = false;
e04ff2d5 277 }
278
4b86bb08 279 if (!isset($this->_features->groupmembersonly)) {
280 $this->_features->groupmembersonly = false;
e04ff2d5 281 }
282
4b86bb08 283 if (!isset($this->_features->outcomes)) {
284 $this->_features->outcomes = true;
285 }
286
287 if (!isset($this->_features->gradecat)) {
288 $this->_features->gradecat = true;
289 }
290
b5ab55dd 291 if (!isset($this->_features->idnumber)) {
292 $this->_features->idnumber = true;
293 }
4e781c7b 294
295 if(!isset($this->_features->defaultcompletion)) {
296 $this->_features->defaultcompletion = true;
297 }
b5ab55dd 298
299 $outcomesused = false;
4b86bb08 300 if (!empty($CFG->enableoutcomes) and $this->_features->outcomes) {
f3b783f4 301 if ($outcomes = grade_outcome::fetch_all_available($COURSE->id)) {
b5ab55dd 302 $outcomesused = true;
f3b783f4 303 $mform->addElement('header', 'modoutcomes', get_string('outcomes', 'grades'));
304 foreach($outcomes as $outcome) {
305 $mform->addElement('advcheckbox', 'outcome_'.$outcome->id, $outcome->get_name());
306 }
307 }
308 }
309
24e25bc1 310 $mform->addElement('header', 'modstandardelshdr', get_string('modstandardels', 'form'));
4b86bb08 311 if ($this->_features->groups) {
a78890d5 312 $options = array(NOGROUPS => get_string('groupsnone'),
313 SEPARATEGROUPS => get_string('groupsseparate'),
314 VISIBLEGROUPS => get_string('groupsvisible'));
315 $mform->addElement('select', 'groupmode', get_string('groupmode'), $options, NOGROUPS);
316 $mform->setHelpButton('groupmode', array('groupmode', get_string('groupmode')));
e24b7f85 317 }
24f41672 318
319 if (!empty($CFG->enablegroupings)) {
4b86bb08 320 if ($this->_features->groupings or $this->_features->groupmembersonly) {
e04ff2d5 321 //groupings selector - used for normal grouping mode or also when restricting access with groupmembersonly
322 $options = array();
323 $options[0] = get_string('none');
c18269c7 324 if ($groupings = $DB->get_records('groupings', array('courseid'=>$COURSE->id))) {
e04ff2d5 325 foreach ($groupings as $grouping) {
326 $options[$grouping->id] = format_string($grouping->name);
327 }
24f41672 328 }
e04ff2d5 329 $mform->addElement('select', 'groupingid', get_string('grouping', 'group'), $options);
330 $mform->setAdvanced('groupingid');
24f41672 331 }
e04ff2d5 332
4b86bb08 333 if ($this->_features->groupmembersonly) {
f2fdc8eb 334 $mform->addElement('checkbox', 'groupmembersonly', get_string('groupmembersonly', 'group'));
a104debf 335 $mform->setAdvanced('groupmembersonly');
336 }
24f41672 337 }
338
e24b7f85 339 $mform->addElement('modvisible', 'visible', get_string('visible'));
b5ab55dd 340
341 if ($this->_features->idnumber) {
342 $mform->addElement('text', 'cmidnumber', get_string('idnumbermod'));
343 $mform->setHelpButton('cmidnumber', array('cmidnumber', get_string('idnumbermod')), true);
344 }
71ee4471 345
4b86bb08 346 if ($this->_features->gradecat) {
57956368 347 $categories = grade_get_categories_menu($COURSE->id, $outcomesused);
4b86bb08 348 $mform->addElement('select', 'gradecat', get_string('gradecategory', 'grades'), $categories);
349 }
350
4e781c7b 351 // Conditional activities: completion tracking section
352 require_once($CFG->libdir.'/completionlib.php');
353 $completion=new completion_info($COURSE);
354 if($completion->is_enabled()) {
355 $mform->addElement('header', '', get_string('activitycompletion', 'completion'));
356
357 // Unlock button for if people have completed it (will
358 // be removed in definition_after_data if they haven't)
359 $mform->addElement('submit','unlockcompletion',get_string('unlockcompletion','completion'));
360 $mform->registerNoSubmitButton('unlockcompletion');
361 $mform->addElement('hidden','completionunlocked',0);
362
363 $mform->addElement('select', 'completion', get_string('completion','completion'),
364 array(COMPLETION_TRACKING_NONE=>get_string('completion_none','completion'),
365 COMPLETION_TRACKING_MANUAL=>get_string('completion_manual','completion')));
366 $mform->setHelpButton('completion', array('completion', get_string('help_completion', 'completion'), 'completion'));
367 $mform->setDefault('completion',$this->_features->defaultcompletion
368 ? COMPLETION_TRACKING_MANUAL
369 : COMPLETION_TRACKING_NONE);
370
371 // Automatic completion once you view it
372 $gotcompletionoptions=false;
373 if(plugin_supports('mod',$modname,FEATURE_COMPLETION_TRACKS_VIEWS)) {
374 $mform->addElement('checkbox', 'completionview', get_string('completionview','completion'),
375 get_string('completionview_text','completion'));
376 $mform->setHelpButton('completionview', array('completionview', get_string('help_completionview', 'completion'), 'completion'));
377 $mform->disabledIf('completionview','completion','ne',COMPLETION_TRACKING_AUTOMATIC);
378 $gotcompletionoptions=true;
379 }
380
381 // Automatic completion once it's graded
382 if(plugin_supports('mod',$modname,FEATURE_GRADE_HAS_GRADE)) {
383 $mform->addElement('checkbox', 'completionusegrade', get_string('completionusegrade','completion'),
384 get_string('completionusegrade_text','completion'));
385 $mform->setHelpButton('completionusegrade', array('completionusegrade', get_string('help_completionusegrade', 'completion'), 'completion'));
386 $mform->disabledIf('completionusegrade','completion','ne',COMPLETION_TRACKING_AUTOMATIC);
387 $gotcompletionoptions=true;
388 }
389
390 // Automatic completion according to module-specific rules
391 $this->_customcompletionelements = $this->add_completion_rules();
392 foreach($this->_customcompletionelements as $element) {
393 $mform->disabledIf($element,'completion','ne',COMPLETION_TRACKING_AUTOMATIC);
394 }
395
396 $gotcompletionoptions = $gotcompletionoptions ||
397 count($this->_customcompletionelements)>0;
398
399 // Automatic option only appears if possible
400 if($gotcompletionoptions) {
401 $mform->getElement('completion')->addOption(
402 get_string('completion_automatic','completion'),
403 COMPLETION_TRACKING_AUTOMATIC);
404 }
405
406 // Completion expected at particular date? (For progress tracking)
407 $mform->addElement('date_selector', 'completionexpected', get_string('completionexpected','completion'), array('optional'=>true));
408 $mform->setHelpButton('completionexpected', array('completionexpected', get_string('help_completionexpected', 'completion'), 'completion'));
409 $mform->disabledIf('completionexpected','completion','eq',COMPLETION_TRACKING_NONE);
410 }
411
e24b7f85 412 $this->standard_hidden_coursemodule_elements();
413 }
4e781c7b 414
415 /**
416 * Can be overridden to add custom completion rules if the module wishes
417 * them. If overriding this, you should also override completion_rule_enabled.
418 * <p>
419 * Just add elements to the form as needed and return the list of IDs. The
420 * system will call disabledIf and handle other behaviour for each returned
421 * ID.
422 * @return array Array of string IDs of added items, empty array if none
423 */
424 function add_completion_rules() {
425 return array();
426 }
427
428 /**
429 * Called during validation. Override to indicate, based on the data, whether
430 * a custom completion rule is enabled (selected).
431 *
432 * @param array $data Input data (not yet validated)
433 * @return bool True if one or more rules is enabled, false if none are;
434 * default returns false
435 */
436 function completion_rule_enabled(&$data) {
437 return false;
438 }
e24b7f85 439
440 function standard_hidden_coursemodule_elements(){
441 $mform =& $this->_form;
442 $mform->addElement('hidden', 'course', 0);
443 $mform->setType('course', PARAM_INT);
444
445 $mform->addElement('hidden', 'coursemodule', 0);
446 $mform->setType('coursemodule', PARAM_INT);
447
448 $mform->addElement('hidden', 'section', 0);
449 $mform->setType('section', PARAM_INT);
450
451 $mform->addElement('hidden', 'module', 0);
452 $mform->setType('module', PARAM_INT);
453
454 $mform->addElement('hidden', 'modulename', '');
455 $mform->setType('modulename', PARAM_SAFEDIR);
456
457 $mform->addElement('hidden', 'instance', 0);
458 $mform->setType('instance', PARAM_INT);
459
460 $mform->addElement('hidden', 'add', 0);
461 $mform->setType('add', PARAM_ALPHA);
462
463 $mform->addElement('hidden', 'update', 0);
464 $mform->setType('update', PARAM_INT);
19110c57 465
466 $mform->addElement('hidden', 'return', 0);
467 $mform->setType('return', PARAM_BOOL);
e24b7f85 468 }
469
6b467109 470 /**
471 * Overriding formslib's add_action_buttons() method, to add an extra submit "save changes and return" button.
b5ab55dd 472 *
473 * @param bool $cancel show cancel button
474 * @param string $submitlabel null means default, false means none, string is label text
475 * @param string $submit2label null means default, false means none, string is label text
6b467109 476 * @return void
b5ab55dd 477 */
6b467109 478 function add_action_buttons($cancel=true, $submitlabel=null, $submit2label=null) {
479 if (is_null($submitlabel)) {
480 $submitlabel = get_string('savechangesanddisplay');
481 }
b5ab55dd 482
6b467109 483 if (is_null($submit2label)) {
484 $submit2label = get_string('savechangesandreturntocourse');
485 }
b5ab55dd 486
6b467109 487 $mform =& $this->_form;
b5ab55dd 488
489 // elements in a row need a group
490 $buttonarray = array();
491
492 if ($submit2label !== false) {
493 $buttonarray[] = &$mform->createElement('submit', 'submitbutton2', $submit2label);
494 }
495
496 if ($submitlabel !== false) {
497 $buttonarray[] = &$mform->createElement('submit', 'submitbutton', $submitlabel);
498 }
499
6b467109 500 if ($cancel) {
501 $buttonarray[] = &$mform->createElement('cancel');
502 }
503
504 $mform->addGroup($buttonarray, 'buttonar', '', array(' '), false);
de6f158f 505 $mform->setType('buttonar', PARAM_RAW);
6b467109 506 $mform->closeHeaderBefore('buttonar');
507 }
e24b7f85 508}
509
f3b783f4 510?>