diff --git a/lib/classes/plugin_manager.php b/lib/classes/plugin_manager.php index 348adef1fad..d49e1a2e2a1 100644 --- a/lib/classes/plugin_manager.php +++ b/lib/classes/plugin_manager.php @@ -310,9 +310,9 @@ class plugin_manager { $this->presentplugins = []; - $plugintypes = core_component::get_plugin_types(); - foreach ($plugintypes as $type => $typedir) { - $plugs = core_component::get_plugin_list($type); + $allplugintypes = core_component::get_all_plugin_types(); + foreach ($allplugintypes as $type => $typedir) { + $plugs = core_component::get_all_plugins_list($type); foreach ($plugs as $plug => $fullplug) { $module = new stdClass(); $plugin = new stdClass(); @@ -371,21 +371,27 @@ class plugin_manager { /** * Returns a tree of known plugins and information about them * + * @param bool $includeindeprecation whether to include plugins which are in deprecation (deprecated or deleted status). * @return array 2D array. The first keys are plugin type names (e.g. qtype); * the second keys are the plugin local name (e.g. multichoice); and * the values are the corresponding objects extending {@link \core\plugininfo\base} */ - public function get_plugins() { + public function get_plugins(bool $includeindeprecation = false) { $this->init_pluginsinfo_property(); // Make sure all types are initialised. foreach ($this->pluginsinfo as $plugintype => $list) { if ($list === null) { - $this->get_plugins_of_type($plugintype); + $this->get_plugins_of_type($plugintype, $includeindeprecation); } } - return $this->pluginsinfo; + if ($includeindeprecation) { + return $this->pluginsinfo; + } + return array_filter($this->pluginsinfo, function($key) { + return !core_component::is_plugintype_in_deprecation($key); + }, ARRAY_FILTER_USE_KEY); } /** @@ -395,14 +401,16 @@ class plugin_manager { * If the given type is not known, empty array is returned. * * @param string $type plugin type, e.g. 'mod' or 'workshopallocation' + * @param bool $includeindeprecation whether to include plugins which are in deprecation (deprecated or deleted status). * @return \core\plugininfo\base[] (string) plugin name => corresponding subclass of {@link \core\plugininfo\base} */ - public function get_plugins_of_type($type) { + public function get_plugins_of_type($type, bool $includeindeprecation = false) { global $CFG; $this->init_pluginsinfo_property(); - if (!array_key_exists($type, $this->pluginsinfo)) { + $exclude = !$includeindeprecation && core_component::is_plugintype_in_deprecation($type); + if (!array_key_exists($type, $this->pluginsinfo) || $exclude) { return []; } @@ -410,9 +418,9 @@ class plugin_manager { return $this->pluginsinfo[$type]; } - $types = core_component::get_plugin_types(); + $allplugintypes = core_component::get_all_plugin_types(); - if (!isset($types[$type])) { + if (!isset($allplugintypes[$type])) { // Orphaned subplugins! $plugintypeclass = static::resolve_plugininfo_class($type); $this->pluginsinfo[$type] = $plugintypeclass::get_plugins($type, null, $plugintypeclass, $this); @@ -420,7 +428,9 @@ class plugin_manager { } $plugintypeclass = static::resolve_plugininfo_class($type); - $plugins = $plugintypeclass::get_plugins($type, $types[$type], $plugintypeclass, $this); + if (isset($allplugintypes[$type])) { + $plugins = $plugintypeclass::get_plugins($type, $allplugintypes[$type], $plugintypeclass, $this); + } $this->pluginsinfo[$type] = $plugins; return $this->pluginsinfo[$type]; @@ -435,13 +445,19 @@ class plugin_manager { } $this->pluginsinfo = []; - $plugintypes = $this->get_plugin_types(); - + // The pluginsinfo instance var contains keys for all plugin types, including those currently in deprecation. + // Other methods should filter their returns as needed, based on key checks, or by checking either + // $plugininfo->is_deprecated() or $plugininfo->is_deleted(). + $plugintypes = array_merge( + $this->get_plugin_types(), + \core_component::get_deprecated_plugin_types(), + \core_component::get_deleted_plugin_types() + ); foreach ($plugintypes as $plugintype => $plugintyperootdir) { $this->pluginsinfo[$plugintype] = null; } - // Add orphaned subplugin types. + // Add orphaned plugins. $this->load_installed_plugins(); foreach ($this->installedplugins as $plugintype => $unused) { if (!isset($plugintypes[$plugintype])) { @@ -457,8 +473,9 @@ class plugin_manager { * @return string name of pluginfo class for give plugin type */ public static function resolve_plugininfo_class($type) { - $plugintypes = core_component::get_plugin_types(); - if (!isset($plugintypes[$type])) { + $allplugintypes = core_component::get_all_plugin_types(); + + if (!isset($allplugintypes[$type])) { return '\core\plugininfo\orphaned'; } @@ -556,7 +573,7 @@ class plugin_manager { foreach (core_component::get_plugin_types_with_subplugins() as $type => $ignored) { foreach (core_component::get_plugin_list($type) as $plugin => $componentdir) { $component = $type . '_' . $plugin; - $subplugins = core_component::get_subplugins($component); + $subplugins = core_component::get_subplugins($component) ?? []; if (!$subplugins) { continue; } @@ -578,9 +595,13 @@ class plugin_manager { * If the given subplugin type is not actually a subplugin, returns false. * * @param string $subplugintype the name of subplugin type, eg. workshopform or quiz + * @param bool $includedeprecated whether to check deprecated subplugin types. * @return false|string the name of the parent plugin, eg. mod_workshop */ - public function get_parent_of_subplugin($subplugintype) { + public function get_parent_of_subplugin($subplugintype, bool $includedeprecated = false) { + if (!$includedeprecated && core_component::is_plugintype_in_deprecation($subplugintype)) { + return false; + } $parent = core_component::get_subtype_parent($subplugintype); if (!$parent) { return false; @@ -657,7 +678,7 @@ class plugin_manager { */ public function get_plugin_info($component) { [$type, $name] = core_component::normalize_component($component); - $plugins = $this->get_plugins_of_type($type); + $plugins = $this->get_plugins_of_type($type, true); if (isset($plugins[$name])) { return $plugins[$name]; } else { @@ -1701,7 +1722,8 @@ class plugin_manager { public function get_plugintype_root($plugintype) { $plugintypepath = null; - foreach (core_component::get_plugin_types() as $type => $fullpath) { + $allplugintypes = core_component::get_all_plugin_types(); + foreach ($allplugintypes as $type => $fullpath) { if ($type === $plugintype) { $plugintypepath = $fullpath; break; diff --git a/lib/classes/plugininfo/base.php b/lib/classes/plugininfo/base.php index f26bb591c9a..7bf55f08c0d 100644 --- a/lib/classes/plugininfo/base.php +++ b/lib/classes/plugininfo/base.php @@ -86,6 +86,12 @@ abstract class base { /** @var string Name of the plugin */ public $component = ''; + /** @var bool whether the plugin is that of a phase 1 deprecated type or subplugin type. */ + public $deprecatedtype = false; + + /** @var bool whether the plugin is that of a phase 2 deprecated (deleted) type or subplugin type. */ + public $deletedtype = false; + /** * Whether this plugintype supports its plugins being disabled. * @@ -143,15 +149,18 @@ abstract class base { * @return array of plugintype classes, indexed by the plugin name */ public static function get_plugins($type, $typerootdir, $typeclass, $pluginman) { - // Get the information about plugins at the disk. - $plugins = core_component::get_plugin_list($type); + // Get the information about plugins at the disk, including deprecated plugins. + $plugins = core_component::get_all_plugins_list($type); + + // Also included deleted plugins. + $return = array(); foreach ($plugins as $pluginname => $pluginrootdir) { $return[$pluginname] = self::make_plugin_instance($type, $typerootdir, $pluginname, $pluginrootdir, $typeclass, $pluginman); } - // Fetch missing incorrectly uninstalled plugins. + // Fetch missing incorrectly uninstalled plugins, including deprecated plugins which are not included above. $plugins = $pluginman->get_installed_plugins($type); foreach ($plugins as $name => $version) { @@ -168,6 +177,7 @@ abstract class base { $plugin->versiondb = $version; $plugin->pluginman = $pluginman; $plugin->init_is_standard(); + $plugin->init_is_deprecated(); $return[$name] = $plugin; } @@ -199,6 +209,7 @@ abstract class base { $plugin->load_disk_version(); $plugin->load_db_version(); $plugin->init_is_standard(); + $plugin->init_is_deprecated(); return $plugin; } @@ -270,6 +281,7 @@ abstract class base { * data) or is missing from disk. */ public function load_disk_version() { + // Note: this includes deprecated plugins. $versions = $this->pluginman->get_present_plugins($this->type); $this->versiondisk = null; @@ -349,7 +361,7 @@ abstract class base { * @return string|bool false if not a subplugin, name of the parent otherwise */ public function get_parent_plugin() { - return $this->pluginman->get_parent_of_subplugin($this->type); + return $this->pluginman->get_parent_of_subplugin($this->type, true); } /** @@ -396,6 +408,21 @@ abstract class base { } } + /** + * Init some instance props denoting the deprecation state of the plugin. + * + * Sets {@see $deprecatedtype} property, indicating whether the plugintype is phase 1 deprecated. + * Sets {@see $deletedtype} property, indicating whether the plugintype is phase 2 deprecated. + * Sets {@see $displayname} property to the plugin name phase 2 deprecated plugins since lang string support has then ended. + * + * @return void + */ + final public function init_is_deprecated(): void { + $this->deprecatedtype = \core_component::is_deprecated_plugin_type($this->type); + $this->deletedtype = \core_component::is_deleted_plugin_type($this->type); + $this->displayname = $this->deletedtype ? $this->name : $this->displayname; + } + /** * Returns true if the plugin is shipped with the official distribution * of the current Moodle version, false otherwise. @@ -500,6 +527,24 @@ abstract class base { return isset($enabled[$this->name]); } + /** + * Return whether this plugin is deprecated (i.e. the plugin type to which it belongs is deprecated). + * + * @return bool + */ + public function is_deprecated(): bool { + return $this->deprecatedtype; + } + + /** + * Return whether this plugin is deleted (i.e. the plugin type to which it belongs is deleted). + * + * @return bool + */ + public function is_deleted(): bool { + return $this->deletedtype; + } + /** * If there are updates for this plugin available, returns them. *