MDL-55580 core: Process for deprecating a capability

* Add a $deprecatedcapabilities variable to deal with deprecated
capabilities

Change-Id: I14f44d331e8a1c4bd9abe9566c78d911c0205583
Co-authored-by: Mark Johnson <[email protected]>
This commit is contained in:
Laurent David
2022-10-11 08:48:17 +01:00
committed by Mark Johnson
co-authored by Mark Johnson
parent cc4fec275f
commit bcc18e2439
8 changed files with 352 additions and 2 deletions
+71 -1
View File
@@ -2525,6 +2525,20 @@ function is_inside_frontpage(context $context) {
function get_capability_info($capabilityname) {
$caps = get_all_capabilities();
// Check for deprecated capability.
if ($deprecatedinfo = get_deprecated_capability_info($capabilityname)) {
if (!empty($deprecatedinfo['replacement'])) {
// Let's try again with this capability if it exists.
if (isset($caps[$deprecatedinfo['replacement']])) {
$capabilityname = $deprecatedinfo['replacement'];
} else {
debugging("Capability '{$capabilityname}' was supposed to be replaced with ".
"'{$deprecatedinfo['replacement']}', which does not exist !");
}
}
$fullmessage = $deprecatedinfo['fullmessage'];
debugging($fullmessage, DEBUG_DEVELOPER);
}
if (!isset($caps[$capabilityname])) {
return null;
}
@@ -2532,6 +2546,57 @@ function get_capability_info($capabilityname) {
return (object) $caps[$capabilityname];
}
/**
* Returns deprecation info for this particular capabilty (cached)
*
* Do not use this function except in the get_capability_info
*
* @param string $capabilityname
* @return stdClass|null with deprecation message and potential replacement if not null
*/
function get_deprecated_capability_info($capabilityname) {
// Here if we do like get_all_capabilities, we run into performance issues as the full array is unserialised each time.
// We could have used an adhoc task but this also had performance issue. Last solution was to create a cache using
// the official caches.php file. The performance issue shows in test_permission_evaluation.
$cache = cache::make('core', 'deprecatedcapabilities');
// Cache has not be initialised.
if (!$cache->get('deprecated_capabilities_initialised')) {
// Look for deprecated capabilities in each components.
$allcaps = get_all_capabilities();
$components = [];
$alldeprecatedcaps = [];
foreach ($allcaps as $cap) {
if (!in_array($cap['component'], $components)) {
$components[] = $cap['component'];
$defpath = core_component::get_component_directory($cap['component']).'/db/access.php';
if (file_exists($defpath)) {
$deprecatedcapabilities = [];
require($defpath);
if (!empty($deprecatedcapabilities)) {
foreach ($deprecatedcapabilities as $cname => $cdef) {
$cache->set($cname, $cdef);
}
}
}
}
}
$cache->set('deprecated_capabilities_initialised', true);
}
if (!$cache->has($capabilityname)) {
return null;
}
$deprecatedinfo = $cache->get($capabilityname);
$deprecatedinfo['fullmessage'] = "The capability '{$capabilityname}' is deprecated.";
if (!empty($deprecatedinfo['message'])) {
$deprecatedinfo['fullmessage'] .= $deprecatedinfo['message'];
}
if (!empty($deprecatedinfo['replacement'])) {
$deprecatedinfo['fullmessage'] .=
"It will be replaced by '{$deprecatedinfo['replacement']}'.";
}
return $deprecatedinfo;
}
/**
* Returns all capabilitiy records, preferably from MUC and not database.
*
@@ -4135,6 +4200,11 @@ function get_user_capability_contexts(string $capability, bool $getcategories, $
$userid = $USER->id;
}
if (!$capinfo = get_capability_info($capability)) {
debugging('Capability "'.$capability.'" was not found! This has to be fixed in code.');
return [false, false];
}
if ($doanything && is_siteadmin($userid)) {
// If the user is a site admin and $doanything is enabled then there is no need to restrict
// the list of courses.
@@ -4143,7 +4213,7 @@ function get_user_capability_contexts(string $capability, bool $getcategories, $
} else {
// Gets SQL to limit contexts ('x' table) to those where the user has this capability.
list ($contextlimitsql, $contextlimitparams) = \core\access\get_user_capability_course_helper::get_sql(
$userid, $capability);
$userid, $capinfo->name);
if (!$contextlimitsql) {
// If the does not have this capability in any context, return false without querying.
return [false, false];