Skip to content

Commit

Permalink
pre-cache active filters for course categories
Browse files Browse the repository at this point in the history
If $CFG->filterall is true, pre-cache the list
of filters for course categories when on
course/index.php or course/category.php.
This can significantly reduce database queries
for sites with a large number of course categories
and that have the multilang filter enabled for these.
  • Loading branch information
brki committed Oct 13, 2012
1 parent 562dbe4 commit da23cce
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 0 deletions.
4 changes: 4 additions & 0 deletions course/category.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@
require_capability('moodle/category:viewhiddencategories', $context);
}

if (!empty($CFG->filterall)) {
filter_preload_course_categories();
}

$canmanage = has_capability('moodle/category:manage', $context);
$sesskeyprovided = !empty($sesskey) && confirm_sesskey($sesskey);

Expand Down
3 changes: 3 additions & 0 deletions course/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@
$straction = get_string('action');
$strfulllistofcourses = get_string('fulllistofcourses');

if (!empty($CFG->filterall)) {
filter_preload_course_categories();
}

/// Unless it's an editing admin, just print the regular listing of courses/categories
if (!$adminediting) {
Expand Down
107 changes: 107 additions & 0 deletions lib/filterlib.php
Original file line number Diff line number Diff line change
Expand Up @@ -1493,3 +1493,110 @@ function openpopup(url,name,options,fullscreen) {
//last chance - try adding head element
return preg_replace("/<html.*?>/is", "\\0<head>".$js.'</head>', $text);
}

/**
* Preloads filters used for course categories.
* This reduces the database queries necessary when many categories
* will be processed. It adds entries to the $FILTERLIB_PRIVATE variable
* if there are any filters active for any course categories.
*/
function filter_preload_course_categories()
{
global $DB, $FILTERLIB_PRIVATE;

if (!isset($FILTERLIB_PRIVATE)) {
$FILTERLIB_PRIVATE = new stdClass();
}

if (!isset($FILTERLIB_PRIVATE->active)) {
$FILTERLIB_PRIVATE->active = array();
}

$columns = context_helper::get_preload_record_columns_sql('ctx');
$rs = $DB->get_recordset_sql("
SELECT id, path, $columns
FROM {context} ctx
WHERE id = 1
OR contextlevel = :coursecatcontext
ORDER BY path
", array('coursecatcontext' => CONTEXT_COURSECAT ));

$contexts = array();
foreach ($rs as $contextrecord) {
context_helper::preload_from_record($contextrecord);
$contexts[$contextrecord->id] = context::instance_by_id($contextrecord->id);
}
$rs->close();

$rs = $DB->get_recordset_sql("
SELECT active.filter, c.path, active.contextid, active.is_active, fc.name, fc.value
FROM mdl_context c,
(SELECT f.filter, f.contextid, MAX(f.sortorder) AS sortorder, f.active, ctx.depth,
CASE WHEN max(f.active * ctx.depth) > -min(f.active * ctx.depth) THEN 1 ELSE 0 END AS is_active
FROM mdl_filter_active f
JOIN mdl_context ctx ON f.contextid = ctx.id
WHERE ctx.id = 1
OR ctx.contextlevel = 40
GROUP BY filter, f.contextid, f.active, ctx.depth) active
LEFT JOIN mdl_filter_config fc ON fc.filter = active.filter
WHERE c.id = active.contextid
ORDER BY active.contextid, c.path, active.sortorder
");

$activefilters = array();
$inactivefilters = array();
foreach ($rs as $state) {
$contextid = $state->contextid;
$filter = $state->filter;
if ($state->is_active) {
if (!isset($activefilters[$contextid])) {
$activefilters[$contextid] = array();
}
if (!isset($activefilters[$contextid][$filter])) {
$activefilters[$contextid][$filter] = array();
}
if (!is_null($state->name)) {
$activefilters[$contextid][$filter][$state->name] = $state->value;
}
} else {
if (!isset($inactivefilters[$contextid])) {
$inactivefilters[$contextid] = array();
}
$inactivefilters[$contextid][$filter] = 1;
}
}
$rs->close();

foreach ($contexts as $contextid => $context) {
if ($filters = find_active_filters($context, $contexts, $activefilters, $inactivefilters)) {
$FILTERLIB_PRIVATE->active[$contextid] = $filters;
}
}
}

/**
* Helper function for filter_preload_course_categories() to extract
* the active filters for the given context.
*
* @param context_coursecat $context
* @param array $contexts
* @param array $activefilters
* @param array $inactivefilters
*/
function find_active_filters($context, $contexts, $activefilters, $inactivefilters)
{
$currentcontext = $context;
while (1) {
$ctx = $currentcontext->id;
if (isset($activefilters[$ctx])) {
return $activefilters[$ctx];
}
if (isset($inactivefilters[$ctx])) {
return false;
}
if (!$parent = $currentcontext->get_parent_context()) {
return false;
}
$currentcontext = $contexts[$parent->id];
}
}

0 comments on commit da23cce

Please sign in to comment.