diff --git a/admin/cli/install.php b/admin/cli/install.php index 2cd66f7646e..79ff0b7126d 100644 --- a/admin/cli/install.php +++ b/admin/cli/install.php @@ -678,7 +678,9 @@ if (!$envstatus) { // Test plugin dependencies. require_once($CFG->libdir . '/pluginlib.php'); -if (!plugin_manager::instance()->all_plugins_ok($version)) { +$failed = array(); +if (!plugin_manager::instance()->all_plugins_ok($version, $failed)) { + cli_problem(get_string('pluginscheckfailed', 'admin', array('pluginslist' => implode(', ', array_unique($failed))))); cli_error(get_string('pluginschecktodo', 'admin')); } diff --git a/admin/cli/install_database.php b/admin/cli/install_database.php index 2524c4101eb..313f3521d40 100644 --- a/admin/cli/install_database.php +++ b/admin/cli/install_database.php @@ -161,7 +161,9 @@ if (!$envstatus) { // Test plugin dependencies. require_once($CFG->libdir . '/pluginlib.php'); -if (!plugin_manager::instance()->all_plugins_ok($version)) { +$failed = array(); +if (!plugin_manager::instance()->all_plugins_ok($version, $failed)) { + cli_problem(get_string('pluginscheckfailed', 'admin', array('pluginslist' => implode(', ', array_unique($failed))))); cli_error(get_string('pluginschecktodo', 'admin')); } diff --git a/admin/cli/upgrade.php b/admin/cli/upgrade.php index e552d4e1b31..1fae897c8cb 100644 --- a/admin/cli/upgrade.php +++ b/admin/cli/upgrade.php @@ -109,7 +109,9 @@ if (!$envstatus) { } // Test plugin dependencies. -if (!plugin_manager::instance()->all_plugins_ok($version)) { +$failed = array(); +if (!plugin_manager::instance()->all_plugins_ok($version, $failed)) { + cli_problem(get_string('pluginscheckfailed', 'admin', array('pluginslist' => implode(', ', array_unique($failed))))); cli_error(get_string('pluginschecktodo', 'admin')); } diff --git a/admin/index.php b/admin/index.php index 5b01be2749b..bf3eea52aa6 100644 --- a/admin/index.php +++ b/admin/index.php @@ -152,6 +152,20 @@ if (!core_tables_exist()) { die(); } + // check plugin dependencies + $failed = array(); + if (!plugin_manager::instance()->all_plugins_ok($version, $failed)) { + $PAGE->navbar->add(get_string('pluginscheck', 'admin')); + $PAGE->set_title($strinstallation); + $PAGE->set_heading($strinstallation . ' - Moodle ' . $CFG->target_release); + + $output = $PAGE->get_renderer('core', 'admin'); + $url = new moodle_url('/admin/index.php', array('agreelicense' => 1, 'confirmrelease' => 1, 'lang' => $CFG->lang)); + echo $output->unsatisfied_dependencies_page($version, $failed, $url); + die(); + } + unset($failed); + //TODO: add a page with list of non-standard plugins here $strdatabasesetup = get_string('databasesetup'); @@ -238,6 +252,15 @@ if ($version > $CFG->version) { // upgrade $reloadurl = new moodle_url('/admin/index.php', array('confirmupgrade' => 1, 'confirmrelease' => 1)); + // check plugin dependencies first + $failed = array(); + if (!plugin_manager::instance()->all_plugins_ok($version, $failed)) { + $output = $PAGE->get_renderer('core', 'admin'); + echo $output->unsatisfied_dependencies_page($version, $failed, $reloadurl); + die(); + } + unset($failed); + if ($fetchupdates) { // no sesskey support guaranteed here if (empty($CFG->disableupdatenotifications)) { @@ -290,6 +313,16 @@ if (moodle_needs_upgrading()) { } $output = $PAGE->get_renderer('core', 'admin'); + + // check plugin dependencies first + $failed = array(); + if (!plugin_manager::instance()->all_plugins_ok($version, $failed)) { + echo $output->unsatisfied_dependencies_page($version, $failed, $PAGE->url); + die(); + } + unset($failed); + + // dependencies check passed, let's rock! echo $output->upgrade_plugin_check_page(plugin_manager::instance(), available_update_checker::instance(), $version, $showallplugins, new moodle_url($PAGE->url), diff --git a/admin/renderer.php b/admin/renderer.php index b7a1bab12db..9b689a6903e 100644 --- a/admin/renderer.php +++ b/admin/renderer.php @@ -107,6 +107,29 @@ class core_admin_renderer extends plugin_renderer_base { return $output; } + /** + * Displays the list of plugins with unsatisfied dependencies + * + * @param double|string|int $version Moodle on-disk version + * @param array $failed list of plugins with unsatisfied dependecies + * @param moodle_url $reloadurl URL of the page to recheck the dependencies + * @return string HTML + */ + public function unsatisfied_dependencies_page($version, array $failed, moodle_url $reloadurl) { + $output = ''; + + $output .= $this->header(); + $output .= $this->heading(get_string('pluginscheck', 'admin')); + $output .= $this->warning(get_string('pluginscheckfailed', 'admin', array('pluginslist' => implode(', ', array_unique($failed))))); + $output .= $this->plugins_check_table(plugin_manager::instance(), $version, array('xdep' => true)); + $output .= $this->warning(get_string('pluginschecktodo', 'admin')); + $output .= $this->continue_button($reloadurl); + + $output .= $this->footer(); + + return $output; + } + /** * Display the 'You are about to upgrade Moodle' page. The first page * during upgrade. @@ -197,19 +220,15 @@ class core_admin_renderer extends plugin_renderer_base { $output .= $this->box_end(); $output .= $this->upgrade_reload($reloadurl); - if ($pluginman->all_plugins_ok($version)) { - if ($pluginman->some_plugins_updatable()) { - $output .= $this->container_start('upgradepluginsinfo'); - $output .= $this->help_icon('upgradepluginsinfo', 'core_admin', get_string('upgradepluginsfirst', 'core_admin')); - $output .= $this->container_end(); - } - $button = new single_button($continueurl, get_string('upgradestart', 'admin'), 'get'); - $button->class = 'continuebutton'; - $output .= $this->render($button); - } else { - $output .= $this->box(get_string('pluginschecktodo', 'admin'), 'environmentbox errorbox'); + if ($pluginman->some_plugins_updatable()) { + $output .= $this->container_start('upgradepluginsinfo'); + $output .= $this->help_icon('upgradepluginsinfo', 'core_admin', get_string('upgradepluginsfirst', 'core_admin')); + $output .= $this->container_end(); } + $button = new single_button($continueurl, get_string('upgradestart', 'admin'), 'get'); + $button->class = 'continuebutton'; + $output .= $this->render($button); $output .= $this->footer(); return $output; @@ -563,13 +582,14 @@ class core_admin_renderer extends plugin_renderer_base { * This default implementation renders all plugins into one big table. The rendering * options support: * (bool)full = false: whether to display up-to-date plugins, too + * (bool)xdep = false: display the plugins with unsatisified dependecies only * * @param plugin_manager $pluginman provides information about the plugins. * @param int $version the version of the Moodle code from version.php. * @param array $options rendering options * @return string HTML code */ - public function plugins_check_table(plugin_manager $pluginman, $version, array $options = null) { + public function plugins_check_table(plugin_manager $pluginman, $version, array $options = array()) { global $CFG; $plugininfo = $pluginman->get_plugins(); @@ -578,11 +598,8 @@ class core_admin_renderer extends plugin_renderer_base { return ''; } - if (empty($options)) { - $options = array( - 'full' => false, - ); - } + $options['full'] = isset($options['full']) ? (bool)$options['full'] : false; + $options['xdep'] = isset($options['xdep']) ? (bool)$options['xdep'] : false; $table = new html_table(); $table->id = 'plugins-check'; @@ -666,16 +683,28 @@ class core_admin_renderer extends plugin_renderer_base { $statusisboring = in_array($statuscode, array( plugin_manager::PLUGIN_STATUS_NODB, plugin_manager::PLUGIN_STATUS_UPTODATE)); - $dependenciesok = $pluginman->are_dependencies_satisfied( - $plugin->get_other_required_plugins()); - if ($isstandard and $statusisboring and $dependenciesok and empty($availableupdates)) { + + $coredependency = $plugin->is_core_dependency_satisfied($version); + $otherpluginsdependencies = $pluginman->are_dependencies_satisfied($plugin->get_other_required_plugins()); + $dependenciesok = $coredependency && $otherpluginsdependencies; + + if ($options['xdep']) { + // we want to see only plugins with failed dependencies + if ($dependenciesok) { + continue; + } + + } else if ($isstandard and $statusisboring and $dependenciesok and empty($availableupdates)) { + // no change is going to happen to the plugin - display it only + // if the user wants to see the full list if (empty($options['full'])) { continue; } - } else { - $numofhighlighted[$type]++; } + // ok, the plugin should be displayed + $numofhighlighted[$type]++; + $row->cells = array($displayname, $rootdir, $source, $versiondb, $versiondisk, $requires, $status); $plugintyperows[] = $row; @@ -691,7 +720,11 @@ class core_admin_renderer extends plugin_renderer_base { $sumofhighlighted = array_sum($numofhighlighted); - if ($sumofhighlighted == 0) { + if ($options['xdep']) { + // we do not want to display no heading and links in this mode + $out = ''; + + } else if ($sumofhighlighted == 0) { $out = $this->output->container_start('nonehighlighted', 'plugins-check-info'); $out .= $this->output->heading(get_string('nonehighlighted', 'core_plugin')); if (empty($options['full'])) { diff --git a/lang/en/admin.php b/lang/en/admin.php index 82581fe53d0..6dbb85977b9 100644 --- a/lang/en/admin.php +++ b/lang/en/admin.php @@ -754,6 +754,8 @@ $string['pleaserefreshregistration'] = 'Your site has been registered with moodl $string['pleaseregister'] = 'Please register your site to remove this button'; $string['plugin'] = 'Plugin'; $string['plugins'] = 'Plugins'; +$string['pluginscheck'] = 'Plugin dependencies check'; +$string['pluginscheckfailed'] = 'Dependencies check failed for {$a->pluginslist}'; $string['pluginschecktodo'] = 'You must solve all the plugin requirements before proceeding to install this Moodle version!'; $string['pluginsoverview'] = 'Plugins overview'; $string['profilecategory'] = 'Category'; diff --git a/lang/en/plugin.php b/lang/en/plugin.php index 3bc89ef8d37..3bba405afa6 100644 --- a/lang/en/plugin.php +++ b/lang/en/plugin.php @@ -31,7 +31,7 @@ $string['checkforupdates'] = 'Check for available updates'; $string['checkforupdateslast'] = 'Last check done on {$a}'; $string['displayname'] = 'Plugin name'; $string['moodleversion'] = 'Moodle {$a}'; -$string['nonehighlighted'] = 'No plugins require your attention during this upgrade'; +$string['nonehighlighted'] = 'No plugins require your attention now'; $string['nonehighlightedinfo'] = 'Display the list of all installed plugins anyway'; $string['noneinstalled'] = 'No plugins of this type are installed'; $string['notes'] = 'Notes'; @@ -52,7 +52,7 @@ $string['requiredby'] = 'Required by: {$a}'; $string['requires'] = 'Requires'; $string['rootdir'] = 'Directory'; $string['settings'] = 'Settings'; -$string['somehighlighted'] = 'Number of plugins requiring attention during this upgrade: {$a}'; +$string['somehighlighted'] = 'Number of plugins requiring your attention: {$a}'; $string['somehighlightedinfo'] = 'Display the full list of installed plugins'; $string['somehighlightedonly'] = 'Display only plugins requiring your attention'; $string['source'] = 'Source'; diff --git a/lib/pluginlib.php b/lib/pluginlib.php index df5239c4995..20f8a340254 100644 --- a/lib/pluginlib.php +++ b/lib/pluginlib.php @@ -280,25 +280,35 @@ class plugin_manager { } /** - * Checks all dependencies for all installed plugins. Used by install and upgrade. + * Checks all dependencies for all installed plugins + * + * This is used by install and upgrade. The array passed by reference as the second + * argument is populated with the list of plugins that have failed dependencies (note that + * a single plugin can appear multiple times in the $failedplugins). + * * @param int $moodleversion the version from version.php. + * @param array $failedplugins to return the list of plugins with non-satisfied dependencies * @return bool true if all the dependencies are satisfied for all plugins. */ - public function all_plugins_ok($moodleversion) { + public function all_plugins_ok($moodleversion, &$failedplugins = array()) { + + $return = true; foreach ($this->get_plugins() as $type => $plugins) { foreach ($plugins as $plugin) { - if (!empty($plugin->versionrequires) && $plugin->versionrequires > $moodleversion) { - return false; + if (!$plugin->is_core_dependency_satisfied($moodleversion)) { + $return = false; + $failedplugins[] = $plugin->component; } if (!$this->are_dependencies_satisfied($plugin->get_other_required_plugins())) { - return false; + $return = false; + $failedplugins[] = $plugin->component; } } } - return true; + return $return; } /** @@ -1610,6 +1620,22 @@ abstract class plugininfo_base { return $this->source === plugin_manager::PLUGIN_SOURCE_STANDARD; } + /** + * Returns true if the the given Moodle version is enough to run this plugin + * + * @param string|int|double $moodleversion + * @return bool + */ + public function is_core_dependency_satisfied($moodleversion) { + + if (empty($this->versionrequires)) { + return true; + + } else { + return (double)$this->versionrequires <= (double)$moodleversion; + } + } + /** * Returns the status of the plugin *