Example #1
0
 public static function create_group($group)
 {
     global $DB, $CFG;
     // Valida os parametros.
     $params = self::validate_parameters(self::create_group_parameters(), array('group' => $group));
     // Transforma o array em objeto.
     $group = (object) $group;
     // Inicia a transacao, qualquer erro que aconteca o rollback sera executado.
     $transaction = $DB->start_delegated_transaction();
     // Busca o id do curso apartir do trm_id da turma.
     $courseid = self::get_course_by_trm_id($group->trm_id);
     // Se nao existir curso mapeado para a turma dispara uma excessao.
     if (!$courseid) {
         throw new Exception("Nenhum curso mapeado com a turma com trm_id: " . $group->trm_id);
     }
     $groupbyname = self::get_group_by_name($courseid, $group->name);
     // Dispara uma excessao caso ja exista um grupo com o mesmo nome no mesmo curso
     if ($groupbyname) {
         throw new Exception("ja existe um grupo com o mesmo nome nessa turma trm_id: " . $group->trm_id);
     }
     $groupdata['courseid'] = $courseid;
     $groupdata['name'] = $group->name;
     $groupdata['description'] = $group->description;
     $groupdata['descriptionformat'] = 1;
     $groupdata['timecreated'] = time();
     $groupdata['timemodified'] = $groupdata['timecreated'];
     $resultid = $DB->insert_record('groups', $groupdata);
     // Caso o curso tenha sido criado adiciona a tabela de controle os dados dos curso e da turma.
     if ($resultid) {
         $data['trm_id'] = $group->trm_id;
         $data['grp_id'] = $group->grp_id;
         $data['groupid'] = $resultid;
         $res = $DB->insert_record('itg_grupo_group', $data);
         // Busca as configuracoes do curso
         $courseoptions = $DB->get_record('course', array('id' => $courseid), '*');
         // Altera o formato de grupos do curso
         $courseoptions->groupmode = 1;
         $courseoptions->groupmodeforce = 1;
         $DB->update_record('course', $courseoptions);
         // Invalidate the grouping cache for the course
         cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($courseid));
         // Prepara o array de retorno.
         $returndata = null;
         if ($res) {
             $returndata['id'] = $resultid;
             $returndata['status'] = 'success';
             $returndata['message'] = 'Grupo criado com sucesso';
         } else {
             $returndata['id'] = 0;
             $returndata['status'] = 'error';
             $returndata['message'] = 'Erro ao tentar criar o grupo';
         }
     }
     // Persiste as operacoes em caso de sucesso.
     $transaction->allow_commit();
     return $returndata;
 }
Example #2
0
 protected function after_execute()
 {
     // Add group related files, matching with "group" mappings
     $this->add_related_files('group', 'icon', 'group');
     $this->add_related_files('group', 'description', 'group');
     // Add grouping related files, matching with "grouping" mappings
     $this->add_related_files('grouping', 'description', 'grouping');
     // Invalidate the course group data.
     cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($this->get_courseid()));
 }
Example #3
0
/**
 * Delete subscription and all related events.
 *
 * @param int|stdClass $subscription subscription or it's id, which needs to be deleted.
 */
function calendar_delete_subscription($subscription)
{
    global $DB;
    if (is_object($subscription)) {
        $subscription = $subscription->id;
    }
    // Delete subscription and related events.
    $DB->delete_records('event', array('subscriptionid' => $subscription));
    $DB->delete_records('event_subscriptions', array('id' => $subscription));
    cache_helper::invalidate_by_definition('core', 'calendar_subscriptions', array(), array($subscription));
}
Example #4
0
/**
 * Uninstall a message processor
 *
 * @param string $name A message processor name like 'email', 'jabber'
 */
function message_processor_uninstall($name) {
    global $DB;

    $transaction = $DB->start_delegated_transaction();
    $DB->delete_records('message_processors', array('name' => $name));
    $DB->delete_records_select('config_plugins', "plugin = ?", array("message_{$name}"));
    // delete permission preferences only, we do not care about loggedin/loggedoff
    // defaults, they will be removed on the next attempt to update the preferences
    $DB->delete_records_select('config_plugins', "plugin = 'message' AND ".$DB->sql_like('name', '?', false), array("{$name}_provider_%"));
    $transaction->allow_commit();
    // Purge all messaging settings from the caches. They are stored by plugin so we have to clear all message settings.
    cache_helper::invalidate_by_definition('core', 'config', array(), array('message', "message_{$name}"));
}
Example #5
0
/**
 * Remove all the config variables for a given plugin.
 *
 * NOTE: this function is called from lib/db/upgrade.php
 *
 * @param string $plugin a plugin, for example 'quiz' or 'qtype_multichoice';
 * @return boolean whether the operation succeeded.
 */
function unset_all_config_for_plugin($plugin)
{
    global $DB;
    // Delete from the obvious config_plugins first.
    $DB->delete_records('config_plugins', array('plugin' => $plugin));
    // Next delete any suspect settings from config.
    $like = $DB->sql_like('name', '?', true, true, false, '|');
    $params = array($DB->sql_like_escape($plugin . '_', '|') . '%');
    $DB->delete_records_select('config', $like, $params);
    // Finally clear both the plugin cache and the core cache (suspect settings now removed from core).
    cache_helper::invalidate_by_definition('core', 'config', array(), array('core', $plugin));
    return true;
}
Example #6
0
/**
 * Delete subscription and all related events.
 *
 * @param int|stdClass $subscription subscription or it's id, which needs to be deleted.
 */
function calendar_delete_subscription($subscription)
{
    global $DB;
    if (!is_object($subscription)) {
        $subscription = $DB->get_record('event_subscriptions', array('id' => $subscription), '*', MUST_EXIST);
    }
    // Delete subscription and related events.
    $DB->delete_records('event', array('subscriptionid' => $subscription->id));
    $DB->delete_records('event_subscriptions', array('id' => $subscription->id));
    cache_helper::invalidate_by_definition('core', 'calendar_subscriptions', array(), array($subscription->id));
    // Trigger event, calendar subscription deleted.
    $eventparams = array('objectid' => $subscription->id, 'context' => calendar_get_calendar_context($subscription), 'other' => array('courseid' => $subscription->courseid));
    $event = \core\event\calendar_subscription_deleted::create($eventparams);
    $event->trigger();
}
Example #7
0
            }
            $newgroup = new stdClass();
            $newgroup->courseid = $data->courseid;
            $newgroup->name = $group['name'];
            $groupid = groups_create_group($newgroup);
            $createdgroups[] = $groupid;
            foreach ($group['members'] as $user) {
                groups_add_member($groupid, $user->id);
            }
            if ($grouping) {
                // Ask this function not to invalidate the cache, we'll do that manually once at the end.
                groups_assign_grouping($grouping->id, $groupid, null, false);
            }
        }
        // Invalidate the course groups cache seeing as we've changed it.
        cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($courseid));
        if ($failed) {
            foreach ($createdgroups as $groupid) {
                groups_delete_group($groupid);
            }
            if ($createdgrouping) {
                groups_delete_grouping($createdgrouping);
            }
        } else {
            redirect($returnurl);
        }
    }
}
$PAGE->navbar->add($strparticipants, new moodle_url('/user/index.php', array('id' => $courseid)));
$PAGE->navbar->add($strgroups, new moodle_url('/group/index.php', array('id' => $courseid)));
$PAGE->navbar->add($strautocreategroups);
Example #8
0
/**
 * Unassigns group from grouping
 *
 * @param int groupingid
 * @param int groupid
 * @param bool $invalidatecache If set to true the course group cache will be invalidated as well.
 * @return bool success
 */
function groups_unassign_grouping($groupingid, $groupid, $invalidatecache = true)
{
    global $DB;
    $DB->delete_records('groupings_groups', array('groupingid' => $groupingid, 'groupid' => $groupid));
    if ($invalidatecache) {
        // Invalidate the grouping cache for the course
        $courseid = $DB->get_field('groupings', 'courseid', array('id' => $groupingid));
        cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($courseid));
    }
    return true;
}
                $configfield->value = $value;
                if (!$DB->update_record('config_plugins', $configfield)) {
                    error("errorupdating");
                }
            } else {
                $configfield = new stdClass();
                $configfield->value = $value;
                $configfield->plugin = 'plagiarism';
                $configfield->name = $field;
                if (!$DB->insert_record('config_plugins', $configfield)) {
                    error("errorinserting");
                }
            }
        }
    }
    cache_helper::invalidate_by_definition('core', 'config', array(), 'plagiarism');
    // TODO - check settings to see if valid.
    $quotas = compilatio_getquotas(true);
    if ($quotas == null) {
        // Disable compilatio as this config isn't correct.
        $rec = $DB->get_record('config_plugins', array('name' => 'compilatio_use', 'plugin' => 'plagiarism'));
        $rec->value = 0;
        $DB->update_record('config_plugins', $rec);
        echo $OUTPUT->notification(get_string('savedconfigfailed', 'plagiarism_compilatio'));
    }
}
$invalidhandlers = compilatio_check_event_handlers();
if (!empty($invalidhandlers)) {
    echo $OUTPUT->notification("There are invalid event handlers - these MUST be fixed. Please use the correct procedure to uninstall any components listed in the table below.<br>\nThe existence of these events may cause this plugin to function incorrectly.");
    $table = new html_table();
    $table->head = array('eventname', 'plugin', 'handlerfile');
Example #10
0
    /**
     * Process the membership tag. This defines whether the specified Moodle users
     * should be added/removed as teachers/students.
     *
     * @param string $tagcontents The raw contents of the XML element
     */
    protected function process_membership_tag($tagcontents) {
        global $DB;

        // Get plugin configs.
        $truncatecoursecodes = $this->get_config('truncatecoursecodes');
        $imscapitafix = $this->get_config('imscapitafix');

        $memberstally = 0;
        $membersuntally = 0;

        // In order to reduce the number of db queries required, group name/id associations are cached in this array.
        $groupids = array();

        $ship = new stdClass();

        if (preg_match('{<sourcedid>.*?<id>(.+?)</id>.*?</sourcedid>}is', $tagcontents, $matches)) {
            $ship->coursecode = ($truncatecoursecodes > 0)
                ? substr(trim($matches[1]), 0, intval($truncatecoursecodes))
                : trim($matches[1]);
            $ship->courseid = $DB->get_field('course', 'id', array('idnumber' => $ship->coursecode));
        }
        if ($ship->courseid && preg_match_all('{<member>(.*?)</member>}is', $tagcontents, $membermatches, PREG_SET_ORDER)) {
            $courseobj = new stdClass();
            $courseobj->id = $ship->courseid;

            foreach ($membermatches as $mmatch) {
                $member = new stdClass();
                $memberstoreobj = new stdClass();
                if (preg_match('{<sourcedid>.*?<id>(.+?)</id>.*?</sourcedid>}is', $mmatch[1], $matches)) {
                    $member->idnumber = trim($matches[1]);
                }
                if (preg_match('{<role\s+roletype=["\'](.+?)["\'].*?>}is', $mmatch[1], $matches)) {
                    // 01 means Student, 02 means Instructor, 3 means ContentDeveloper, and there are more besides.
                    $member->roletype = trim($matches[1]);
                } else if ($imscapitafix && preg_match('{<roletype>(.+?)</roletype>}is', $mmatch[1], $matches)) {
                    // The XML that comes out of Capita Student Records seems to contain a misinterpretation of
                    // the IMS specification! 01 means Student, 02 means Instructor, 3 means ContentDeveloper,
                    // and there are more besides.
                    $member->roletype = trim($matches[1]);
                }
                if (preg_match('{<role\b.*?<status>(.+?)</status>.*?</role>}is', $mmatch[1], $matches)) {
                    // 1 means active, 0 means inactive - treat this as enrol vs unenrol.
                    $member->status = trim($matches[1]);
                }

                $recstatus = ($this->get_recstatus($mmatch[1], 'role'));
                if ($recstatus == 3) {
                    // See above - recstatus of 3 (==delete) is treated the same as status of 0.
                    $member->status = 0;
                }

                $timeframe = new stdClass();
                $timeframe->begin = 0;
                $timeframe->end = 0;
                if (preg_match('{<role\b.*?<timeframe>(.+?)</timeframe>.*?</role>}is', $mmatch[1], $matches)) {
                    $timeframe = $this->decode_timeframe($matches[1]);
                }
                if (preg_match('{<role\b.*?<extension>.*?<cohort>(.+?)</cohort>.*?</extension>.*?</role>}is',
                        $mmatch[1], $matches)) {
                    $member->groupname = trim($matches[1]);
                    // The actual processing (ensuring a group record exists, etc) occurs below, in the enrol-a-student clause.
                }

                // Add or remove this student or teacher to the course...
                $memberstoreobj->userid = $DB->get_field('user', 'id', array('idnumber' => $member->idnumber));
                $memberstoreobj->enrol = 'imsenterprise';
                $memberstoreobj->course = $ship->courseid;
                $memberstoreobj->time = time();
                $memberstoreobj->timemodified = time();
                if ($memberstoreobj->userid) {

                    // Decide the "real" role (i.e. the Moodle role) that this user should be assigned to.
                    // Zero means this roletype is supposed to be skipped.
                    $moodleroleid = $this->rolemappings[$member->roletype];
                    if (!$moodleroleid) {
                        $this->log_line("SKIPPING role $member->roletype for $memberstoreobj->userid "
                            ."($member->idnumber) in course $memberstoreobj->course");
                        continue;
                    }

                    if (intval($member->status) == 1) {
                        // Enrol the member.

                        $einstance = $DB->get_record('enrol',
                            array('courseid' => $courseobj->id, 'enrol' => $memberstoreobj->enrol));
                        if (empty($einstance)) {
                            // Only add an enrol instance to the course if non-existent.
                            $enrolid = $this->add_instance($courseobj);
                            $einstance = $DB->get_record('enrol', array('id' => $enrolid));
                        }

                        $this->enrol_user($einstance, $memberstoreobj->userid, $moodleroleid, $timeframe->begin, $timeframe->end);

                        $this->log_line("Enrolled user #$memberstoreobj->userid ($member->idnumber) "
                            ."to role $member->roletype in course $memberstoreobj->course");
                        $memberstally++;

                        // At this point we can also ensure the group membership is recorded if present.
                        if (isset($member->groupname)) {
                            // Create the group if it doesn't exist - either way, make sure we know the group ID.
                            if (isset($groupids[$member->groupname])) {
                                $member->groupid = $groupids[$member->groupname]; // Recall the group ID from cache if available.
                            } else {
                                $params = array('courseid' => $ship->courseid, 'name' => $member->groupname);
                                if ($groupid = $DB->get_field('groups', 'id', $params)) {
                                    $member->groupid = $groupid;
                                    $groupids[$member->groupname] = $groupid; // Store ID in cache.
                                } else {
                                    // Attempt to create the group.
                                    $group = new stdClass();
                                    $group->name = $member->groupname;
                                    $group->courseid = $ship->courseid;
                                    $group->timecreated = time();
                                    $group->timemodified = time();
                                    $groupid = $DB->insert_record('groups', $group);
                                    $this->log_line('Added a new group for this course: '.$group->name);
                                    $groupids[$member->groupname] = $groupid; // Store ID in cache.
                                    $member->groupid = $groupid;
                                    // Invalidate the course group data cache just in case.
                                    cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($ship->courseid));
                                }
                            }
                            // Add the user-to-group association if it doesn't already exist.
                            if ($member->groupid) {
                                groups_add_member($member->groupid, $memberstoreobj->userid,
                                    'enrol_imsenterprise', $einstance->id);
                            }
                        }

                    } else if ($this->get_config('imsunenrol')) {
                        // Unenrol member.

                        $einstances = $DB->get_records('enrol',
                            array('enrol' => $memberstoreobj->enrol, 'courseid' => $courseobj->id));
                        foreach ($einstances as $einstance) {
                            // Unenrol the user from all imsenterprise enrolment instances.
                            $this->unenrol_user($einstance, $memberstoreobj->userid);
                        }

                        $membersuntally++;
                        $this->log_line("Unenrolled $member->idnumber from role $moodleroleid in course");
                    }

                }
            }
            $this->log_line("Added $memberstally users to course $ship->coursecode");
            if ($membersuntally > 0) {
                $this->log_line("Removed $membersuntally users from course $ship->coursecode");
            }
        }
    } // End process_membership_tag().
Example #11
0
    /**
     * Store user_enrolments changes and trigger event.
     *
     * @param stdClass $instance
     * @param int $userid
     * @param int $status
     * @param int $timestart
     * @param int $timeend
     * @return void
     */
    public function update_user_enrol(stdClass $instance, $userid, $status = NULL, $timestart = NULL, $timeend = NULL) {
        global $DB, $USER;

        $name = $this->get_name();

        if ($instance->enrol !== $name) {
            throw new coding_exception('invalid enrol instance!');
        }

        if (!$ue = $DB->get_record('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$userid))) {
            // weird, user not enrolled
            return;
        }

        $modified = false;
        if (isset($status) and $ue->status != $status) {
            $ue->status = $status;
            $modified = true;
        }
        if (isset($timestart) and $ue->timestart != $timestart) {
            $ue->timestart = $timestart;
            $modified = true;
        }
        if (isset($timeend) and $ue->timeend != $timeend) {
            $ue->timeend = $timeend;
            $modified = true;
        }

        if (!$modified) {
            // no change
            return;
        }

        $ue->modifierid = $USER->id;
        $DB->update_record('user_enrolments', $ue);
        context_course::instance($instance->courseid)->mark_dirty(); // reset enrol caches

        // Invalidate core_access cache for get_suspended_userids.
        cache_helper::invalidate_by_definition('core', 'suspended_userids', array(), array($instance->courseid));

        // Trigger event.
        $event = \core\event\user_enrolment_updated::create(
                array(
                    'objectid' => $ue->id,
                    'courseid' => $instance->courseid,
                    'context' => context_course::instance($instance->courseid),
                    'relateduserid' => $ue->userid,
                    'other' => array('enrol' => $name)
                    )
                );
        $event->trigger();
    }
Example #12
0
 /**
  * Tests application cache definition invalidation
  */
 public function test_application_definition_invalidation()
 {
     $instance = cache_config_phpunittest::instance();
     $instance->phpunit_add_definition('phpunit/definitioninvalidation', array('mode' => cache_store::MODE_APPLICATION, 'component' => 'phpunit', 'area' => 'definitioninvalidation'));
     $cache = cache::make('phpunit', 'definitioninvalidation');
     $this->assertTrue($cache->set('testkey1', 'test data 1'));
     $this->assertEquals('test data 1', $cache->get('testkey1'));
     $this->assertTrue($cache->set('testkey2', 'test data 2'));
     $this->assertEquals('test data 2', $cache->get('testkey2'));
     cache_helper::invalidate_by_definition('phpunit', 'definitioninvalidation', array(), 'testkey1');
     $this->assertFalse($cache->get('testkey1'));
     $this->assertEquals('test data 2', $cache->get('testkey2'));
     $this->assertTrue($cache->set('testkey1', 'test data 1'));
     cache_helper::invalidate_by_definition('phpunit', 'definitioninvalidation', array(), array('testkey1'));
     $this->assertFalse($cache->get('testkey1'));
     $this->assertEquals('test data 2', $cache->get('testkey2'));
     $this->assertTrue($cache->set('testkey1', 'test data 1'));
     cache_helper::invalidate_by_definition('phpunit', 'definitioninvalidation', array(), array('testkey1', 'testkey2'));
     $this->assertFalse($cache->get('testkey1'));
     $this->assertFalse($cache->get('testkey2'));
 }
Example #13
0
 /**
  * Tests session cache definition invalidation
  */
 public function test_session_definition_invalidation()
 {
     $instance = cache_config_testing::instance();
     $instance->phpunit_add_definition('phpunit/test_session_definition_invalidation', array('mode' => cache_store::MODE_SESSION, 'component' => 'phpunit', 'area' => 'test_session_definition_invalidation'));
     $cache = cache::make('phpunit', 'test_session_definition_invalidation');
     $this->assertInstanceOf('cache_session', $cache);
     $this->assertTrue($cache->set('testkey1', 'test data 1'));
     $this->assertEquals('test data 1', $cache->get('testkey1'));
     $this->assertTrue($cache->set('testkey2', 'test data 2'));
     $this->assertEquals('test data 2', $cache->get('testkey2'));
     cache_helper::invalidate_by_definition('phpunit', 'test_session_definition_invalidation', array(), 'testkey1');
     $this->assertFalse($cache->get('testkey1'));
     $this->assertEquals('test data 2', $cache->get('testkey2'));
     $this->assertTrue($cache->set('testkey1', 'test data 1'));
     cache_helper::invalidate_by_definition('phpunit', 'test_session_definition_invalidation', array(), array('testkey1'));
     $this->assertFalse($cache->get('testkey1'));
     $this->assertEquals('test data 2', $cache->get('testkey2'));
     $this->assertTrue($cache->set('testkey1', 'test data 1'));
     cache_helper::invalidate_by_definition('phpunit', 'test_session_definition_invalidation', array(), array('testkey1', 'testkey2'));
     $this->assertFalse($cache->get('testkey1'));
     $this->assertFalse($cache->get('testkey2'));
 }
 private function process_action_allocation_to_grouping()
 {
     $now = time();
     if ($this->ratingallocate->accesstimestop < $now) {
         global $OUTPUT;
         $allgroupings = groups_get_all_groupings($this->course->id);
         $groupingidname = ratingallocate_MOD_NAME . '_instid_' . $this->ratingallocateid;
         // search if there is already a grouping from us
         $grouping = groups_get_grouping_by_idnumber($this->course->id, $groupingidname);
         $groupingid = null;
         if (!$grouping) {
             // create grouping
             $data = new stdClass();
             $data->name = get_string('groupingname', ratingallocate_MOD_NAME, $this->ratingallocate->name);
             $data->idnumber = $groupingidname;
             $data->courseid = $this->course->id;
             $groupingid = groups_create_grouping($data);
         } else {
             $groupingid = $grouping->id;
         }
         $group_identifier_from_choice_id = function ($choiceid) {
             return ratingallocate_MOD_NAME . '_c_' . $choiceid;
         };
         $choices = $this->get_choices_with_allocationcount();
         // make a new array containing only the identifiers of the choices
         $choice_identifiers = array();
         foreach ($choices as $id => $choice) {
             $choice_identifiers[$group_identifier_from_choice_id($choice->id)] = array('key' => $id);
         }
         // find all associated groups in this grouping
         $groups = groups_get_all_groups($this->course->id, 0, $groupingid);
         // loop through the groups in the grouping: if the choice does not exist anymore -> delete
         // otherwise mark it
         foreach ($groups as $group) {
             if (array_key_exists($group->idnumber, $choice_identifiers)) {
                 // group exists, mark
                 $choice_identifiers[$group->idnumber]['exists'] = true;
                 $choice_identifiers[$group->idnumber]['groupid'] = $group->id;
             } else {
                 // delete group $group->id
                 groups_delete_group($group->id);
             }
         }
         // create groups groups for new identifiers or empty group if it exists
         foreach ($choice_identifiers as $group_idnumber => $choice) {
             if (key_exists('exists', $choice)) {
                 // remove all members
                 groups_delete_group_members_by_group($choice['groupid']);
             } else {
                 $data = new stdClass();
                 $data->courseid = $this->course->id;
                 $data->name = $choices[$choice['key']]->title;
                 $data->idnumber = $group_idnumber;
                 $createdid = groups_create_group($data);
                 groups_assign_grouping($groupingid, $createdid);
                 $choice_identifiers[$group_idnumber]['groupid'] = $createdid;
             }
         }
         // add all participants in the correct group
         $allocations = $this->get_allocations();
         foreach ($allocations as $id => $allocation) {
             $choice_id = $allocation->choiceid;
             $user_id = $allocation->userid;
             $choiceidnumber = $group_identifier_from_choice_id($choice_id);
             groups_add_member($choice_identifiers[$choiceidnumber]['groupid'], $user_id);
         }
         // Invalidate the grouping cache for the course
         cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($this->course->id));
         $renderer = $this->get_renderer();
         $renderer->add_notification(get_string('moodlegroups_created', ratingallocate_MOD_NAME), self::NOTIFY_SUCCESS);
     }
     return $this->process_default();
 }
Example #15
0
/**
 * Unassigns group from grouping
 *
 * @param int groupingid
 * @param int groupid
 * @param bool $invalidatecache If set to true the course group cache will be invalidated as well.
 * @return bool success
 */
function groups_unassign_grouping($groupingid, $groupid, $invalidatecache = true)
{
    global $DB;
    $DB->delete_records('groupings_groups', array('groupingid' => $groupingid, 'groupid' => $groupid));
    $courseid = $DB->get_field('groupings', 'courseid', array('id' => $groupingid));
    if ($invalidatecache) {
        // Invalidate the grouping cache for the course
        cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($courseid));
    }
    // Trigger event.
    $params = array('context' => context_course::instance($courseid), 'objectid' => $groupingid, 'other' => array('groupid' => $groupid));
    $event = \core\event\grouping_group_unassigned::create($params);
    $event->trigger();
    return true;
}