Skip to content

Commit

Permalink
MDL-65646 core: Move component storage to json
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewnicols committed Jun 13, 2019
1 parent f350727 commit 29c442c
Show file tree
Hide file tree
Showing 31 changed files with 347 additions and 183 deletions.
5 changes: 5 additions & 0 deletions admin/tool/log/db/subplugins.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"plugintypes": {
"logstore": "admin\/tool\/log\/store"
}
}
3 changes: 2 additions & 1 deletion admin/tool/log/db/subplugins.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

$subplugins = array('logstore' => 'admin/tool/log/store');
debugging('Use of subplugins.php has been deprecated. Please provide a subplugins.json instead.', DEBUG_DEVELOPER);
$subplugins = (array) json_decode(file_get_contents(__DIR__ . "/subplugins.json"))->plugintypes;
9 changes: 4 additions & 5 deletions backup/util/plan/backup_structure_step.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ protected function add_plugin_structure($plugintype, $element, $multiple) {
* looking for /mod/modulenanme subplugins. This new method is a generalization of the
* existing one for activities, supporting all subplugins injecting information everywhere.
*
* @param string $subplugintype type of subplugin as defined in plugin's db/subplugins.php.
* @param string $subplugintype type of subplugin as defined in plugin's db/subplugins.json.
* @param backup_nested_element $element element in the backup tree (anywhere) that
* we are going to add subplugin information to.
* @param bool $multiple to define if multiple subplugins can produce information
Expand Down Expand Up @@ -206,11 +206,10 @@ protected function add_subplugin_structure($subplugintype, $element, $multiple,
}

// Check the requested subplugintype is a valid one.
$subpluginsfile = core_component::get_component_directory($plugintype . '_' . $pluginname) . '/db/subplugins.php';
if (!file_exists($subpluginsfile)) {
throw new backup_step_exception('plugin_missing_subplugins_php_file', array($plugintype, $pluginname));
$subplugins = core_component::get_subplugins("{$plugintype}_{$pluginname}");
if (null === $subplugins) {
throw new backup_step_exception('plugin_missing_subplugins_configuration', [$plugintype, $pluginname]);
}
include($subpluginsfile);
if (!array_key_exists($subplugintype, $subplugins)) {
throw new backup_step_exception('incorrect_subplugin_type', $subplugintype);
}
Expand Down
9 changes: 4 additions & 5 deletions backup/util/plan/restore_structure_step.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ protected function add_plugin_structure($plugintype, $element) {
* looking for /mod/modulenanme subplugins. This new method is a generalization of the
* existing one for activities, supporting all subplugins injecting information everywhere.
*
* @param string $subplugintype type of subplugin as defined in plugin's db/subplugins.php.
* @param string $subplugintype type of subplugin as defined in plugin's db/subplugins.json.
* @param restore_path_element $element element in the structure restore tree that
* we are going to add subplugin information to.
* @param string $plugintype type of the plugin.
Expand Down Expand Up @@ -336,11 +336,10 @@ protected function add_subplugin_structure($subplugintype, $element, $plugintype
}

// Check the requested subplugintype is a valid one.
$subpluginsfile = core_component::get_component_directory($plugintype . '_' . $pluginname) . '/db/subplugins.php';
if (!file_exists($subpluginsfile)) {
throw new restore_step_exception('plugin_missing_subplugins_php_file', array($plugintype, $pluginname));
$subplugins = core_component::get_subplugins("{$plugintype}_{$pluginname}");
if (null === $subplugins) {
throw new restore_step_exception('plugin_missing_subplugins_configuration', array($plugintype, $pluginname));
}
include($subpluginsfile);
if (!array_key_exists($subplugintype, $subplugins)) {
throw new restore_step_exception('incorrect_subplugin_type', $subplugintype);
}
Expand Down
8 changes: 4 additions & 4 deletions backup/util/plan/tests/step_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ public function test_backup_structure_step_add_subplugin_structure() {
$this->assertTrue(false, 'base_step_exception expected');
} catch (exception $e) {
$this->assertTrue($e instanceof backup_step_exception);
$this->assertEquals('plugin_missing_subplugins_php_file', $e->errorcode);
$this->assertEquals('plugin_missing_subplugins_configuration', $e->errorcode);
}
// Wrong BC (defaulting to mod and modulename) use not having subplugins.
try {
Expand All @@ -250,7 +250,7 @@ public function test_backup_structure_step_add_subplugin_structure() {
$this->assertTrue(false, 'base_step_exception expected');
} catch (exception $e) {
$this->assertTrue($e instanceof backup_step_exception);
$this->assertEquals('plugin_missing_subplugins_php_file', $e->errorcode);
$this->assertEquals('plugin_missing_subplugins_configuration', $e->errorcode);
}
// Wrong subplugin type.
try {
Expand Down Expand Up @@ -362,7 +362,7 @@ public function test_restore_structure_step_add_subplugin_structure() {
$this->assertTrue(false, 'base_step_exception expected');
} catch (exception $e) {
$this->assertTrue($e instanceof restore_step_exception);
$this->assertEquals('plugin_missing_subplugins_php_file', $e->errorcode);
$this->assertEquals('plugin_missing_subplugins_configuration', $e->errorcode);
}
// Wrong BC (defaulting to mod and modulename) use not having subplugins.
try {
Expand All @@ -371,7 +371,7 @@ public function test_restore_structure_step_add_subplugin_structure() {
$this->assertTrue(false, 'base_step_exception expected');
} catch (exception $e) {
$this->assertTrue($e instanceof restore_step_exception);
$this->assertEquals('plugin_missing_subplugins_php_file', $e->errorcode);
$this->assertEquals('plugin_missing_subplugins_configuration', $e->errorcode);
}
// Wrong subplugin type.
try {
Expand Down
25 changes: 16 additions & 9 deletions lib/accesslib.php
Original file line number Diff line number Diff line change
Expand Up @@ -7010,20 +7010,27 @@ public function get_capabilities() {
$module = $DB->get_record('modules', array('id'=>$cm->module));

$subcaps = array();
$subpluginsfile = "$CFG->dirroot/mod/$module->name/db/subplugins.php";
if (file_exists($subpluginsfile)) {

$modulepath = "{$CFG->dirroot}/mod/{$module->name}";
if (file_exists("{$modulepath}/db/subplugins.json")) {
$subplugins = (array) json_decode(file_get_contents("{$modulepath}/db/subplugins.json"))->plugintypes;
} else if (file_exists("{$modulepath}/db/subplugins.php")) {
debugging('Use of subplugins.php has been deprecated. ' .
'Please update your plugin to provide a subplugins.json file instead.',
DEBUG_DEVELOPER);
$subplugins = array(); // should be redefined in the file
include($subpluginsfile);
if (!empty($subplugins)) {
foreach (array_keys($subplugins) as $subplugintype) {
foreach (array_keys(core_component::get_plugin_list($subplugintype)) as $subpluginname) {
$subcaps = array_merge($subcaps, array_keys(load_capability_def($subplugintype.'_'.$subpluginname)));
}
include("{$modulepath}/db/subplugins.php");
}

if (!empty($subplugins)) {
foreach (array_keys($subplugins) as $subplugintype) {
foreach (array_keys(core_component::get_plugin_list($subplugintype)) as $subpluginname) {
$subcaps = array_merge($subcaps, array_keys(load_capability_def($subplugintype.'_'.$subpluginname)));
}
}
}

$modfile = "$CFG->dirroot/mod/$module->name/lib.php";
$modfile = "{$modulepath}/lib.php";
$extracaps = array();
if (file_exists($modfile)) {
include_once($modfile);
Expand Down
19 changes: 14 additions & 5 deletions lib/adminlib.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,17 +132,26 @@ function uninstall_plugin($type, $name) {
$subplugintypes = core_component::get_plugin_types_with_subplugins();
if (isset($subplugintypes[$type])) {
$base = core_component::get_plugin_directory($type, $name);
if (file_exists("$base/db/subplugins.php")) {
$subplugins = array();
include("$base/db/subplugins.php");
foreach ($subplugins as $subplugintype=>$dir) {

$subpluginsfile = "{$base}/db/subplugins.json";
if (file_exists($subpluginsfile)) {
$subplugins = (array) json_decode(file_get_contents($subpluginsfile))->plugintypes;
} else if (file_exists("{$base}/db/subplugins.php")) {
debugging('Use of subplugins.php has been deprecated. ' .
'Please update your plugin to provide a subplugins.json file instead.',
DEBUG_DEVELOPER);
$subplugins = [];
include("{$base}/db/subplugins.php");
}

if (!empty($subplugins)) {
foreach (array_keys($subplugins) as $subplugintype) {
$instances = core_component::get_plugin_list($subplugintype);
foreach ($instances as $subpluginname => $notusedpluginpath) {
uninstall_plugin($subplugintype, $subpluginname);
}
}
}

}

$component = $type . '_' . $name; // eg. 'qtype_multichoice' or 'workshopgrading_accumulative' or 'mod_forum'
Expand Down
191 changes: 63 additions & 128 deletions lib/classes/component.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ class core_component {
/** @var array list plugin types that support subplugins, do not add more here unless absolutely necessary */
protected static $supportsubplugins = array('mod', 'editor', 'tool', 'local');

/** @var object JSON source of the component data */
protected static $componentsource = null;
/** @var array cache of plugin types */
protected static $plugintypes = null;
/** @var array cache of plugin locations */
Expand Down Expand Up @@ -416,79 +418,20 @@ protected static function fetch_subsystems() {
global $CFG;

// NOTE: Any additions here must be verified to not collide with existing add-on modules and subplugins!!!
$info = [];
foreach (self::fetch_component_source('subsystems') as $subsystem => $path) {
// Replace admin/ directory with the config setting.
if ($CFG->admin !== 'admin') {
if ($path === 'admin') {
$path = $CFG->admin;
}
if (strpos($path, 'admin/') === 0) {
$path = $CFG->admin . substr($path, 0, 5);
}
}

$info = array(
'access' => null,
'admin' => $CFG->dirroot.'/'.$CFG->admin,
'analytics' => $CFG->dirroot . '/analytics',
'antivirus' => $CFG->dirroot . '/lib/antivirus',
'auth' => $CFG->dirroot.'/auth',
'availability' => $CFG->dirroot . '/availability',
'backup' => $CFG->dirroot.'/backup/util/ui',
'badges' => $CFG->dirroot.'/badges',
'block' => $CFG->dirroot.'/blocks',
'blog' => $CFG->dirroot.'/blog',
'bulkusers' => null,
'cache' => $CFG->dirroot.'/cache',
'calendar' => $CFG->dirroot.'/calendar',
'cohort' => $CFG->dirroot.'/cohort',
'comment' => $CFG->dirroot.'/comment',
'competency' => $CFG->dirroot.'/competency',
'completion' => $CFG->dirroot.'/completion',
'countries' => null,
'course' => $CFG->dirroot.'/course',
'currencies' => null,
'customfield' => $CFG->dirroot.'/customfield',
'dbtransfer' => null,
'debug' => null,
'editor' => $CFG->dirroot.'/lib/editor',
'edufields' => null,
'enrol' => $CFG->dirroot.'/enrol',
'error' => null,
'favourites' => $CFG->dirroot . '/favourites',
'filepicker' => null,
'fileconverter' => $CFG->dirroot.'/files/converter',
'files' => $CFG->dirroot.'/files',
'filters' => $CFG->dirroot.'/filter',
//'fonts' => null, // Bogus.
'form' => $CFG->dirroot.'/lib/form',
'grades' => $CFG->dirroot.'/grade',
'grading' => $CFG->dirroot.'/grade/grading',
'group' => $CFG->dirroot.'/group',
'help' => null,
'hub' => null,
'imscc' => null,
'install' => null,
'iso6392' => null,
'langconfig' => null,
'license' => null,
'mathslib' => null,
'media' => $CFG->dirroot.'/media',
'message' => $CFG->dirroot.'/message',
'mimetypes' => null,
'mnet' => $CFG->dirroot.'/mnet',
//'moodle.org' => null, // Not used any more.
'my' => $CFG->dirroot.'/my',
'notes' => $CFG->dirroot.'/notes',
'pagetype' => null,
'pix' => null,
'plagiarism' => $CFG->dirroot.'/plagiarism',
'plugin' => null,
'portfolio' => $CFG->dirroot.'/portfolio',
'privacy' => $CFG->dirroot . '/privacy',
'question' => $CFG->dirroot.'/question',
'rating' => $CFG->dirroot.'/rating',
'repository' => $CFG->dirroot.'/repository',
'rss' => $CFG->dirroot.'/rss',
'role' => $CFG->dirroot.'/'.$CFG->admin.'/roles',
'search' => $CFG->dirroot.'/search',
'table' => null,
'tag' => $CFG->dirroot.'/tag',
'timezones' => null,
'user' => $CFG->dirroot.'/user',
'userkey' => $CFG->dirroot.'/lib/userkey',
'webservice' => $CFG->dirroot.'/webservice',
);
$info[$subsystem] = empty($path) ? null : "{$CFG->dirroot}/{$path}";
}

return $info;
}
Expand All @@ -500,43 +443,15 @@ protected static function fetch_subsystems() {
protected static function fetch_plugintypes() {
global $CFG;

$types = array(
'antivirus' => $CFG->dirroot . '/lib/antivirus',
'availability' => $CFG->dirroot . '/availability/condition',
'qtype' => $CFG->dirroot.'/question/type',
'mod' => $CFG->dirroot.'/mod',
'auth' => $CFG->dirroot.'/auth',
'calendartype' => $CFG->dirroot.'/calendar/type',
'customfield' => $CFG->dirroot.'/customfield/field',
'enrol' => $CFG->dirroot.'/enrol',
'message' => $CFG->dirroot.'/message/output',
'block' => $CFG->dirroot.'/blocks',
'media' => $CFG->dirroot.'/media/player',
'filter' => $CFG->dirroot.'/filter',
'editor' => $CFG->dirroot.'/lib/editor',
'format' => $CFG->dirroot.'/course/format',
'dataformat' => $CFG->dirroot.'/dataformat',
'profilefield' => $CFG->dirroot.'/user/profile/field',
'report' => $CFG->dirroot.'/report',
'coursereport' => $CFG->dirroot.'/course/report', // Must be after system reports.
'gradeexport' => $CFG->dirroot.'/grade/export',
'gradeimport' => $CFG->dirroot.'/grade/import',
'gradereport' => $CFG->dirroot.'/grade/report',
'gradingform' => $CFG->dirroot.'/grade/grading/form',
'mlbackend' => $CFG->dirroot.'/lib/mlbackend',
'mnetservice' => $CFG->dirroot.'/mnet/service',
'webservice' => $CFG->dirroot.'/webservice',
'repository' => $CFG->dirroot.'/repository',
'portfolio' => $CFG->dirroot.'/portfolio',
'search' => $CFG->dirroot.'/search/engine',
'qbehaviour' => $CFG->dirroot.'/question/behaviour',
'qformat' => $CFG->dirroot.'/question/format',
'plagiarism' => $CFG->dirroot.'/plagiarism',
'tool' => $CFG->dirroot.'/'.$CFG->admin.'/tool',
'cachestore' => $CFG->dirroot.'/cache/stores',
'cachelock' => $CFG->dirroot.'/cache/locks',
'fileconverter' => $CFG->dirroot.'/files/converter',
);
$types = [];
foreach (self::fetch_component_source('plugintypes') as $plugintype => $path) {
// Replace admin/ with the config setting.
if ($CFG->admin !== 'admin' && strpos($path, 'admin/') === 0) {
$path = $CFG->admin . substr($path, 0, 5);
}
$types[$plugintype] = "{$CFG->dirroot}/{$path}";
}

$parents = array();
$subplugins = array();

Expand Down Expand Up @@ -596,6 +511,19 @@ protected static function fetch_plugintypes() {
return array($types, $parents, $subplugins);
}

/**
* Returns the component source content as loaded from /lib/components.json.
*
* @return array
*/
protected static function fetch_component_source(string $key) {
if (null === self::$componentsource) {
self::$componentsource = (array) json_decode(file_get_contents(__DIR__ . '/../components.json'));
}

return (array) self::$componentsource[$key];
}

/**
* Returns list of subtypes.
* @param string $ownerdir
Expand All @@ -605,28 +533,35 @@ protected static function fetch_subtypes($ownerdir) {
global $CFG;

$types = array();
if (file_exists("$ownerdir/db/subplugins.php")) {
$subplugins = array();
$subplugins = array();
if (file_exists("$ownerdir/db/subplugins.json")) {
$subplugins = (array) json_decode(file_get_contents("$ownerdir/db/subplugins.json"))->plugintypes;
} else if (file_exists("$ownerdir/db/subplugins.php")) {
debugging('Use of subplugins.php has been deprecated. ' .
'Please update your plugin to provide a subplugins.json file instead.',
DEBUG_DEVELOPER);
include("$ownerdir/db/subplugins.php");
foreach ($subplugins as $subtype => $dir) {
if (!preg_match('/^[a-z][a-z0-9]*$/', $subtype)) {
error_log("Invalid subtype '$subtype'' detected in '$ownerdir', invalid characters present.");
continue;
}
if (isset(self::$subsystems[$subtype])) {
error_log("Invalid subtype '$subtype'' detected in '$ownerdir', duplicates core subsystem.");
continue;
}
if ($CFG->admin !== 'admin' and strpos($dir, 'admin/') === 0) {
$dir = preg_replace('|^admin/|', "$CFG->admin/", $dir);
}
if (!is_dir("$CFG->dirroot/$dir")) {
error_log("Invalid subtype directory '$dir' detected in '$ownerdir'.");
continue;
}
$types[$subtype] = "$CFG->dirroot/$dir";
}

foreach ($subplugins as $subtype => $dir) {
if (!preg_match('/^[a-z][a-z0-9]*$/', $subtype)) {
error_log("Invalid subtype '$subtype'' detected in '$ownerdir', invalid characters present.");
continue;
}
if (isset(self::$subsystems[$subtype])) {
error_log("Invalid subtype '$subtype'' detected in '$ownerdir', duplicates core subsystem.");
continue;
}
if ($CFG->admin !== 'admin' and strpos($dir, 'admin/') === 0) {
$dir = preg_replace('|^admin/|', "$CFG->admin/", $dir);
}
if (!is_dir("$CFG->dirroot/$dir")) {
error_log("Invalid subtype directory '$dir' detected in '$ownerdir'.");
continue;
}
$types[$subtype] = "$CFG->dirroot/$dir";
}

return $types;
}

Expand Down
Loading

0 comments on commit 29c442c

Please sign in to comment.