MDL-79527 questions: category tree loading handling bad data
It should always be the case that a question category and its parent category belong to the same context. However, over the years, we have observed that this becomes violated by some data in some Moodle sites. (The suspicion is that this is a backup/restor bug of some sort which has never been tracked down.) Since this happens, we should make the code robust to it, which is what this change does. It ensure that when loading child categories, we only consider ones in the same context.
This commit is contained in:
+23
-19
@@ -1315,10 +1315,11 @@ function question_categorylist($categoryid): array {
|
||||
global $DB;
|
||||
|
||||
// Final list of category IDs.
|
||||
$categorylist = array();
|
||||
$categorylist = [];
|
||||
|
||||
// A list of category IDs to check for any sub-categories.
|
||||
$subcategories = array($categoryid);
|
||||
$subcategories = [$categoryid];
|
||||
$contextid = $DB->get_field('question_categories', 'contextid', ['id' => $categoryid]);
|
||||
|
||||
while ($subcategories) {
|
||||
foreach ($subcategories as $subcategory) {
|
||||
@@ -1329,37 +1330,40 @@ function question_categorylist($categoryid): array {
|
||||
$categorylist[$subcategory] = $subcategory;
|
||||
}
|
||||
|
||||
list ($in, $params) = $DB->get_in_or_equal($subcategories);
|
||||
[$in, $params] = $DB->get_in_or_equal($subcategories);
|
||||
$params[] = $contextid;
|
||||
|
||||
$subcategories = $DB->get_records_select_menu('question_categories', "parent $in", $params,
|
||||
null, 'id,id AS id2');
|
||||
// Order by id is not strictly needed, but it will be cheap, and makes the results deterministic.
|
||||
$subcategories = $DB->get_records_select_menu('question_categories',
|
||||
"parent $in AND contextid = ?", $params, 'id', 'id,id AS id2');
|
||||
}
|
||||
|
||||
return $categorylist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all parent categories of a given question category in decending order.
|
||||
* Get all parent categories of a given question category in descending order.
|
||||
*
|
||||
* @param int $categoryid for which you want to find the parents.
|
||||
* @return array of question category ids of all parents categories.
|
||||
*/
|
||||
function question_categorylist_parents(int $categoryid): array {
|
||||
global $DB;
|
||||
$parent = $DB->get_field('question_categories', 'parent', array('id' => $categoryid));
|
||||
if (!$parent) {
|
||||
return [];
|
||||
}
|
||||
$categorylist = [$parent];
|
||||
$currentid = $parent;
|
||||
while ($currentid) {
|
||||
$currentid = $DB->get_field('question_categories', 'parent', array('id' => $currentid));
|
||||
if ($currentid) {
|
||||
$categorylist[] = $currentid;
|
||||
|
||||
$category = $DB->get_record('question_categories', ['id' => $categoryid]);
|
||||
$contextid = $category->contextid;
|
||||
|
||||
$categorylist = [];
|
||||
while ($category->parent) {
|
||||
$category = $DB->get_record('question_categories', ['id' => $category->parent]);
|
||||
if (!$category || $category->contextid != $contextid) {
|
||||
break;
|
||||
}
|
||||
$categorylist[] = $category->id;
|
||||
}
|
||||
// Present the list in decending order (the top category at the top).
|
||||
$categorylist = array_reverse($categorylist);
|
||||
return $categorylist;
|
||||
|
||||
// Present the list in descending order (the top category at the top).
|
||||
return array_reverse($categorylist);
|
||||
}
|
||||
|
||||
// Import/Export Functions.
|
||||
|
||||
Reference in New Issue
Block a user