Permalink
Browse files

MDL-39087 Simplify get_uninstall_url() interpretation

The get_uninstall_url() method of all subclasses of plugininfo_base
class is now expected to always return moodle_url. Subclasses can use
the new method is_uninstall_allowed() to control the availability of the
'Uninstall' link at the Plugins overview page (previously they would do
it by get_uninstall_url() returning null). By default, URL to a new
general plugin uninstall tool is returned. Unless the plugin type needs
extra steps that can't be handled by plugininfo_xxx::uninstall() method
or xmldb_xxx_uninstall() function, this default URL should satisfy all
plugin types.

The overall logic is implemented in plugin_manager::can_install_plugin()
that respects the plugininfo class decision and vetoes it in certain
cases (typically when plugin or its subplugin is required by some other
plugin).
  • Loading branch information...
1 parent d7d48b4 commit 73658371eb3a7f6569e0d9d9cafff1dfb4beea02 @mudrd8mz mudrd8mz committed Apr 11, 2013
View
@@ -1229,8 +1229,8 @@ public function plugins_control_panel(plugin_manager $pluginman, array $options
$actions[] = html_writer::link($settingsurl, get_string('settings', 'core_plugin'), array('class' => 'settings'));
}
- $uninstallurl = $plugin->get_uninstall_url();
- if (!is_null($uninstallurl)) {
+ if ($pluginman->can_uninstall_plugin($plugin->component)) {
+ $uninstallurl = $plugin->get_uninstall_url();
$actions[] = html_writer::link($uninstallurl, get_string('uninstall', 'core_plugin'), array('class' => 'uninstall'));
}
@@ -35,6 +35,11 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class plugininfo_tinymce extends plugininfo_base {
+
+ public function is_uninstall_allowed() {
+ return true;
+ }
+
public function get_uninstall_url() {
return new moodle_url('/lib/editor/tinymce/subplugins.php', array('delete' => $this->name, 'sesskey' => sesskey()));
}
View
@@ -469,6 +469,70 @@ public function all_plugins_ok($moodleversion, &$failedplugins = array()) {
}
/**
+ * Is it possible to uninstall the given plugin?
+ *
+ * False is returned if the plugininfo subclass declares the uninstall should
+ * not be allowed via {@link plugininfo_base::is_uninstall_allowed()} or if the
+ * core vetoes it (e.g. becase the plugin or some of its subplugins is required
+ * by some other installed plugin).
+ *
+ * @param string $component full frankenstyle name, e.g. mod_foobar
+ * @return bool
+ */
+ public function can_uninstall_plugin($component) {
+
+ $pluginfo = $this->get_plugin_info($component);
+
+ if (is_null($pluginfo)) {
+ return false;
+ }
+
+ // Backwards compatibility check.
+ if (is_null($pluginfo->get_uninstall_url())) {
+ debugging('plugininfo_base subclasses should use is_uninstall_allowed() instead of returning null in get_uninstall_url()',
+ DEBUG_DEVELOPER);
+ return false;
+ }
+
+ // In case the $component has subplugins, get their list.
+ $mysubplugins = $this->get_subplugins_of_plugin($pluginfo->component);
+
+ // In case the $component is a subplugin, get all subplugins of its parent (i.e. siblings).
+ $myparent = $this->get_parent_of_subplugin($pluginfo->type);
+ if ($myparent === false) {
+ $mysiblings = array();
+ } else {
+ $mysiblings = $this->get_subplugins_of_plugin($myparent);
+ }
+
+ // If the plugin has subplugins, check we can uninstall them first.
+ foreach ($mysubplugins as $subpluginfo) {
+ if (!$this->can_uninstall_plugin($subpluginfo->component)) {
+ return false;
+ }
+ }
+
+ // Check there are no other plugins (but eventual subplugins or siblings) that
+ // require us. Subplugins would be uninstalled together with the parent plugin
+ // without the need to uninstall each of them individually.
+ foreach ($this->other_plugins_that_require($pluginfo->component) as $requiresme) {
+ $ismyparent = ($myparent === $requiresme);
+ $ismysubplugin = in_array($requiresme, array_keys($mysubplugins));
+ $ismysibling = in_array($requiresme, array_keys($mysiblings));
+ if (!$ismyparent and !$ismysubplugin and !$ismysibling) {
+ return false;
+ }
+ }
+
+ // Finally give the plugin plugininfo subclass a chance to prevent uninstallation.
+ if (!$pluginfo->is_uninstall_allowed()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
* Uninstall the given plugin.
*
* Automatically cleans-up all remaining configuration data, log records, events,
@@ -2501,6 +2565,24 @@ public function get_other_required_plugins() {
}
/**
+ * Is this is a subplugin?
+ *
+ * @return boolean
+ */
+ public function is_subplugin() {
+ return ($this->get_parent_plugin() !== false);
+ }
+
+ /**
+ * If I am a subplugin, return the name of my parent plugin.
+ *
+ * @return string|bool false if not a subplugin, name of the parent otherwise
+ */
+ public function get_parent_plugin() {
+ return $this->get_plugin_manager()->get_parent_of_subplugin($this->type);
+ }
+
+ /**
* Sets {@link $versiondb} property to a numerical value representing the
* currently installed version of the plugin.
*
@@ -2710,31 +2792,41 @@ public function load_settings(part_of_admin_tree $adminroot, $parentnodename, $h
}
/**
- * Returns the URL of the screen where this plugin can be uninstalled
+ * Should there be a way to uninstall the plugin via the administration UI
*
- * Visiting that URL must be safe, that is a manual confirmation is needed
- * for actual uninstallation of the plugin. Null value means that the
- * plugin cannot be uninstalled (such as due to dependencies), or it does
- * not support uninstallation, or the location of the screen is not
- * available (shortly, the 'Uninstall' link should not be displayed).
+ * By default, uninstallation is allowed for all non-standard add-ons. Subclasses
+ * may want to override this to allow uninstallation of all plugins (simply by
+ * returning true unconditionally). Subplugins follow their parent plugin's
+ * decision by default.
*
- * By default, URL to a common uninstalling handler is returned for all
- * add-ons and null is returned for standard plugins.
+ * Note that even if true is returned, the core may still prohibit the uninstallation,
+ * e.g. in case there are other plugins that depend on this one.
*
- * @return null|moodle_url
+ * @return boolean
*/
- public function get_uninstall_url() {
+ public function is_uninstall_allowed() {
- if ($this->is_standard()) {
- return null;
+ if ($this->is_subplugin()) {
+ return $this->get_plugin_manager()->get_plugin_info($this->get_parent_plugin())->is_uninstall_allowed();
}
- $pluginman = plugin_manager::instance();
- $requiredby = $pluginman->other_plugins_that_require($this->component);
- if (!empty($requiredby)) {
- return null;
+ if ($this->is_standard()) {
+ return false;
}
+ return true;
+ }
+
+ /**
+ * Returns the URL of the screen where this plugin can be uninstalled
+ *
+ * Visiting that URL must be safe, that is a manual confirmation is needed
+ * for actual uninstallation of the plugin. By default, URL to a common
+ * uninstalling tool is returned.
+ *
+ * @return moodle_url
+ */
+ public function get_uninstall_url() {
return $this->get_default_uninstall_url();
}
@@ -2771,7 +2863,7 @@ public function uninstall(array &$messages) {
*
* @return moodle_url
*/
- protected function get_default_uninstall_url() {
+ protected final function get_default_uninstall_url() {
return new moodle_url('/admin/plugins.php', array(
'sesskey' => sesskey(),
'uninstall' => $this->component,
@@ -2809,6 +2901,15 @@ protected function get_version_from_config_plugins($plugin, $disablecache=false)
return false;
}
}
+
+ /**
+ * Provides access to the plugin_manager singleton.
+ *
+ * @return plugin_manmager
+ */
+ protected function get_plugin_manager() {
+ return plugin_manager::instance();
+ }
}
@@ -2935,8 +3036,11 @@ public function load_settings(part_of_admin_tree $adminroot, $parentnodename, $h
}
}
- public function get_uninstall_url() {
+ public function is_uninstall_allowed() {
+ return true;
+ }
+ public function get_uninstall_url() {
$blocksinfo = self::get_blocks_info();
return new moodle_url('/admin/blocks.php', array('delete' => $blocksinfo[$this->name]->id, 'sesskey' => sesskey()));
}
@@ -3071,6 +3175,10 @@ public function load_settings(part_of_admin_tree $adminroot, $parentnodename, $h
}
}
+ public function is_uninstall_allowed() {
+ return true;
+ }
+
public function get_uninstall_url() {
return new moodle_url('/admin/filters.php', array('sesskey' => sesskey(), 'filterpath' => $this->name, 'action' => 'delete'));
}
@@ -3254,15 +3362,24 @@ public function load_settings(part_of_admin_tree $adminroot, $parentnodename, $h
}
}
- public function get_uninstall_url() {
+ /**
+ * Allow all activity modules but Forum to be uninstalled.
- if ($this->name !== 'forum') {
- return new moodle_url('/admin/modules.php', array('delete' => $this->name, 'sesskey' => sesskey()));
+ * This exception for the Forum has been hard-coded in Moodle since ages,
+ * we may want to re-think it one day.
+ */
+ public function is_uninstall_allowed() {
+ if ($this->name === 'forum') {
+ return false;
} else {
- return null;
+ return true;
}
}
+ public function get_uninstall_url() {
+ return new moodle_url('/admin/modules.php', array('delete' => $this->name, 'sesskey' => sesskey()));
+ }
+
/**
* Provides access to the records in {modules} table
*
@@ -3296,6 +3413,10 @@ protected static function get_modules_info($disablecache=false) {
*/
class plugininfo_qbehaviour extends plugininfo_base {
+ public function is_uninstall_allowed() {
+ return true;
+ }
+
public function get_uninstall_url() {
return new moodle_url('/admin/qbehaviours.php',
array('delete' => $this->name, 'sesskey' => sesskey()));
@@ -3308,6 +3429,10 @@ public function get_uninstall_url() {
*/
class plugininfo_qtype extends plugininfo_base {
+ public function is_uninstall_allowed() {
+ return true;
+ }
+
public function get_uninstall_url() {
return new moodle_url('/admin/qtypes.php',
array('delete' => $this->name, 'sesskey' => sesskey()));
@@ -3432,6 +3557,10 @@ public function load_settings(part_of_admin_tree $adminroot, $parentnodename, $h
}
}
+ public function is_uninstall_allowed() {
+ return true;
+ }
+
public function get_uninstall_url() {
return new moodle_url('/admin/enrol.php', array('action' => 'uninstall', 'enrol' => $this->name, 'sesskey' => sesskey()));
}
@@ -3482,16 +3611,21 @@ public function is_enabled() {
}
}
+ public function is_uninstall_allowed() {
+ $processors = get_message_processors();
+ if (isset($processors[$this->name])) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
/**
* @see plugintype_interface::get_uninstall_url()
*/
public function get_uninstall_url() {
$processors = get_message_processors();
- if (isset($processors[$this->name])) {
- return new moodle_url('/admin/message.php', array('uninstall' => $processors[$this->name]->id, 'sesskey' => sesskey()));
- } else {
- return null;
- }
+ return new moodle_url('/admin/message.php', array('uninstall' => $processors[$this->name]->id, 'sesskey' => sesskey()));
}
}
@@ -3636,6 +3770,10 @@ public function is_enabled() {
*/
class plugininfo_tool extends plugininfo_base {
+ public function is_uninstall_allowed() {
+ return true;
+ }
+
public function get_uninstall_url() {
return new moodle_url('/admin/tools.php', array('delete' => $this->name, 'sesskey' => sesskey()));
}
@@ -3647,6 +3785,10 @@ public function get_uninstall_url() {
*/
class plugininfo_report extends plugininfo_base {
+ public function is_uninstall_allowed() {
+ return true;
+ }
+
public function get_uninstall_url() {
return new moodle_url('/admin/reports.php', array('delete' => $this->name, 'sesskey' => sesskey()));
}
@@ -3770,6 +3912,10 @@ public function is_enabled() {
return false;
}
+ public function is_uninstall_allowed() {
+ return true;
+ }
+
public function get_uninstall_url() {
return new moodle_url('/admin/webservice/protocols.php',
array('sesskey' => sesskey(), 'action' => 'uninstall', 'webservice' => $this->name));
@@ -3825,11 +3971,16 @@ public function is_enabled() {
return !get_config($this->component, 'disabled');
}
- public function get_uninstall_url() {
+ public function is_uninstall_allowed() {
if ($this->name !== get_config('moodlecourse', 'format') && $this->name !== 'site') {
- return new moodle_url('/admin/courseformats.php',
- array('sesskey' => sesskey(), 'action' => 'uninstall', 'format' => $this->name));
+ return true;
+ } else {
+ return false;
}
- return null;
+ }
+
+ public function get_uninstall_url() {
+ return new moodle_url('/admin/courseformats.php',
+ array('sesskey' => sesskey(), 'action' => 'uninstall', 'format' => $this->name));
}
}
@@ -0,0 +1,5 @@
+<?php
+
+$plugin->version = 2013041103;
+$plugin->requires = 2013010100;
+$plugin->component = 'bazmeg_one';
@@ -0,0 +1,4 @@
+<?php
+
+$module->version = 2012030500;
+$module->requires = 2012010100;
@@ -0,0 +1,6 @@
+<?php
+
+$plugin->version = 2013041103;
+$plugin->requires = 2012010100;
+$plugin->component = 'foolish_hippo';
+$plugin->dependencies = array('foolish_frog' => ANY_VERSION);
@@ -6,4 +6,5 @@
$module->dependencies = array(
'mod_bar' => 2012030500,
'mod_missing' => ANY_VERSION,
+ 'foolish_frog' => ANY_VERSION,
);
@@ -0,0 +1,6 @@
+<?php
+
+$plugin->version = 2013041103;
+$plugin->requires = 2013010100;
+$plugin->component = 'quxcat_one';
+$plugin->dependencies = array('bazmeg_one' => 2013010100);
Oops, something went wrong.

0 comments on commit 7365837

Please sign in to comment.