Skip to content

Commit

Permalink
MDL-10995 backported basic perf improvement from HEAD - course parent…
Browse files Browse the repository at this point in the history
…s are now cached when walking the context tree - this should substantially improve login time; HEAD will have a better solution soon by ML;
  • Loading branch information
skodak committed Sep 15, 2007
1 parent 0fcad93 commit 2baa6af
Showing 1 changed file with 85 additions and 116 deletions.
201 changes: 85 additions & 116 deletions lib/accesslib.php
Expand Up @@ -267,64 +267,82 @@ function get_guest_role() {
* (!)note this only gets course category contexts, and not the site
* context
* @param object $context
* @param int $type
* @return array of contextids
*/
function get_parent_cats($context, $type) {
function get_parent_cats($context) {
global $COURSE;

$parents = array();

switch ($type) {
switch ($context->contextlevel) {
// a category can be the parent of another category
// there is no limit of depth in this case
case CONTEXT_COURSECAT:
if (!$cat = get_record('course_categories','id',$context->instanceid)) {
break;
static $categoryparents = null; // cache for parent categories
if (!isset($categoryparents)) {
$categoryparents = array();
}
if (array_key_exists($context->instanceid, $categoryparents)) {
return $categoryparents[$context->instanceid];
}

if (!$cat = get_record('course_categories','id',$context->instanceid)) {
//error?
return array();
}
$parents = array();
while (!empty($cat->parent)) {
if (!$context = get_context_instance(CONTEXT_COURSECAT, $cat->parent)) {
if (!$catcontext = get_context_instance(CONTEXT_COURSECAT, $cat->parent)) {
debugging('Incorrect category parent');
break;
}
$parents[] = $context->id;
$parents[] = $catcontext->id;
$cat = get_record('course_categories','id',$cat->parent);
}
return $categoryparents[$context->instanceid] = array_reverse($parents);
break;

// a course always fall into a category, unless it's a site course
// this happens when SITEID == $course->id
// in this case the parent of the course is site context
case CONTEXT_COURSE:
if (!$course = get_record('course', 'id', $context->instanceid)) {
break;
static $courseparents = null; // cache course parents
if (!isset($courseparents)) {
$courseparents = array();
}
if (!$catinstance = get_context_instance(CONTEXT_COURSECAT, $course->category)) {
break;
if (array_key_exists($context->instanceid, $courseparents)) {
return $courseparents[$context->instanceid];
}

$parents[] = $catinstance->id;

if (!$cat = get_record('course_categories','id',$course->category)) {
break;
if (count($courseparents) > 1000) {
$courseparents = array(); // max cache size when looping through thousands of courses
}
if ($context->instanceid == SITEID) {
return $courseparents[$context->instanceid] = array(); // frontpage course does not have parent cats
}
// Yu: Separating site and site course context
if ($course->id == SITEID) {
break;
if ($context->instanceid == $COURSE->id) {
$course = $COURSE;
} else if (!$course = get_record('course', 'id', $context->instanceid)) {
//error?
return array();;
}

while (!empty($cat->parent)) {
if (!$context = get_context_instance(CONTEXT_COURSECAT, $cat->parent)) {
break;
}
$parents[] = $context->id;
$cat = get_record('course_categories','id',$cat->parent);
if (empty($course->category)) {
// this should not happen
return $courseparents[$context->instanceid] = array();
}

if (!$catcontext = get_context_instance(CONTEXT_COURSECAT, $course->category)) {
debugging('Incorect course category');
return array();;
}

return $courseparents[$context->instanceid] = array_merge(get_parent_cats($catcontext), array($catcontext->id)); //recursion :-)
break;

default:
// something is very wrong!
return array();
break;
}
return array_reverse($parents);
}


Expand Down Expand Up @@ -411,9 +429,8 @@ function has_capability_including_child_contexts($context, $capabilitynames) {

/**
* This function returns whether the current user has the capability of performing a function
* For example, we can do has_capability('mod/forum:replypost',$cm) in forum
* only one of the 4 (moduleinstance, courseid, site, userid) would be set at 1 time
* This is a recursive funciton.
* For example, we can do has_capability('mod/forum:replypost',$context) in forum
* This is a recursive function.
* @uses $USER
* @param string $capability - name of the capability (or debugcache or clearcache)
* @param object $context - a context object (record from context table)
Expand Down Expand Up @@ -556,7 +573,7 @@ function has_capability($capability, $context=NULL, $userid=NULL, $doanything=tr

case CONTEXT_COURSECAT:
// Check parent cats.
$parentcats = get_parent_cats($context, CONTEXT_COURSECAT);
$parentcats = get_parent_cats($context);
foreach ($parentcats as $parentcat) {
if (isset($capabilities[$parentcat]['moodle/site:doanything'])) {
$result = (0 < $capabilities[$parentcat]['moodle/site:doanything']);
Expand All @@ -568,7 +585,7 @@ function has_capability($capability, $context=NULL, $userid=NULL, $doanything=tr

case CONTEXT_COURSE:
// Check parent cat.
$parentcats = get_parent_cats($context, CONTEXT_COURSE);
$parentcats = get_parent_cats($context);

foreach ($parentcats as $parentcat) {
if (isset($capabilities[$parentcat]['do_anything'])) {
Expand All @@ -584,7 +601,7 @@ function has_capability($capability, $context=NULL, $userid=NULL, $doanything=tr
$courseid = groups_get_course($context->instanceid);
$courseinstance = get_context_instance(CONTEXT_COURSE, $courseid);

$parentcats = get_parent_cats($courseinstance, CONTEXT_COURSE);
$parentcats = get_parent_cats($courseinstance);
foreach ($parentcats as $parentcat) {
if (isset($capabilities[$parentcat]['do_anything'])) {
$result = (0 < $capabilities[$parentcat]['do_anything']);
Expand All @@ -607,7 +624,7 @@ function has_capability($capability, $context=NULL, $userid=NULL, $doanything=tr
$cm = get_record('course_modules', 'id', $context->instanceid);
$courseinstance = get_context_instance(CONTEXT_COURSE, $cm->course);

if ($parentcats = get_parent_cats($courseinstance, CONTEXT_COURSE)) {
if ($parentcats = get_parent_cats($courseinstance)) {
foreach ($parentcats as $parentcat) {
if (isset($capabilities[$parentcat]['do_anything'])) {
$result = (0 < $capabilities[$parentcat]['do_anything']);
Expand All @@ -630,7 +647,7 @@ function has_capability($capability, $context=NULL, $userid=NULL, $doanything=tr
$block = get_record('block_instance','id',$context->instanceid);
if ($block->pagetype == 'course-view') {
$courseinstance = get_context_instance(CONTEXT_COURSE, $block->pageid); // needs check
$parentcats = get_parent_cats($courseinstance, CONTEXT_COURSE);
$parentcats = get_parent_cats($courseinstance);

foreach ($parentcats as $parentcat) {
if (isset($capabilities[$parentcat]['do_anything'])) {
Expand All @@ -645,13 +662,9 @@ function has_capability($capability, $context=NULL, $userid=NULL, $doanything=tr
$capcache[$cachekey] = $result;
return $result;
}
} else { // if not course-view type of blocks, check site
if (isset($capabilities[$sitecontext->id]['do_anything'])) {
$result = (0 < $capabilities[$sitecontext->id]['do_anything']);
$capcache[$cachekey] = $result;
return $result;
}
}
// blocks that do not have course as parent do not need to do any more checks - already done above

break;

default:
Expand Down Expand Up @@ -686,7 +699,7 @@ function has_capability($capability, $context=NULL, $userid=NULL, $doanything=tr
*/
function capability_search($capability, $context, $capabilities, $switchroleactive=false) {

global $USER, $CFG;
global $USER, $CFG, $COURSE;

if (!isset($context->id)) {
return 0;
Expand Down Expand Up @@ -716,27 +729,25 @@ function capability_search($capability, $context, $capabilities, $switchroleacti
$permission = capability_search($capability, $parentcontext, $capabilities, $switchroleactive);
break;

case CONTEXT_COURSECAT: // Coursecat -> coursecat or site
$coursecat = get_record('course_categories','id',$context->instanceid);
if (!empty($coursecat->parent)) { // return parent value if it exists
$parentcontext = get_context_instance(CONTEXT_COURSECAT, $coursecat->parent);
} else { // else return site value
$parentcontext = get_context_instance(CONTEXT_SYSTEM);
case CONTEXT_COURSE:
if ($switchroleactive) {
// if switchrole active, do not check permissions above the course context, blocks are an exception
break;
}
$permission = capability_search($capability, $parentcontext, $capabilities, $switchroleactive);
break;
// break is not here intentionally - because the code is the same for category and course
case CONTEXT_COURSECAT: // Coursecat -> coursecat or site
$parents = get_parent_cats($context); // cached internally

case CONTEXT_COURSE: // 1 to 1 to course cat
if (empty($switchroleactive)) {
// find the course cat, and return its value
$course = get_record('course','id',$context->instanceid);
if ($course->id == SITEID) { // In 1.8 we've separated site course and system
$parentcontext = get_context_instance(CONTEXT_SYSTEM);
} else {
$parentcontext = get_context_instance(CONTEXT_COURSECAT, $course->category);
// non recursive - should be faster
foreach ($parents as $parentid) {
$parentcontext = get_context_instance_by_id($parentid);
if (isset($capabilities[$parentcontext->id][$capability])) {
return ($capabilities[$parentcontext->id][$capability]);
}
$permission = capability_search($capability, $parentcontext, $capabilities, $switchroleactive);
}
// finally check system context
$parentcontext = get_context_instance(CONTEXT_SYSTEM);
$permission = capability_search($capability, $parentcontext, $capabilities, $switchroleactive);
break;

case CONTEXT_GROUP: // 1 to 1 to course
Expand All @@ -758,7 +769,8 @@ function capability_search($capability, $context, $capabilities, $switchroleacti
} else {
$parentcontext = get_context_instance(CONTEXT_SYSTEM);
}
$permission = capability_search($capability, $parentcontext, $capabilities, $switchroleactive);
// ignore the $switchroleactive beause we want the real block view capability defined in system context
$permission = capability_search($capability, $parentcontext, $capabilities, false);
break;

default:
Expand Down Expand Up @@ -1338,34 +1350,17 @@ function capability_prohibits($capability, $context, $sum='', $array='') {
break;

case CONTEXT_COURSECAT:
// Coursecat -> coursecat or site.
if (!$coursecat = get_record('course_categories','id',$context->instanceid)) {
$prohibits[$capability][$context->id] = false;
return false;
}
if (!empty($coursecat->parent)) {
// return parent value if exist.
$parent = get_context_instance(CONTEXT_COURSECAT, $coursecat->parent);
} else {
// Return site value.
$parent = get_context_instance(CONTEXT_SYSTEM);
}
$prohibits[$capability][$context->id] = capability_prohibits($capability, $parent);
return $prohibits[$capability][$context->id];
break;

case CONTEXT_COURSE:
// 1 to 1 to course cat.
// Find the course cat, and return its value.
if (!$course = get_record('course','id',$context->instanceid)) {
$prohibits[$capability][$context->id] = false;
return false;
}
// Yu: Separating site and site course context
if ($course->id == SITEID) {
$parents = get_parent_cats($context); // cached internally
// no workaround for recursion now - it needs some more work and maybe fixing

if (empty($parents)) {
// system context - this is either top category or frontpage course
$parent = get_context_instance(CONTEXT_SYSTEM);
} else {
$parent = get_context_instance(CONTEXT_COURSECAT, $course->category);
// parent context - recursion
$parentid = array_pop($parents);
$parent = get_context_instance_by_id($parentid);
}
$prohibits[$capability][$context->id] = capability_prohibits($capability, $parent);
return $prohibits[$capability][$context->id];
Expand Down Expand Up @@ -3018,37 +3013,11 @@ function get_parent_contexts($context) {
break;

case CONTEXT_COURSECAT: // Coursecat -> coursecat or site
if (!$coursecat = get_record('course_categories','id',$context->instanceid)) {
return array();
}
if (!empty($coursecat->parent)) { // return parent value if exist
$parent = get_context_instance(CONTEXT_COURSECAT, $coursecat->parent);
$res = array_merge(array($parent->id), get_parent_contexts($parent));
$pcontexts[$context->id] = $res;
return $res;
} else { // else return site value
$parent = get_context_instance(CONTEXT_SYSTEM);
$res = array($parent->id);
$pcontexts[$context->id] = $res;
return $res;
}
break;

case CONTEXT_COURSE: // 1 to 1 to course cat
if (!$course = get_record('course','id',$context->instanceid)) {
return array();
}
if ($course->id != SITEID) {
$parent = get_context_instance(CONTEXT_COURSECAT, $course->category);
$res = array_merge(array($parent->id), get_parent_contexts($parent));
return $res;
} else {
// Yu: Separating site and site course context
$parent = get_context_instance(CONTEXT_SYSTEM);
$res = array($parent->id);
$pcontexts[$context->id] = $res;
return $res;
}
$parents = get_parent_cats($context);
$parents = array_reverse($parents);
$systemcontext = get_context_instance(CONTEXT_SYSTEM);
return $pcontexts[$context->id] = array_merge($parents, array($systemcontext->id));
break;

case CONTEXT_GROUP: // 1 to 1 to course
Expand Down Expand Up @@ -3077,7 +3046,7 @@ function get_parent_contexts($context) {
}
break;

case CONTEXT_BLOCK: // 1 to 1 to course
case CONTEXT_BLOCK: // not necessarily 1 to 1 to course
if (!$block = get_record('block_instance','id',$context->instanceid)) {
return array();
}
Expand Down

0 comments on commit 2baa6af

Please sign in to comment.