Skip to content

Commit

Permalink
MDL-44070 Conditional availability enhancements (7): forms
Browse files Browse the repository at this point in the history
Changes to the module and section editing forms to use the new
fields and JavaScript.
  • Loading branch information
sammarshallou committed Apr 7, 2014
1 parent 8d1f33e commit 400c0fd
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 462 deletions.
22 changes: 15 additions & 7 deletions course/editsection.php
Expand Up @@ -49,25 +49,33 @@
array('cs' => $sectioninfo, 'editoroptions' => $editoroptions));
// set current value, make an editable copy of section_info object
// this will retrieve all format-specific options as well
$mform->set_data(convert_to_array($sectioninfo));
$initialdata = convert_to_array($sectioninfo);
if (!empty($CFG->enableavailability)) {
$initialdata['availabilityconditionsjson'] = $sectioninfo->availability;
}
$mform->set_data($initialdata);

if ($mform->is_cancelled()){
// Form cancelled, return to course.
redirect(course_get_url($course, $section, array('sr' => $sectionreturn)));
} else if ($data = $mform->get_data()) {
// Data submitted and validated, update and return to course.

// For consistency, we set the availability field to 'null' if it is empty.
if (!empty($CFG->enableavailability)) {
// Renamed field.
$data->availability = $data->availabilityconditionsjson;
unset($data->availabilityconditionsjson);
if ($data->availability === '') {
$data->availability = null;
}
}
$DB->update_record('course_sections', $data);
rebuild_course_cache($course->id, true);
if (isset($data->section)) {
// Usually edit form does not change relative section number but just in case.
$sectionnum = $data->section;
}
if (!empty($CFG->enableavailability)) {
// Update grade and completion conditions.
$sectioninfo = get_fast_modinfo($course)->get_section_info($sectionnum);
condition_info_section::update_section_from_form($sectioninfo, $data);
rebuild_course_cache($course->id, true);
}
course_get_format($course->id)->update_section_format_options($data);

// Set section info, as this might not be present in form_data.
Expand Down
249 changes: 21 additions & 228 deletions course/editsection_form.php
Expand Up @@ -60,241 +60,22 @@ public function definition_after_data() {
$context = context_course::instance($course->id);

if (!empty($CFG->enableavailability)) {
$mform->addElement('header', 'availabilityconditions', get_string('availabilityconditions', 'condition'));
$mform->addElement('header', 'availabilityconditions',
get_string('restrictaccess', 'availability'));
$mform->setExpanded('availabilityconditions', false);
// String used by conditions more than once
$strcondnone = get_string('none', 'condition');
// Grouping conditions - only if grouping is enabled at site level
if (!empty($CFG->enablegroupmembersonly)) {
$options = array();
if ($groupings = $DB->get_records('groupings', array('courseid' => $course->id))) {
foreach ($groupings as $grouping) {
$options[$grouping->id] = format_string(
$grouping->name, true, array('context' => $context));
}
}
core_collator::asort($options);
$options = array(0 => get_string('none')) + $options;
$mform->addElement('select', 'groupingid', get_string('groupingsection', 'group'), $options);
$mform->addHelpButton('groupingid', 'groupingsection', 'group');
}

// Available from/to defaults to midnight because then the display
// will be nicer where it tells users when they can access it (it
// shows only the date and not time).
$date = usergetdate(time());
$midnight = make_timestamp($date['year'], $date['mon'], $date['mday']);

// Date and time conditions.
$mform->addElement('date_time_selector', 'availablefrom',
get_string('availablefrom', 'condition'),
array('optional' => true, 'defaulttime' => $midnight));
$mform->addElement('date_time_selector', 'availableuntil',
get_string('availableuntil', 'condition'),
array('optional' => true, 'defaulttime' => $midnight));

// Conditions based on grades
$gradeoptions = array();
$items = grade_item::fetch_all(array('courseid' => $course->id));
$items = $items ? $items : array();
foreach ($items as $id => $item) {
$gradeoptions[$id] = $item->get_name();
}
asort($gradeoptions);
$gradeoptions = array(0 => $strcondnone) + $gradeoptions;

$grouparray = array();
$grouparray[] = $mform->createElement('select', 'conditiongradeitemid', '', $gradeoptions);
$grouparray[] = $mform->createElement('static', '', '',
' ' . get_string('grade_atleast', 'condition').' ');
$grouparray[] = $mform->createElement('text', 'conditiongrademin', '', array('size' => 3));
$grouparray[] = $mform->createElement('static', '', '',
'% ' . get_string('grade_upto', 'condition') . ' ');
$grouparray[] = $mform->createElement('text', 'conditiongrademax', '', array('size' => 3));
$grouparray[] = $mform->createElement('static', '', '', '%');
$group = $mform->createElement('group', 'conditiongradegroup',
get_string('gradecondition', 'condition'), $grouparray);

// Get full version (including condition info) of section object
$ci = new condition_info_section($this->_customdata['cs']);
$fullcs = $ci->get_full_section();
$count = count($fullcs->conditionsgrade) + 1;

// Grade conditions
$this->repeat_elements(array($group), $count, array(
'conditiongradegroup[conditiongrademin]' => array('type' => PARAM_RAW),
'conditiongradegroup[conditiongrademax]' => array('type' => PARAM_RAW)
), 'conditiongraderepeats', 'conditiongradeadds', 2, get_string('addgrades', 'condition'), true);
$mform->addHelpButton('conditiongradegroup[0]', 'gradecondition', 'condition');

// Conditions based on user fields
$operators = condition_info::get_condition_user_field_operators();
$useroptions = condition_info::get_condition_user_fields(array('context' => $context));
asort($useroptions);

$useroptions = array(0 => $strcondnone) + $useroptions;
$grouparray = array();
$grouparray[] =& $mform->createElement('select', 'conditionfield', '', $useroptions);
$grouparray[] =& $mform->createElement('select', 'conditionfieldoperator', '', $operators);
$grouparray[] =& $mform->createElement('text', 'conditionfieldvalue');
$group = $mform->createElement('group', 'conditionfieldgroup', get_string('userfield', 'condition'), $grouparray);

$fieldcount = count($fullcs->conditionsfield) + 1;

$this->repeat_elements(array($group), $fieldcount, array(
'conditionfieldgroup[conditionfieldvalue]' => array('type' => PARAM_RAW)),
'conditionfieldrepeats', 'conditionfieldadds', 2, get_string('adduserfields', 'condition'), true);
$mform->addHelpButton('conditionfieldgroup[0]', 'userfield', 'condition');

// Conditions based on completion
$completion = new completion_info($course);
if ($completion->is_enabled()) {
$completionoptions = array();
$modinfo = get_fast_modinfo($course);
foreach ($modinfo->cms as $id => $cm) {
// Add each course-module if it:
// (a) has completion turned on
// (b) does not belong to current course-section
if ($cm->completion && ($fullcs->id != $cm->section)) {
$completionoptions[$id] = $cm->name;
}
}
asort($completionoptions);
$completionoptions = array(0 => $strcondnone) +
$completionoptions;

$completionvalues = array(
COMPLETION_COMPLETE => get_string('completion_complete', 'condition'),
COMPLETION_INCOMPLETE => get_string('completion_incomplete', 'condition'),
COMPLETION_COMPLETE_PASS => get_string('completion_pass', 'condition'),
COMPLETION_COMPLETE_FAIL => get_string('completion_fail', 'condition'));

$grouparray = array();
$grouparray[] = $mform->createElement('select', 'conditionsourcecmid', '',
$completionoptions);
$grouparray[] = $mform->createElement('select', 'conditionrequiredcompletion', '',
$completionvalues);
$group = $mform->createElement('group', 'conditioncompletiongroup',
get_string('completioncondition', 'condition'), $grouparray);

$count = count($fullcs->conditionscompletion) + 1;
$this->repeat_elements(array($group), $count, array(),
'conditioncompletionrepeats', 'conditioncompletionadds', 2,
get_string('addcompletions', 'condition'), true);
$mform->addHelpButton('conditioncompletiongroup[0]',
'completionconditionsection', 'condition');
}

// Availability conditions - set up form values
if (!empty($CFG->enableavailability)) {
$num = 0;
foreach ($fullcs->conditionsgrade as $gradeitemid => $minmax) {
$groupelements = $mform->getElement(
'conditiongradegroup[' . $num . ']')->getElements();
$groupelements[0]->setValue($gradeitemid);
$groupelements[2]->setValue(is_null($minmax->min) ? '' :
format_float($minmax->min, 5, true, true));
$groupelements[4]->setValue(is_null($minmax->max) ? '' :
format_float($minmax->max, 5, true, true));
$num++;
}

$num = 0;
foreach ($fullcs->conditionsfield as $fieldid => $data) {
$groupelements = $mform->getElement(
'conditionfieldgroup[' . $num . ']')->getElements();
$groupelements[0]->setValue($fieldid);
$groupelements[1]->setValue(is_null($data->operator) ? '' :
$data->operator);
$groupelements[2]->setValue(is_null($data->value) ? '' :
$data->value);
$num++;
}

if ($completion->is_enabled()) {
$num = 0;
foreach ($fullcs->conditionscompletion as $othercmid => $state) {
$groupelements = $mform->getElement('conditioncompletiongroup[' . $num . ']')->getElements();
$groupelements[0]->setValue($othercmid);
$groupelements[1]->setValue($state);
$num++;
}
}
}

// Do we display availability info to students?
$showhide = array(
CONDITION_STUDENTVIEW_SHOW => get_string('showavailabilitysection_show', 'condition'),
CONDITION_STUDENTVIEW_HIDE => get_string('showavailabilitysection_hide', 'condition'));
$mform->addElement('select', 'showavailability',
get_string('showavailabilitysection', 'condition'), $showhide);
// Availability field. This is just a textarea; the user interface
// interaction is all implemented in JavaScript. The field is named
// availabilityconditionsjson for consistency with moodleform_mod.
$mform->addElement('textarea', 'availabilityconditionsjson',
get_string('accessrestrictions', 'availability'));
\core_availability\frontend::include_all_javascript($course, null,
$this->_customdata['cs']);
}

$this->add_action_buttons();
}

public function validation($data, $files) {
$errors = parent::validation($data, $files);
// Conditions: Don't let them set dates which make no sense
if (array_key_exists('availablefrom', $data) &&
$data['availablefrom'] && $data['availableuntil'] &&
$data['availablefrom'] >= $data['availableuntil']) {
$errors['availablefrom'] = get_string('badavailabledates', 'condition');
}

// Conditions: Verify that the grade conditions are numbers, and make sense.
if (array_key_exists('conditiongradegroup', $data)) {
foreach ($data['conditiongradegroup'] as $i => $gradedata) {
if ($gradedata['conditiongrademin'] !== '' &&
!is_numeric(unformat_float($gradedata['conditiongrademin']))) {
$errors["conditiongradegroup[{$i}]"] = get_string('gradesmustbenumeric', 'condition');
continue;
}
if ($gradedata['conditiongrademax'] !== '' &&
!is_numeric(unformat_float($gradedata['conditiongrademax']))) {
$errors["conditiongradegroup[{$i}]"] = get_string('gradesmustbenumeric', 'condition');
continue;
}
if ($gradedata['conditiongrademin'] !== '' && $gradedata['conditiongrademax'] !== '' &&
unformat_float($gradedata['conditiongrademax']) <= unformat_float($gradedata['conditiongrademin'])) {
$errors["conditiongradegroup[{$i}]"] = get_string('badgradelimits', 'condition');
continue;
}
if ($gradedata['conditiongrademin'] === '' && $gradedata['conditiongrademax'] === '' &&
$gradedata['conditiongradeitemid']) {
$errors["conditiongradegroup[{$i}]"] = get_string('gradeitembutnolimits', 'condition');
continue;
}
if (($gradedata['conditiongrademin'] !== '' || $gradedata['conditiongrademax'] !== '') &&
!$gradedata['conditiongradeitemid']) {
$errors["conditiongradegroup[{$i}]"] = get_string('gradelimitsbutnoitem', 'condition');
continue;
}
}
}

// Conditions: Verify that the user profile field has not been declared more than once
if (array_key_exists('conditionfieldgroup', $data)) {
// Array to store the existing fields
$arrcurrentfields = array();
// Error message displayed if any condition is declared more than once. We use lang string because
// this way we don't actually generate the string unless there is an error.
$stralreadydeclaredwarning = new lang_string('fielddeclaredmultipletimes', 'condition');
foreach ($data['conditionfieldgroup'] as $i => $fielddata) {
if ($fielddata['conditionfield'] == 0) { // Don't need to bother if none is selected
continue;
}
if (in_array($fielddata['conditionfield'], $arrcurrentfields)) {
$errors["conditionfieldgroup[{$i}]"] = $stralreadydeclaredwarning->out();
}
// Add the field to the array
$arrcurrentfields[] = $fielddata['conditionfield'];
}
}

return $errors;
}

/**
* Load in existing data as form defaults
*
Expand Down Expand Up @@ -337,4 +118,16 @@ function get_data() {
}
return $data;
}

public function validation($data, $files) {
global $CFG;
$errors = array();

// Availability: Check availability field does not have errors.
if (!empty($CFG->enableavailability)) {
\core_availability\frontend::report_validation_errors($data, $errors);
}

return $errors;
}
}
4 changes: 1 addition & 3 deletions course/modedit.php
Expand Up @@ -160,9 +160,7 @@
$data->completionusegrade = is_null($cm->completiongradeitemnumber) ? 0 : 1;
$data->showdescription = $cm->showdescription;
if (!empty($CFG->enableavailability)) {
$data->availablefrom = $cm->availablefrom;
$data->availableuntil = $cm->availableuntil;
$data->showavailability = $cm->showavailability;
$data->availabilityconditionsjson = $cm->availability;
}

if (plugin_supports('mod', $data->modulename, FEATURE_MOD_INTRO, true)) {
Expand Down
35 changes: 23 additions & 12 deletions course/modlib.php
Expand Up @@ -75,9 +75,17 @@ function add_moduleinfo($moduleinfo, $course, $mform = null) {
$newcm->completionexpected = $moduleinfo->completionexpected;
}
if(!empty($CFG->enableavailability)) {
$newcm->availablefrom = $moduleinfo->availablefrom;
$newcm->availableuntil = $moduleinfo->availableuntil;
$newcm->showavailability = $moduleinfo->showavailability;
// This code is used both when submitting the form, which uses a long
// name to avoid clashes, and by unit test code which uses the real
// name in the table.
$newcm->availability = null;
if (property_exists($moduleinfo, 'availabilityconditionsjson')) {
if ($moduleinfo->availabilityconditionsjson !== '') {
$newcm->availability = $moduleinfo->availabilityconditionsjson;
}
} else if (property_exists($moduleinfo, 'availability')) {
$newcm->availability = $moduleinfo->availability;
}
}
if (isset($moduleinfo->showdescription)) {
$newcm->showdescription = $moduleinfo->showdescription;
Expand Down Expand Up @@ -139,11 +147,6 @@ function add_moduleinfo($moduleinfo, $course, $mform = null) {
// So we have to update one of them twice.
$sectionid = course_add_cm_to_section($course, $moduleinfo->coursemodule, $moduleinfo->section);

// Set up conditions.
if ($CFG->enableavailability) {
condition_info::update_cm_from_form((object)array('id'=>$moduleinfo->coursemodule), $moduleinfo, false);
}

// Trigger event based on the action we did.
$event = \core\event\course_module_created::create(array(
'courseid' => $course->id,
Expand Down Expand Up @@ -473,10 +476,18 @@ function update_moduleinfo($cm, $moduleinfo, $course, $mform = null) {
$cm->completionexpected = $moduleinfo->completionexpected;
}
if (!empty($CFG->enableavailability)) {
$cm->availablefrom = $moduleinfo->availablefrom;
$cm->availableuntil = $moduleinfo->availableuntil;
$cm->showavailability = $moduleinfo->showavailability;
condition_info::update_cm_from_form($cm,$moduleinfo,true);
// This code is used both when submitting the form, which uses a long
// name to avoid clashes, and by unit test code which uses the real
// name in the table.
if (property_exists($moduleinfo, 'availabilityconditionsjson')) {
if ($moduleinfo->availabilityconditionsjson !== '') {
$cm->availability = $moduleinfo->availabilityconditionsjson;
} else {
$cm->availability = null;
}
} else if (property_exists($moduleinfo, 'availability')) {
$cm->availability = $moduleinfo->availability;
}
}
if (isset($moduleinfo->showdescription)) {
$cm->showdescription = $moduleinfo->showdescription;
Expand Down

0 comments on commit 400c0fd

Please sign in to comment.