Example #1
0
/**
 * More user friendly role permission changing,
 * it should produce as few overrides as possible.
 *
 * @param int $roleid
 * @param stdClass $context
 * @param string $capname capability name
 * @param int $permission
 * @return void
 */
function role_change_permission($roleid, $context, $capname, $permission) {
    global $DB;

    if ($permission == CAP_INHERIT) {
        unassign_capability($capname, $roleid, $context->id);
        $context->mark_dirty();
        return;
    }

    $ctxids = trim($context->path, '/'); // kill leading slash
    $ctxids = str_replace('/', ',', $ctxids);

    $params = array('roleid'=>$roleid, 'cap'=>$capname);

    $sql = "SELECT ctx.id, rc.permission, ctx.depth
              FROM {role_capabilities} rc
              JOIN {context} ctx ON ctx.id = rc.contextid
             WHERE rc.roleid = :roleid AND rc.capability = :cap AND ctx.id IN ($ctxids)
          ORDER BY ctx.depth DESC";

    if ($existing = $DB->get_records_sql($sql, $params)) {
        foreach($existing as $e) {
            if ($e->permission == CAP_PROHIBIT) {
                // prohibit can not be overridden, no point in changing anything
                return;
            }
        }
        $lowest = array_shift($existing);
        if ($lowest->permission == $permission) {
            // permission already set in this context or parent - nothing to do
            return;
        }
        if ($existing) {
            $parent = array_shift($existing);
            if ($parent->permission == $permission) {
                // permission already set in parent context or parent - just unset in this context
                // we do this because we want as few overrides as possible for performance reasons
                unassign_capability($capname, $roleid, $context->id);
                $context->mark_dirty();
                return;
            }
        }

    } else {
        if ($permission == CAP_PREVENT) {
            // nothing means role does not have permission
            return;
        }
    }

    // assign the needed capability
    assign_capability($capname, $permission, $roleid, $context->id, true);

    // force cap reloading
    $context->mark_dirty();
}