From 76af15bb4c9f524497693e7fd8231e9d495c191b Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Mon, 26 Sep 2011 21:20:17 +0800 Subject: [PATCH] MDL-29538 core_condition: initial commit to add support for making things conditional on user profile fields --- backup/moodle2/backup_stepslib.php | 5 +- backup/moodle2/restore_stepslib.php | 21 +- course/lib.php | 1 + course/moodleform_mod.php | 35 +++- lang/en/condition.php | 4 + lib/conditionlib.php | 293 +++++++++++++++++++++++++++- lib/db/install.xml | 19 +- lib/db/upgrade.php | 16 ++ lib/modinfolib.php | 8 + lib/moodlelib.php | 3 + user/profile/definelib.php | 4 + 11 files changed, 399 insertions(+), 10 deletions(-) diff --git a/backup/moodle2/backup_stepslib.php b/backup/moodle2/backup_stepslib.php index 7169e1903c2..b3dd574919c 100644 --- a/backup/moodle2/backup_stepslib.php +++ b/backup/moodle2/backup_stepslib.php @@ -322,6 +322,8 @@ class backup_module_structure_step extends backup_structure_step { $availinfo = new backup_nested_element('availability_info'); $availability = new backup_nested_element('availability', array('id'), array( 'sourcecmid', 'requiredcompletion', 'gradeitemid', 'grademin', 'grademax')); + $availability_field = new backup_nested_element('availability_field', array('id'), array( + 'field', 'operator', 'value')); // attach format plugin structure to $module element, only one allowed $this->add_plugin_structure('format', $module, false); @@ -333,9 +335,9 @@ class backup_module_structure_step extends backup_structure_step { // Define the tree $module->add_child($availinfo); $availinfo->add_child($availability); + $availinfo->add_child($availability_field); // Set the sources - $module->set_source_sql(' SELECT cm.*, m.version, m.name AS modulename, s.id AS sectionid, s.section AS sectionnumber FROM {course_modules} cm @@ -344,6 +346,7 @@ class backup_module_structure_step extends backup_structure_step { WHERE cm.id = ?', array(backup::VAR_MODID)); $availability->set_source_table('course_modules_availability', array('coursemoduleid' => backup::VAR_MODID)); + $availability_field->set_source_table('course_modules_availability_field', array('coursemoduleid' => backup::VAR_MODID)); // Define annotations $module->annotate_ids('grouping', 'groupingid'); diff --git a/backup/moodle2/restore_stepslib.php b/backup/moodle2/restore_stepslib.php index adb3cd6b968..6e34cc551af 100644 --- a/backup/moodle2/restore_stepslib.php +++ b/backup/moodle2/restore_stepslib.php @@ -546,6 +546,14 @@ class restore_process_course_modules_availability extends restore_execution_step $DB->insert_record('course_modules_availability', $availability); } } + + // Now we need to do it for conditional field availability + $params = array('backupid' => $this->get_restoreid(), 'itemname' => 'module_availability_field'); + $rs = $DB->get_recordset('backup_ids_temp', $params, '', 'itemid'); + foreach($rs as $availrec) { + $availability = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'module_availability_field', $availrec->itemid)->info; + $DB->insert_record('course_modules_availability_field', $availability); + } $rs->close(); } } @@ -2539,6 +2547,7 @@ class restore_module_structure_step extends restore_structure_step { $paths[] = $module; if ($CFG->enableavailability) { $paths[] = new restore_path_element('availability', '/module/availability_info/availability'); + $paths[] = new restore_path_element('availability_fields', '/module/availability_info/availability_field'); } // Apply for 'format' plugins optional paths at module level @@ -2632,15 +2641,23 @@ class restore_module_structure_step extends restore_structure_step { $DB->set_field('course_sections', 'sequence', $sequence, array('id' => $data->section)); } - protected function process_availability($data) { $data = (object)$data; // Simply going to store the whole availability record now, we'll process - // all them later in the final task (once all actvivities have been restored) + // all them later in the final task (once all activities have been restored) // Let's call the low level one to be able to store the whole object $data->coursemoduleid = $this->task->get_moduleid(); // Let add the availability cmid restore_dbops::set_backup_ids_record($this->get_restoreid(), 'module_availability', $data->id, 0, null, $data); } + + protected function process_availability_fields($data) { + $data = (object)$data; + // Simply going to store the whole availability record now, we'll process + // all them later in the final task (once all activities have been restored) + // Let's call the low level one to be able to store the whole object + $data->coursemoduleid = $this->task->get_moduleid(); // Let add the availability cmid + restore_dbops::set_backup_ids_record($this->get_restoreid(), 'module_availability_field', $data->id, 0, null, $data); + } } /** diff --git a/course/lib.php b/course/lib.php index 82f2b8cb2f6..54fb37d0268 100644 --- a/course/lib.php +++ b/course/lib.php @@ -1111,6 +1111,7 @@ function get_array_of_activities($courseid) { condition_info::fill_availability_conditions($rawmods[$seq]); $mod[$seq]->conditionscompletion = $rawmods[$seq]->conditionscompletion; $mod[$seq]->conditionsgrade = $rawmods[$seq]->conditionsgrade; + $mod[$seq]->conditionsfield = $rawmods[$seq]->conditionsfield; } $modname = $mod[$seq]->mod; diff --git a/course/moodleform_mod.php b/course/moodleform_mod.php index 292387b9dbd..37fe3b0b514 100644 --- a/course/moodleform_mod.php +++ b/course/moodleform_mod.php @@ -259,6 +259,15 @@ abstract class moodleform_mod extends moodleform { $num++; } + $num=0; + foreach($fullcm->conditionsfield as $field=>$details) { + $groupelements=$mform->getElement('conditionfieldgroup['.$num.']')->getElements(); + $groupelements[0]->setValue($field); + $groupelements[1]->setValue(is_null($details->operator)?'':$details->operator); + $groupelements[2]->setValue(is_null($details->value)?'':($details->value)); + $num++; + } + if ($completion->is_enabled()) { $num=0; foreach($fullcm->conditionscompletion as $othercmid=>$state) { @@ -471,6 +480,8 @@ abstract class moodleform_mod extends moodleform { } if (!empty($CFG->enableavailability)) { + // String used by conditions + $strnone = get_string('none','condition'); // Conditional availability // Available from/to defaults to midnight because then the display @@ -504,7 +515,7 @@ abstract class moodleform_mod extends moodleform { $gradeoptions[$id] = $item->get_name(); } asort($gradeoptions); - $gradeoptions = array(0=>get_string('none','condition'))+$gradeoptions; + $gradeoptions = array(0=>$strnone)+$gradeoptions; $grouparray = array(); $grouparray[] =& $mform->createElement('select','conditiongradeitemid','',$gradeoptions); @@ -522,14 +533,34 @@ abstract class moodleform_mod extends moodleform { $ci = new condition_info($this->_cm, CONDITION_MISSING_EXTRATABLE); $this->_cm = $ci->get_full_course_module(); $count = count($this->_cm->conditionsgrade)+1; + $fieldcount = count($this->_cm->conditionsfield)+1; } else { $count = 1; + $fieldcount = 1; } $this->repeat_elements(array($group), $count, array(), '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(); + asort($useroptions); + + $useroptions = array(0=>$strnone)+$useroptions; + $grouparray = array(); + $grouparray[] =& $mform->createElement('select','conditionfield','',$useroptions); + $grouparray[] =& $mform->createElement('select', 'conditionfieldoperator','',$operators); + $grouparray[] =& $mform->createElement('text', 'conditionfieldvalue'); + $mform->setType('conditionfieldvalue',PARAM_RAW); + $group = $mform->createElement('group','conditionfieldgroup', + get_string('userfield', 'condition'),$grouparray); + + $this->repeat_elements(array($group), $fieldcount, array(), '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()) { @@ -544,7 +575,7 @@ abstract class moodleform_mod extends moodleform { } } asort($completionoptions); - $completionoptions = array(0=>get_string('none','condition'))+$completionoptions; + $completionoptions = array(0=>$strnone)+$completionoptions; $completionvalues=array( COMPLETION_COMPLETE=>get_string('completion_complete','condition'), diff --git a/lang/en/condition.php b/lang/en/condition.php index fddd673c416..0d77874178d 100644 --- a/lang/en/condition.php +++ b/lang/en/condition.php @@ -25,6 +25,7 @@ $string['addcompletions'] = 'Add {no} activity conditions to form'; $string['addgrades'] = 'Add {no} grade conditions to form'; +$string['adduserfields'] = 'Add {no} user field conditions to form'; $string['availabilityconditions'] = 'Restrict access'; $string['availablefrom'] = 'Allow access from'; $string['availablefrom_help'] = 'Access from/to dates determine when students can access the activity via a link on the course page. @@ -74,12 +75,15 @@ $string['requires_grade_any'] = 'Not available until you have a grade in field}\' {$a->operator} \'{$a->value}\'.'; $string['showavailability'] = 'Before activity can be accessed'; $string['showavailabilitysection'] = 'Before section can be accessed'; $string['showavailability_hide'] = 'Hide activity entirely'; $string['showavailability_show'] = 'Show activity greyed-out, with restriction information'; $string['showavailabilitysection_hide'] = 'Hide section entirely'; $string['showavailabilitysection_show'] = 'Show section greyed-out, with restriction information'; +$string['userfield'] = 'User field'; +$string['userfield_help'] = 'This is an attribute associated with each individual user'; $string['userrestriction_hidden'] = 'Restricted (completely hidden, no message): ‘{$a}’'; $string['userrestriction_visible'] = 'Restricted: ‘{$a}’'; $string['groupingnoaccess'] = 'You do not currently belong to a group which has access to this section. '; diff --git a/lib/conditionlib.php b/lib/conditionlib.php index 0d8b3cbfde7..3e8738bd741 100644 --- a/lib/conditionlib.php +++ b/lib/conditionlib.php @@ -408,7 +408,8 @@ abstract class condition_info_base { $this->gotdata = true; // Missing extra data - if (!isset($item->conditionsgrade) || !isset($item->conditionscompletion)) { + if (!isset($item->conditionsgrade) || !isset($item->conditionscompletion) + || !isset($item->conditionsfield)) { if ($expectingmissingconditionsgrade) || !isset($item->conditionscompletion)) { + if (!isset($item->conditionsgrade) || !isset($item->conditionscompletion) + || !isset($item->conditionsfield)) { $item->conditionsgrade = array(); $item->conditionscompletion = array(); + $item->conditionsfield = array(); $conditions = $DB->get_records_sql(' SELECT @@ -470,6 +473,32 @@ abstract class condition_info_base { $item->conditionsgrade[$condition->gradeitemid] = $minmax; } } + // For user fields + $conditions = $DB->get_records_sql($sql=" +SELECT + cma.* +FROM + {course_modules_availability_field} cma +WHERE + coursemoduleid=?",array($cm->id)); + foreach ($conditions as $condition) { + // If the condition field is numeric, check + // the user profile field is available + if (is_numeric($condition->field)) { + if ($field = $DB->get_record('user_info_field', array('id'=>$condition->field))) { + $fieldname = $field->name; + } else { + $fieldname = '!missing'; + } + } else { + $fieldname = $condition->field; + } + $details = new stdClass; + $details->fieldname = $fieldname; + $details->operator = $condition->operator; + $details->value = $condition->value; + $cm->conditionsfield[$condition->field] = $details; + } } } @@ -503,6 +532,63 @@ abstract class condition_info_base { return $this->item; } + /** + * The operators that provide the relationship + * between a field and a value. + * + * @return array + */ + public function get_condition_user_field_operators() { + return array( + 0 => get_string('contains', 'filters'), + 1 => get_string('doesnotcontain','filters'), + 2 => get_string('isequalto','filters'), + 3 => get_string('startswith','filters'), + 4 => get_string('endswith','filters'), + 5 => get_string('isempty','filters') + ); + } + + /** + * The user fields we can compare + * + * @global $DB + * @return array + */ + public function get_condition_user_fields() { + global $DB; + + $userfields = array( + 'firstname' => get_string('firstname'), + 'lastname' => get_string('lastname'), + 'email' => get_string('email'), + 'city' => get_string('city'), + 'country' => get_string('country'), + 'interests' => get_string('interests'), + 'url' => get_string('webpage'), + 'icq' => get_string('icqnumber'), + 'skype' => get_string('skypeid'), + 'aim' => get_string('aimid'), + 'yahoo' => get_string('yahooid'), + 'msn' => get_string('msnid'), + 'idnumber' => get_string('idnumber'), + 'institution' => get_string('institution'), + 'department' => get_string('department'), + 'phone' => get_string('phone'), + 'phone2' => get_string('phone2'), + 'address' => get_string('address') + ); + + // Go through the custom profile fields now + if ($user_info_fields = $DB->get_records('user_info_field')) { + foreach ($user_info_fields as $field) { + $userfields[$field->id] = $field->name; + } + } + + return $userfields; + } + /** * Adds to the database a condition based on completion of another module. * @@ -522,6 +608,29 @@ abstract class condition_info_base { $this->item->conditionscompletion[$cmid] = $requiredcompletion; } + /** + * Adds user fields condition + * + * @global object + * @param mixed $field numeric if it is a user profile field, character + * if it is a column in the user table + * @param int $operator specifies the relationship between field and value + * @param char $value the value of the field + */ + public function add_user_field_condition($field, $operator, $value) { + // Add to DB + global $DB; + $DB->insert_record('course_modules_availability_field', + (object)array('coursemoduleid'=>$this->cm->id, + 'field'=>$field,'operator'=>$operator, + 'value'=>$value), + false); + + // Store in memory too + $this->cm->conditionsfield[$field] = (object)array( + 'field'=>$field,'operator'=>$operator,'value'=>$value); + } + /** * Adds to the database a condition based on the value of a grade item. * @@ -565,11 +674,15 @@ abstract class condition_info_base { public function wipe_conditions() { // Wipe from DB global $DB; + $DB->delete_records($this->availtable, array($this->idfieldname => $this->item->id)); + $DB->delete_records('course_modules_availability_field', + array('coursemoduleid'=>$this->cm->id)); // And from memory $this->item->conditionsgrade = array(); $this->item->conditionscompletion = array(); + $this->item->conditionsfield = array(); } /** @@ -630,6 +743,19 @@ abstract class condition_info_base { } } + // User field conditions + if (count($this->cm->conditionsfield)>0) { + // Need the array of operators + $arroperators = $this->get_condition_user_field_operators(); + foreach ($this->cm->conditionsfield as $field=>$details) { + $a = new stdclass; + $a->field = $details->fieldname; + $a->operator = $arroperators[$details->operator]; + $a->value = $details->value; + $information .= get_string('requires_user_field_restriction', 'condition', $a); + } + } + // The date logic is complicated. The intention of this logic is: // 1) display date without time where possible (whenever the date is // midnight) @@ -822,6 +948,67 @@ abstract class condition_info_base { } } + // Check if user field condition + if (count($this->cm->conditionsfield)>0) { + $arroperators = $this->get_condition_user_field_operators(); + foreach ($this->cm->conditionsfield as $field=>$details) { + // Need the array of operators + $operator = $details->operator; + $value = $details->value; + $uservalue = $this->get_cached_user_profile_field($userid, $field, $grabthelot); + // Assume that it passed + $fieldconditionmet = true; + switch($operator) { + case 0: // contains + $pos = strpos($uservalue, $value); + if ($pos === false) { + $fieldconditionmet = false; + } + break; + case 1: // does not contain + if (!empty($value)) { + $pos = strpos($uservalue, $value); + if ($pos !== false) { + $fieldconditionmet = false; + } + } + break; + case 2: // equal to + if ($value !== $uservalue) { + $fieldconditionmet = false; + } + break; + case 3: // starts with + $length = strlen($value); + if ((substr($uservalue, 0, $length) !== $value)) { + $fieldconditionmet = false; + } + break; + case 4: // ends with + $length = strlen($value); + $start = $length * -1; //negative + if (substr($uservalue, $start) !== $value) { + $fieldconditionmet = false; + } + break; + case 5: // empty + if (!empty($uservalue)) { + $fieldconditionmet = false; + } + break; + } + if (!$fieldconditionmet) { + // Set available to false + $available = false; + $a = new stdClass(); + $a->field = $details->fieldname; + $a->operator = $arroperators[$operator]; + $a->value = $details->value; + $information .= get_string('requires_user_field_restriction', 'condition', $a).' '; + } + } + } + // Test dates if ($this->item->availablefrom) { if (time() < $this->item->availablefrom) { @@ -983,6 +1170,100 @@ abstract class condition_info_base { } } + /** + * Return the value for a user's profile field + * + * @global object + * @global object + * @global object + * @param int $userid Set if requesting grade for a different user (does + * not use cache) + * @param int $fieldid the user profile field id + * @param bool $grabthelot If true, grabs all the user profile fields for + * current user on this course, so that later ones come from cache + * @return string the user value + */ + private function get_cached_user_profile_field($userid, $fieldid, $grabthelot) { + global $USER, $DB, $SESSION; + // Check if the field is a custom profile field + $iscustomprofilefield = is_numeric($fieldid) ? true : false; + if ($userid==0 || $userid==$USER->id) { + if ($iscustomprofilefield) { + // For current user, go via cache in session + if (empty($SESSION->userfieldcache) || $SESSION->userfieldcacheuserid!=$USER->id) { + $SESSION->userfieldcache = array(); + $SESSION->userfieldcacheuserid = $USER->id; + } + if (!array_key_exists($fieldid, $SESSION->userfieldcache)) { + if ($grabthelot) { + // Get all custom profile field values for user + $rs = $DB->get_recordset_sql(" +SELECT + uf.id, ud.data +FROM + {user_info_field} uf + LEFT JOIN {user_info_data} ud + ON uf.id = ud.fieldid +WHERE + ud.userid=?", array($USER->id)); + foreach ($rs as $record) { + $SESSION->userfieldcache[$record->id] = $record->data; + } + $rs->close(); + // And if it's still not set, well it doesn't exist (eg + // the user may have no entry for the profile field) + if (!array_key_exists($fieldid, $SESSION->userfieldcache)) { + $SESSION->userfieldcache[$fieldid] = false; + } + } else { + // Just get specified user field + if ($record = $DB->get_record_sql(" +SELECT + ud.data +FROM + {user_info_data} ud + INNER JOIN {user_info_field} uf + ON ud.fieldid = uf.id +WHERE + uf.id = ? +AND + ud.userid = ?", array($fieldid, $USER->id))) { + $field = $record->data; + } else { + $field = false; + } + $SESSION->userfieldcache[$fieldid]=$field; + } + } + return $SESSION->userfieldcache[$fieldid]; + } else { + return $USER->$fieldid; + } + } else { + if ($iscustomprofilefield) { + if ($record = $DB->get_record_sql(" +SELECT + ud.data +FROM + {user_info_data} ud + INNER JOIN {user_info_field} uf + ON ud.fieldid = uf.id +WHERE + uf.id = ? +AND + ud.userid = ?", array($fieldid, $userid))) { + return $record->data; + } + } else { + if ($user = $DB->get_record('user', array('id' => $userid), $fieldid)) { + return $user->$fieldid; + } + } + // If it reaches here, then no matches found + return false; + } + } + /** * For testing only. Wipes information cached in user session. * @@ -992,6 +1273,7 @@ abstract class condition_info_base { global $SESSION; unset($SESSION->gradescorecache); unset($SESSION->gradescorecacheuserid); + unset($SESSION->userfieldcache); } /** @@ -1023,6 +1305,13 @@ abstract class condition_info_base { unformat_float($record['conditiongrademin']), unformat_float($record['conditiongrademax'])); } } + foreach ($fromform->conditionfieldgroup as $record) { + if($record['conditionfield']) { + $ci->add_user_field_condition($record['conditionfield'], + $record['conditionfieldoperator'], + $record['conditionfieldvalue']); + } + } if(isset ($fromform->conditioncompletiongroup)) { foreach($fromform->conditioncompletiongroup as $record) { if($record['conditionsourcecmid']) { diff --git a/lib/db/install.xml b/lib/db/install.xml index 38ef87ec592..5cae8e2f971 100644 --- a/lib/db/install.xml +++ b/lib/db/install.xml @@ -330,7 +330,7 @@ - +
@@ -347,7 +347,20 @@
- +
+ + + + + + + + + + + +
+ @@ -2875,4 +2888,4 @@
- \ No newline at end of file + diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index 3be8b80bf88..6c8be26eb8e 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -586,6 +586,22 @@ function xmldb_main_upgrade($oldversion) { $table->add_key('sourcecmid', XMLDB_KEY_FOREIGN, array('sourcecmid'), 'course_modules', array('id')); $table->add_key('gradeitemid', XMLDB_KEY_FOREIGN, array('gradeitemid'), 'grade_items', array('id')); + // Define table course_modules_availability to be created + $table = new xmldb_table('course_modules_avail_fields'); + + // Adding fields to table course_modules_avail_fields + $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); + $table->add_field('coursemoduleid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null); + $table->add_field('userfield', XMLDB_TYPE_CHAR, '50', null, null, null, null); + $table->add_field('customfieldid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null); + $table->add_field('operator', XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null); + $table->add_field('value', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null); + + // Adding keys to table course_modules_avail_fields + $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id')); + $table->add_key('coursemoduleid', XMLDB_KEY_FOREIGN, array('coursemoduleid'), 'course_modules', array('id')); + + // Conditionally launch create table for course_modules_availability if (!$dbman->table_exists($table)) { $dbman->create_table($table); } diff --git a/lib/modinfolib.php b/lib/modinfolib.php index bcbb7ecff22..114fbd42db3 100644 --- a/lib/modinfolib.php +++ b/lib/modinfolib.php @@ -596,6 +596,12 @@ class cm_info extends stdClass { */ public $conditionsgrade; + /** + * Availability conditions for this course-module based on user fields + * @var array + */ + public $conditionsfield; + /** * Plural name of module type, e.g. 'Forums' - from lang file * @deprecated Do not use this value (you can obtain it by calling get_string instead); it @@ -996,6 +1002,8 @@ class cm_info extends stdClass { ? $mod->conditionscompletion : array(); $this->conditionsgrade = isset($mod->conditionsgrade) ? $mod->conditionsgrade : array(); + $this->conditionsfield = isset($mod->conditionsfield) + ? $mod->conditionsfield : array(); // Get module plural name. // TODO This was a very old performance hack and should now be removed as the information diff --git a/lib/moodlelib.php b/lib/moodlelib.php index 2dd1f58addf..8ad17a1fafc 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -4584,6 +4584,9 @@ function remove_course_contents($courseid, $showfeedback = true, array $options $DB->delete_records_select('course_modules_availability', 'coursemoduleid IN (SELECT id from {course_modules} WHERE course=?)', array($courseid)); + $DB->delete_records_select('course_modules_availability_field', + 'coursemoduleid IN (SELECT id from {course_modules} WHERE course=?)', + array($courseid)); // Remove course-module data. $cms = $DB->get_records('course_modules', array('course'=>$course->id)); diff --git a/user/profile/definelib.php b/user/profile/definelib.php index 262fd3e57ed..9cb2d40dd54 100644 --- a/user/profile/definelib.php +++ b/user/profile/definelib.php @@ -289,6 +289,10 @@ function profile_delete_field($id) { print_error('cannotdeletecustomfield'); } + // Delete any module dependencies for this field + $DB->delete_records('course_modules_availability_field', array('field'=>$id)); + // Need to rebuild course cache to update the info + rebuild_course_cache(); /// Try to remove the record from the database $DB->delete_records('user_info_field', array('id'=>$id));