Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'MDL-26784-plugin-manager' of git://github.com/mudrd8mz/…

…moodle
  • Loading branch information...
commit 33620e1772fb9050d66a45d8dd7333098c3b22ce 2 parents 656d17c + 91dedc3
@skodak skodak authored
View
37 admin/index.php
@@ -48,6 +48,7 @@
$confirmupgrade = optional_param('confirmupgrade', 0, PARAM_BOOL);
$confirmrelease = optional_param('confirmrelease', 0, PARAM_BOOL);
$confirmplugins = optional_param('confirmplugincheck', 0, PARAM_BOOL);
+$showallplugins = optional_param('showallplugins', 0, PARAM_BOOL);
$agreelicense = optional_param('agreelicense', 0, PARAM_BOOL);
// Check some PHP server settings
@@ -255,17 +256,19 @@
$PAGE->set_title($strplugincheck);
$PAGE->set_heading($strplugincheck);
$PAGE->set_cacheable(false);
- echo $OUTPUT->header();
- echo $OUTPUT->heading($strplugincheck);
- echo $OUTPUT->box_start('generalbox', 'notice');
- print_string('pluginchecknotice');
- echo $OUTPUT->box_end();
- print_plugin_tables();
+ $output = $PAGE->get_renderer('core', 'admin');
+ $pluginman = plugin_manager::instance();
+
+ echo $output->header();
+ echo $output->box_start('generalbox');
+ echo $output->container(get_string('pluginchecknotice', 'core_plugin'), 'generalbox', 'notice');
+ echo $output->plugins_check($pluginman->get_plugins(), array('full' => $showallplugins));
+ echo $output->box_end();
print_upgrade_reload('index.php?confirmupgrade=1&confirmrelease=1');
$button = new single_button(new moodle_url('index.php', array('confirmupgrade'=>1, 'confirmrelease'=>1, 'confirmplugincheck'=>1)), get_string('upgradestart', 'admin'), 'get');
$button->class = 'continuebutton';
- echo $OUTPUT->render($button);
- echo $OUTPUT->footer();
+ echo $output->render($button);
+ echo $output->footer();
die();
} else {
@@ -293,17 +296,19 @@
$PAGE->set_title($strplugincheck);
$PAGE->set_heading($strplugincheck);
$PAGE->set_cacheable(false);
- echo $OUTPUT->header();
- echo $OUTPUT->heading($strplugincheck);
- echo $OUTPUT->box_start('generalbox', 'notice');
- print_string('pluginchecknotice');
- echo $OUTPUT->box_end();
- print_plugin_tables();
+ $output = $PAGE->get_renderer('core', 'admin');
+ $pluginman = plugin_manager::instance();
+
+ echo $output->header();
+ echo $output->box_start('generalbox');
+ echo $output->container(get_string('pluginchecknotice', 'core_plugin'), 'generalbox', 'notice');
+ echo $output->plugins_check($pluginman->get_plugins(), array('full' => $showallplugins));
+ echo $output->box_end();
print_upgrade_reload('index.php');
$button = new single_button(new moodle_url('index.php', array('confirmplugincheck'=>1)), get_string('upgradestart', 'admin'), 'get');
$button->class = 'continuebutton';
- echo $OUTPUT->render($button);
- echo $OUTPUT->footer();
+ echo $output->render($button);
+ echo $output->footer();
die();
}
}
View
41 admin/plugins.php
@@ -0,0 +1,41 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * UI for general plugins management
+ *
+ * @package core
+ * @subpackage admin
+ * @copyright 2011 David Mudrak <david@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once(dirname(dirname(__FILE__)) . '/config.php');
+require_once($CFG->libdir . '/adminlib.php');
+require_once($CFG->libdir . '/pluginlib.php');
+
+require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM));
+admin_externalpage_setup('pluginsoverview');
+$output = $PAGE->get_renderer('core', 'admin');
+$pluginman = plugin_manager::instance();
+
+echo $output->header();
+echo $output->heading(get_string('pluginsoverview', 'core_admin'));
+echo $output->box_start('generalbox');
+echo $output->plugins_control_panel($pluginman->get_plugins());
+echo $output->box_end();
+echo $output->footer();
View
296 admin/renderer.php
@@ -0,0 +1,296 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Renderer for core_admin subsystem
+ *
+ * @package core
+ * @subpackage admin
+ * @copyright 2011 David Mudrak <david@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once($CFG->libdir . '/pluginlib.php');
+
+/**
+ * Standard HTML output renderer for core_admin subsystem
+ */
+class core_admin_renderer extends plugin_renderer_base {
+
+ /**
+ * Displays all known plugins and information about their installation or upgrade
+ *
+ * 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
+ *
+ * @param array $plugininfo as returned by {@see plugin_manager::get_plugins()}
+ * @param array $options rendering options
+ * @return string HTML code
+ */
+ public function plugins_check(array $plugininfo, array $options = null) {
+
+ if (empty($plugininfo)) {
+ return '';
+ }
+
+ if (empty($options)) {
+ $options = array(
+ 'full' => false,
+ );
+ }
+
+ $pluginman = plugin_manager::instance();
+
+ $table = new html_table();
+ $table->id = 'plugins-check';
+ $table->head = array(
+ get_string('displayname', 'core_plugin'),
+ get_string('rootdir', 'core_plugin'),
+ get_string('source', 'core_plugin'),
+ get_string('versiondb', 'core_plugin'),
+ get_string('versiondisk', 'core_plugin'),
+ get_string('status', 'core_plugin'),
+ );
+ $table->colclasses = array(
+ 'displayname', 'rootdir', 'source', 'versiondb', 'versiondisk', 'status',
+ );
+ $table->data = array();
+
+ $numofhighlighted = array(); // number of highlighted rows per this subsection
+
+ foreach ($plugininfo as $type => $plugins) {
+
+ $header = new html_table_cell($pluginman->plugintype_name_plural($type));
+ $header->header = true;
+ $header->colspan = count($table->head);
+ $header = new html_table_row(array($header));
+ $header->attributes['class'] = 'plugintypeheader type-' . $type;
+
+ $numofhighlighted[$type] = 0;
+
+ if (empty($plugins) and $options['full']) {
+ $msg = new html_table_cell(get_string('noneinstalled', 'core_plugin'));
+ $msg->colspan = count($table->head);
+ $row = new html_table_row(array($msg));
+ $row->attributes['class'] .= 'msg msg-noneinstalled';
+ $table->data[] = $header;
+ $table->data[] = $row;
+ continue;
+ }
+
+ $plugintyperows = array();
+
+ foreach ($plugins as $name => $plugin) {
+ $row = new html_table_row();
+ $row->attributes['class'] = 'type-' . $plugin->type . ' name-' . $plugin->type . '_' . $plugin->name;
+
+ if ($this->page->theme->resolve_image_location('icon', $plugin->type . '_' . $plugin->name)) {
+ $icon = $this->output->pix_icon('icon', '', $plugin->type . '_' . $plugin->name, array('class' => 'smallicon pluginicon'));
+ } else {
+ $icon = $this->output->pix_icon('spacer', '', 'moodle', array('class' => 'smallicon pluginicon noicon'));
+ }
+ $displayname = $icon . ' ' . $plugin->displayname;
+ $displayname = new html_table_cell($displayname);
+
+ $rootdir = new html_table_cell($plugin->get_dir());
+
+ if ($isstandard = $plugin->is_standard()) {
+ $row->attributes['class'] .= ' standard';
+ $source = new html_table_cell(get_string('sourcestd', 'core_plugin'));
+ } else {
+ $row->attributes['class'] .= ' extension';
+ $source = new html_table_cell(get_string('sourceext', 'core_plugin'));
+ }
+
+ $versiondb = new html_table_cell($plugin->versiondb);
+ $versiondisk = new html_table_cell($plugin->versiondisk);
+
+ $statuscode = $plugin->get_status();
+ $row->attributes['class'] .= ' status-' . $statuscode;
+
+ $status = new html_table_cell(get_string('status_' . $statuscode, 'core_plugin'));
+
+ if ($isstandard and in_array($statuscode, array(plugin_manager::PLUGIN_STATUS_NODB, plugin_manager::PLUGIN_STATUS_UPTODATE))) {
+ if (empty($options['full'])) {
+ continue;
+ }
+ } else {
+ $numofhighlighted[$type]++;
+ }
+
+ $row->cells = array($displayname, $rootdir, $source, $versiondb, $versiondisk, $status);
+ $plugintyperows[] = $row;
+ }
+
+ if (empty($numofhighlighted[$type]) and empty($options['full'])) {
+ continue;
+ }
+
+ $table->data[] = $header;
+ $table->data = array_merge($table->data, $plugintyperows);
+ }
+
+ $sumofhighlighted = array_sum($numofhighlighted);
+
+ 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'])) {
+ $out .= html_writer::link(new moodle_url('/admin/index.php',
+ array('confirmupgrade' => 1, 'confirmrelease' => 1, 'showallplugins' => 1)),
+ get_string('nonehighlightedinfo', 'core_plugin'));
+ }
+ $out .= $this->output->container_end();
+
+ } else {
+ $out = $this->output->container_start('somehighlighted', 'plugins-check-info');
+ $out .= $this->output->heading(get_string('somehighlighted', 'core_plugin', $sumofhighlighted));
+ if (empty($options['full'])) {
+ $out .= html_writer::link(new moodle_url('/admin/index.php',
+ array('confirmupgrade' => 1, 'confirmrelease' => 1, 'showallplugins' => 1)),
+ get_string('somehighlightedinfo', 'core_plugin'));
+ }
+ $out .= $this->output->container_end();
+ }
+
+ if ($sumofhighlighted > 0 or $options['full']) {
+ $out .= html_writer::table($table);
+ }
+
+ return $out;
+ }
+
+ /**
+ * Displays all known plugins and links to manage them
+ *
+ * This default implementation renders all plugins into one big table.
+ *
+ * @param array $plugininfo as returned by {@see plugin_manager::get_plugins()}
+ * @return string HTML code
+ */
+ public function plugins_control_panel(array $plugininfo) {
+
+ if (empty($plugininfo)) {
+ return '';
+ }
+
+ $pluginman = plugin_manager::instance();
+
+ $table = new html_table();
+ $table->id = 'plugins-control-panel';
+ $table->head = array(
+ get_string('displayname', 'core_plugin'),
+ get_string('systemname', 'core_plugin'),
+ get_string('source', 'core_plugin'),
+ get_string('version', 'core_plugin'),
+ get_string('availability', 'core_plugin'),
+ get_string('settings', 'core_plugin'),
+ get_string('uninstall','core_plugin'),
+ );
+ $table->colclasses = array(
+ 'displayname', 'systemname', 'source', 'version', 'availability', 'settings', 'uninstall',
+ );
+
+ foreach ($plugininfo as $type => $plugins) {
+
+ $header = new html_table_cell($pluginman->plugintype_name_plural($type));
+ $header->header = true;
+ $header->colspan = count($table->head);
+ $header = new html_table_row(array($header));
+ $header->attributes['class'] = 'plugintypeheader type-' . $type;
+ $table->data[] = $header;
+
+ if (empty($plugins)) {
+ $msg = new html_table_cell(get_string('noneinstalled', 'core_plugin'));
+ $msg->colspan = count($table->head);
+ $row = new html_table_row(array($msg));
+ $row->attributes['class'] .= 'msg msg-noneinstalled';
+ $table->data[] = $row;
+ continue;
+ }
+
+ foreach ($plugins as $name => $plugin) {
+ $row = new html_table_row();
+ $row->attributes['class'] = 'type-' . $plugin->type . ' name-' . $plugin->type . '_' . $plugin->name;
+
+ if ($this->page->theme->resolve_image_location('icon', $plugin->type . '_' . $plugin->name)) {
+ $icon = $this->output->pix_icon('icon', '', $plugin->type . '_' . $plugin->name, array('class' => 'smallicon pluginicon'));
+ } else {
+ $icon = $this->output->pix_icon('spacer', '', 'moodle', array('class' => 'smallicon pluginicon noicon'));
+ }
+ if ($plugin->get_status() === plugin_manager::PLUGIN_STATUS_MISSING) {
+ $msg = html_writer::tag('span', get_string('status_missing', 'core_plugin'), array('class' => 'notifyproblem'));
+ $row->attributes['class'] .= ' missingfromdisk';
+ } else {
+ $msg = '';
+ }
+ $displayname = $icon . ' ' . $plugin->displayname . ' ' . $msg;
+ $displayname = new html_table_cell($displayname);
+
+ $systemname = new html_table_cell($plugin->type . '_' . $plugin->name);
+
+ if ($plugin->is_standard()) {
+ $row->attributes['class'] .= ' standard';
+ $source = new html_table_cell(get_string('sourcestd', 'core_plugin'));
+ } else {
+ $row->attributes['class'] .= ' extension';
+ $source = new html_table_cell(get_string('sourceext', 'core_plugin'));
+ }
+
+ $version = new html_table_cell($plugin->versiondb);
+
+ $isenabled = $plugin->is_enabled();
+ if (is_null($isenabled)) {
+ $availability = new html_table_cell('');
+ } else if ($isenabled) {
+ $row->attributes['class'] .= ' enabled';
+ $icon = $this->output->pix_icon('i/hide', get_string('pluginenabled', 'core_plugin'));
+ $availability = new html_table_cell($icon . ' ' . get_string('pluginenabled', 'core_plugin'));
+ } else {
+ $row->attributes['class'] .= ' disabled';
+ $icon = $this->output->pix_icon('i/show', get_string('plugindisabled', 'core_plugin'));
+ $availability = new html_table_cell($icon . ' ' . get_string('plugindisabled', 'core_plugin'));
+ }
+
+ $settingsurl = $plugin->get_settings_url();
+ if (is_null($settingsurl)) {
+ $settings = new html_table_cell('');
+ } else {
+ $settings = html_writer::link($settingsurl, get_string('settings', 'core_plugin'));
+ $settings = new html_table_cell($settings);
+ }
+
+ $uninstallurl = $plugin->get_uninstall_url();
+ if (is_null($uninstallurl)) {
+ $uninstall = new html_table_cell('');
+ } else {
+ $uninstall = html_writer::link($uninstallurl, get_string('uninstall', 'core_plugin'));
+ $uninstall = new html_table_cell($uninstall);
+ }
+
+ $row->cells = array(
+ $displayname, $systemname, $source, $version, $availability, $settings, $uninstall
+ );
+ $table->data[] = $row;
+ }
+ }
+
+ return html_writer::table($table);
+ }
+}
View
1  admin/settings/plugins.php
@@ -5,6 +5,7 @@
*/
if ($hassiteconfig) {
+ $ADMIN->add('modules', new admin_page_pluginsoverview());
$ADMIN->add('modules', new admin_category('modsettings', get_string('activitymodules')));
$ADMIN->add('modsettings', new admin_page_managemods());
$modules = $DB->get_records('modules', array(), "name ASC");
View
1  lang/en/admin.php
@@ -801,6 +801,7 @@
$string['pleaseregister'] = 'Please register your site to remove this button';
$string['plugin'] = 'Plugin';
$string['plugins'] = 'Plugins';
+$string['pluginsoverview'] = 'Plugins overview';
$string['profilecategory'] = 'Category';
$string['profilecategoryname'] = 'Category name (must be unique)';
$string['profilecategorynamenotunique'] = 'This category name is already in use';
View
3  lang/en/moodle.php
@@ -1263,9 +1263,6 @@
$string['plugin'] = 'Plugin';
$string['plugindeletefiles'] = 'All data associated with the plugin \'{$a->name}\' has been deleted from the database. To prevent the plugin re-installing itself, you should now delete this directory from your server: {$a->directory}';
$string['plugincheck'] = 'Plugins check';
-$string['pluginchecknotice'] = 'The following tables show the modules, blocks and filters that have been detected in your current Moodle installation;
-They indicate which plugins are standard, and which are not. All non-standard plugins should be checked and upgraded to their most recent versions
-before continuing with this Moodle upgrade.';
$string['pluginsetup'] = 'Setting up plugin tables';
$string['policyaccept'] = 'I understand and agree';
$string['policyagree'] = 'You must agree to this policy to continue using this site. Do you agree?';
View
104 lang/en/plugin.php
@@ -0,0 +1,104 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Defines names of plugin types and some strings used at the plugin managment
+ *
+ * @package core
+ * @subpackage admin
+ * @copyright 2011 David Mudrak <david@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['availability'] = 'Availability';
+$string['displayname'] = 'Plugin name';
+$string['nonehighlighted'] = 'No plugins require your attention during this upgrade';
+$string['nonehighlightedinfo'] = 'Display the list of all installed plugins anyway';
+$string['noneinstalled'] = 'No plugins of this type are installed';
+$string['showall'] = 'Reload and show all plugins';
+$string['pluginchecknotice'] = 'This page displays plugins that may require your attention during the upgrade. Highlighted items include new plugins that are about to be installed, updated plugins that are about to be upgraded and any missing plugins. Contributed plugins are also highlighted.
+It is recommended that you check whether there are more recent versions of contributed plugins available and update their source code before continuing with this Moodle upgrade.';
+$string['plugindisable'] = 'Disable';
+$string['plugindisabled'] = 'Disabled';
+$string['pluginenable'] = 'Enable';
+$string['pluginenabled'] = 'Enabled';
+$string['rootdir'] = 'Directory';
+$string['settings'] = 'Settings';
+$string['somehighlighted'] = 'Number of plugins requiring attention during this upgrade: {$a}';
+$string['somehighlightedinfo'] = 'Display the full list of installed plugins';
+$string['source'] = 'Source';
+$string['sourceext'] = 'Extension';
+$string['sourcestd'] = 'Standard';
+$string['status'] = 'Status';
+$string['status_downgrade'] = 'Higher version already installed!';
+$string['status_missing'] = 'Missing from disk!';
+$string['status_new'] = 'To be installed';
+$string['status_nodb'] = 'No database';
+$string['status_upgrade'] = 'To be upgraded';
+$string['status_uptodate'] = 'Up-to-date';
+$string['systemname'] = 'Identifier';
+$string['type_auth'] = 'Authentication method';
+$string['type_auth_plural'] = 'Authentication methods';
+$string['type_block'] = 'Block';
+$string['type_block_plural'] = 'Blocks';
+$string['type_coursereport'] = 'Course report';
+$string['type_coursereport_plural'] = 'Course reports';
+$string['type_editor'] = 'Editor';
+$string['type_editor_plural'] = 'Editors';
+$string['type_enrol'] = 'Enrolment method';
+$string['type_enrol_plural'] = 'Enrolment methods';
+$string['type_filter'] = 'Text filter';
+$string['type_filter_plural'] = 'Text filters';
+$string['type_format'] = 'Course format';
+$string['type_format_plural'] = 'Course formats';
+$string['type_gradeexport'] = 'Grade export method';
+$string['type_gradeexport_plural'] = 'Grade export methods';
+$string['type_gradeimport'] = 'Grade import method';
+$string['type_gradeimport_plural'] = 'Grade import methods';
+$string['type_gradereport'] = 'Gradebook report';
+$string['type_gradereport_plural'] = 'Gradebook reports';
+$string['type_local'] = 'Local plugin';
+$string['type_local_plural'] = 'Local plugins';
+$string['type_message'] = 'Messaging processor';
+$string['type_message_plural'] = 'Messaging processors';
+$string['type_mnetservice'] = 'MNet service';
+$string['type_mnetservice_plural'] = 'MNet services';
+$string['type_mod'] = 'Activity module';
+$string['type_mod_plural'] = 'Activity modules';
+$string['type_plagiarism'] = 'Plagiarism prevention plugin';
+$string['type_plagiarism_plural'] = 'Plagiarism prevention plugins';
+$string['type_portfolio'] = 'Portfolio';
+$string['type_portfolio_plural'] = 'Portfolios';
+$string['type_profilefield'] = 'Profile field type';
+$string['type_profilefield_plural'] = 'Profile field types';
+$string['type_qformat'] = 'Question import/export format';
+$string['type_qformat_plural'] = 'Question import/export formats';
+$string['type_qtype'] = 'Question type';
+$string['type_qtype_plural'] = 'Question types';
+$string['type_report'] = 'Site report';
+$string['type_report_plural'] = 'Site reports';
+$string['type_repository'] = 'Repository';
+$string['type_repository_plural'] = 'Repositories';
+$string['type_theme'] = 'Theme';
+$string['type_theme_plural'] = 'Themes';
+$string['type_webservice'] = 'Webservice protocol';
+$string['type_webservice_plural'] = 'Webservice protocols';
+$string['uninstall'] = 'Uninstall';
+$string['version'] = 'Version';
+$string['versiondb'] = 'Current version';
+$string['versiondisk'] = 'New version';
View
2  lang/en/repository.php
@@ -32,7 +32,7 @@
$string['allowexternallinks'] = 'Allow external links';
$string['areamainfile'] = 'Main file';
$string['coursebackup'] = 'Course backups';
-$string['pluginname'] = 'Repository plugin name';
+$string['pluginname'] = 'Repository plugin name'; // todo fix this, this string identifier is reserved
$string['pluginnamehelp'] = 'If you leave this empty the default name will be used.';
$string['sectionbackup'] = 'Section backups';
$string['activitybackup'] = 'Activity backup';
View
203 lib/adminlib.php
@@ -4587,6 +4587,21 @@ public function load_choices() {
/**
+ * General plugins manager
+ */
+class admin_page_pluginsoverview extends admin_externalpage {
+
+ /**
+ * Sets basic information about the external page
+ */
+ public function __construct() {
+ global $CFG;
+ parent::__construct('pluginsoverview', get_string('pluginsoverview', 'core_admin'),
+ "$CFG->wwwroot/$CFG->admin/plugins.php");
+ }
+}
+
+/**
* Module manage page
*
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
@@ -6117,194 +6132,6 @@ function db_replace($search, $replace) {
}
/**
- * Prints tables of detected plugins, one table per plugin type,
- * and prints whether they are part of the standard Moodle
- * distribution or not.
- */
-function print_plugin_tables() {
- global $DB;
- $plugins_standard = array();
- $plugins_standard['mod'] = array('assignment',
- 'chat',
- 'choice',
- 'data',
- 'feedback',
- 'folder',
- 'forum',
- 'glossary',
- 'imscp',
- 'label',
- 'lesson',
- 'page',
- 'quiz',
- 'resource',
- 'scorm',
- 'survey',
- 'url',
- 'wiki',
- 'workshop');
-
- $plugins_standard['blocks'] = array('activity_modules',
- 'admin_bookmarks',
- 'blog_menu',
- 'blog_recent',
- 'blog_tags',
- 'calendar_month',
- 'calendar_upcoming',
- 'comments',
- 'community',
- 'completionstatus',
- 'course_list',
- 'course_overview',
- 'course_summary',
- 'feedback',
- 'glossary_random',
- 'html',
- 'login',
- 'mentees',
- 'messages',
- 'mnet_hosts',
- 'myprofile',
- 'navigation',
- 'news_items',
- 'online_users',
- 'participants',
- 'private_files',
- 'quiz_results',
- 'recent_activity',
- 'rss_client',
- 'search',
- 'search_forums',
- 'section_links',
- 'selfcompletion',
- 'settings',
- 'site_main_menu',
- 'social_activities',
- 'tag_flickr',
- 'tag_youtube',
- 'tags');
-
- $plugins_standard['filter'] = array('activitynames',
- 'algebra',
- 'censor',
- 'emailprotect',
- 'emoticon',
- 'filter',
- 'mediaplugin',
- 'multilang',
- 'tex',
- 'tidy',
- 'urltolink');
-
- $plugins_installed = array();
- $installed_mods = $DB->get_records('modules', null, 'name');
- $installed_blocks = $DB->get_records('block', null, 'name');
-
- foreach($installed_mods as $mod) {
- $plugins_installed['mod'][] = $mod->name;
- }
-
- foreach($installed_blocks as $block) {
- $plugins_installed['blocks'][] = $block->name;
- }
- $plugins_installed['filter'] = array();
-
- $plugins_ondisk = array();
- $plugins_ondisk['mod'] = array_keys(get_plugin_list('mod'));
- $plugins_ondisk['blocks'] = array_keys(get_plugin_list('block'));
- $plugins_ondisk['filter'] = array_keys(get_plugin_list('filter'));
-
- $strstandard = get_string('standard');
- $strnonstandard = get_string('nonstandard');
- $strmissingfromdisk = '(' . get_string('missingfromdisk') . ')';
- $strabouttobeinstalled = '(' . get_string('abouttobeinstalled') . ')';
-
- $html = '';
-
- $html .= '<table class="generaltable plugincheckwrapper" cellspacing="4" cellpadding="1"><tr valign="top">';
-
- foreach ($plugins_ondisk as $cat => $list_ondisk) {
- if ($cat == 'mod') {
- $strcaption = get_string('activitymodule');
- } elseif ($cat == 'filter') {
- $strcaption = get_string('managefilters');
- } else {
- $strcaption = get_string($cat);
- }
-
- $html .= '<td><table class="plugincompattable generaltable boxaligncenter" cellspacing="1" cellpadding="5" '
- . 'id="' . $cat . 'compattable" summary="compatibility table"><caption>' . $strcaption . '</caption>' . "\n";
- $html .= '<tr class="r0"><th class="header c0">' . get_string('directory') . "</th>\n"
- . '<th class="header c1">' . get_string('name') . "</th>\n"
- . '<th class="header c2">' . get_string('status') . "</th>\n</tr>\n";
-
- $row = 1;
-
- foreach ($list_ondisk as $k => $plugin) {
- $status = 'ok';
- $standard = 'standard';
- $note = '';
-
- if (!in_array($plugin, $plugins_standard[$cat])) {
- $standard = 'nonstandard';
- $status = 'warning';
- }
-
- // Get real name and full path of plugin
- $plugin_name = "[[$plugin]]";
-
- $plugin_path = "$cat/$plugin";
-
- $plugin_name = get_plugin_name($plugin, $cat);
-
- // Determine if the plugin is about to be installed
- if ($cat != 'filter' && !in_array($plugin, $plugins_installed[$cat])) {
- $note = $strabouttobeinstalled;
- $plugin_name = $plugin;
- }
-
- $html .= "<tr class=\"r$row\">\n"
- . "<td class=\"cell c0\">$plugin_path</td>\n"
- . "<td class=\"cell c1\">$plugin_name</td>\n"
- . "<td class=\"$standard $status cell c2\">" . ${'str' . $standard} . " $note</td>\n</tr>\n";
- $row++;
-
- // If the plugin was both on disk and in the db, unset the value from the installed plugins list
- if ($key = array_search($plugin, $plugins_installed[$cat])) {
- unset($plugins_installed[$cat][$key]);
- }
- }
-
- // If there are plugins left in the plugins_installed list, it means they are missing from disk
- foreach ($plugins_installed[$cat] as $k => $missing_plugin) {
- // Make sure the plugin really is missing from disk
- if (!in_array($missing_plugin, $plugins_ondisk[$cat])) {
- $standard = 'standard';
- $status = 'warning';
-
- if (!in_array($missing_plugin, $plugins_standard[$cat])) {
- $standard = 'nonstandard';
- }
-
- $plugin_name = $missing_plugin;
- $html .= "<tr class=\"r$row\">\n"
- . "<td class=\"cell c0\">?</td>\n"
- . "<td class=\"cell c1\">$plugin_name</td>\n"
- . "<td class=\"$standard $status cell c2\">" . ${'str' . $standard} . " $strmissingfromdisk</td>\n</tr>\n";
- $row++;
- }
- }
-
- $html .= '</table></td>';
- }
-
- $html .= '</tr></table><br />';
-
- echo $html;
-}
-
-
-/**
* Manage repository settings
*
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
View
35 lib/moodlelib.php
@@ -9660,41 +9660,6 @@ function object_array_unique($array, $keep_key_assoc = true) {
}
/**
- * Returns the language string for the given plugin.
- *
- * @param string $plugin the plugin code name
- * @param string $type the type of plugin (mod, block, filter)
- * @return string The plugin language string
- */
-function get_plugin_name($plugin, $type='mod') {
- $plugin_name = '';
-
- switch ($type) {
- case 'mod':
- $plugin_name = get_string('modulename', $plugin);
- break;
- case 'blocks':
- $plugin_name = get_string('pluginname', "block_$plugin");
- if (empty($plugin_name) || $plugin_name == '[[pluginname]]') {
- if (($block = block_instance($plugin)) !== false) {
- $plugin_name = $block->get_title();
- } else {
- $plugin_name = "[[$plugin]]";
- }
- }
- break;
- case 'filter':
- $plugin_name = filter_get_name('filter/' . $plugin);
- break;
- default:
- $plugin_name = $plugin;
- break;
- }
-
- return $plugin_name;
-}
-
-/**
* Is a userid the primary administrator?
*
* @param int $userid int id of user to check
View
8 lib/outputrequirementslib.php
@@ -847,13 +847,13 @@ public function string_for_js($identifier, $component, $a = NULL) {
* passed in $module.
*
* <code>
- * $PAGE->strings_for_js(Array('one', 'two', 'three'), 'mymod', Array('a', null, 3));
+ * $PAGE->requires->strings_for_js(array('one', 'two', 'three'), 'mymod', array('a', null, 3));
*
* // The above is identitical to calling
*
- * $PAGE->string_for_js('one', 'mymod', 'a');
- * $PAGE->string_for_js('two', 'mymod');
- * $PAGE->string_for_js('three', 'mymod', 3);
+ * $PAGE->requires->string_for_js('one', 'mymod', 'a');
+ * $PAGE->requires->string_for_js('two', 'mymod');
+ * $PAGE->requires->string_for_js('three', 'mymod', 3);
* </code>
*
* @param array $identifiers An array of desired strings
View
1,483 lib/pluginlib.php
@@ -0,0 +1,1483 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Defines classes used for plugins management
+ *
+ * This library provides a unified interface to various plugin types in
+ * Moodle. It is mainly used by the plugins management admin page and the
+ * plugins check page during the upgrade.
+ *
+ * @package core
+ * @subpackage admin
+ * @copyright 2011 David Mudrak <david@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Singleton class providing general plugins management functionality
+ */
+class plugin_manager {
+
+ /** the plugin is shipped with standard Moodle distribution */
+ const PLUGIN_SOURCE_STANDARD = 'std';
+ /** the plugin is added extension */
+ const PLUGIN_SOURCE_EXTENSION = 'ext';
+
+ /** the plugin uses neither database nor capabilities, no versions */
+ const PLUGIN_STATUS_NODB = 'nodb';
+ /** the plugin is up-to-date */
+ const PLUGIN_STATUS_UPTODATE = 'uptodate';
+ /** the plugin is about to be installed */
+ const PLUGIN_STATUS_NEW = 'new';
+ /** the plugin is about to be upgraded */
+ const PLUGIN_STATUS_UPGRADE = 'upgrade';
+ /** the version at the disk is lower than the one already installed */
+ const PLUGIN_STATUS_DOWNGRADE = 'downgrade';
+ /** the plugin is installed but missing from disk */
+ const PLUGIN_STATUS_MISSING = 'missing';
+
+ /** @var plugin_manager holds the singleton instance */
+ protected static $singletoninstance;
+ /** @var array of raw plugins information */
+ protected $pluginsinfo = null;
+ /** @var array of raw subplugins information */
+ protected $subpluginsinfo = null;
+
+ /**
+ * Direct initiation not allowed, use the factory method {@link self::instance()}
+ *
+ * @todo we might want to specify just a single plugin type to work with
+ */
+ protected function __construct() {
+ $this->get_plugins(true);
+ }
+
+ /**
+ * Sorry, this is singleton
+ */
+ protected function __clone() {
+ }
+
+ /**
+ * Factory method for this class
+ *
+ * @return plugin_manager the singleton instance
+ */
+ public static function instance() {
+ global $CFG;
+
+ if (is_null(self::$singletoninstance)) {
+ self::$singletoninstance = new self();
+ }
+ return self::$singletoninstance;
+ }
+
+ /**
+ * Returns a tree of known plugins and information about them
+ *
+ * @param bool $disablecache force reload, cache can be used otherwise
+ * @return array
+ */
+ public function get_plugins($disablecache=false) {
+
+ if ($disablecache or is_null($this->pluginsinfo)) {
+ $this->pluginsinfo = array();
+ $plugintypes = get_plugin_types();
+ foreach ($plugintypes as $plugintype => $plugintyperootdir) {
+ if (in_array($plugintype, array('base', 'general'))) {
+ throw new coding_exception('Illegal usage of reserved word for plugin type');
+ }
+ if (class_exists('plugintype_' . $plugintype)) {
+ $plugintypeclass = 'plugintype_' . $plugintype;
+ } else {
+ $plugintypeclass = 'plugintype_general';
+ }
+ if (!in_array('plugintype_interface', class_implements($plugintypeclass))) {
+ throw new coding_exception('Class ' . $plugintypeclass . ' must implement plugintype_interface');
+ }
+ $plugins = call_user_func(array($plugintypeclass, 'get_plugins'), $plugintype, $plugintyperootdir, $plugintypeclass);
+ $this->pluginsinfo[$plugintype] = $plugins;
+ }
+ }
+
+ return $this->pluginsinfo;
+ }
+
+ /**
+ * Returns list of plugins that define their subplugins and information about them
+ *
+ * At the moment, only activity modules can define subplugins.
+ *
+ * @param double $disablecache force reload, cache can be used otherwise
+ * @return array
+ */
+ public function get_subplugins($disablecache=false) {
+
+ if ($disablecache or is_null($this->subpluginsinfo)) {
+ $this->subpluginsinfo = array();
+ $mods = get_plugin_list('mod');
+ foreach ($mods as $mod => $moddir) {
+ $modsubplugins = array();
+ if (file_exists($moddir . '/db/subplugins.php')) {
+ include($moddir . '/db/subplugins.php');
+ foreach ($subplugins as $subplugintype => $subplugintyperootdir) {
+ $subplugin = new stdClass();
+ $subplugin->type = $subplugintype;
+ $subplugin->typerootdir = $subplugintyperootdir;
+ $modsubplugins[$subplugintype] = $subplugin;
+ }
+ $this->subpluginsinfo['mod_' . $mod] = $modsubplugins;
+ }
+ }
+ }
+
+ return $this->subpluginsinfo;
+ }
+
+ /**
+ * Returns the name of the plugin that defines the given subplugin type
+ *
+ * If the given subplugin type is not actually a subplugin, returns false.
+ *
+ * @param string $subplugintype the name of subplugin type, eg. workshopform or quiz
+ * @return false|string the name of the parent plugin, eg. mod_workshop
+ */
+ public function get_parent_of_subplugin($subplugintype) {
+
+ $parent = false;
+ foreach ($this->get_subplugins() as $pluginname => $subplugintypes) {
+ if (isset($subplugintypes[$subplugintype])) {
+ $parent = $pluginname;
+ break;
+ }
+ }
+
+ return $parent;
+ }
+
+ /**
+ * Returns a localized name of a given plugin
+ *
+ * @param string $plugin name of the plugin, eg mod_workshop or auth_ldap
+ * @return string
+ */
+ public function plugin_name($plugin) {
+ list($type, $name) = normalize_component($plugin);
+ return $this->pluginsinfo[$type][$name]->displayname;
+ }
+
+ /**
+ * Returns a localized name of a plugin type in plural form
+ *
+ * Most plugin types define their names in core_plugin lang file. In case of subplugins,
+ * we try to ask the parent plugin for the name. In the worst case, we will return
+ * the value of the passed $type parameter.
+ *
+ * @param string $type the type of the plugin, e.g. mod or workshopform
+ * @return string
+ */
+ public function plugintype_name_plural($type) {
+
+ if (get_string_manager()->string_exists('type_' . $type . '_plural', 'core_plugin')) {
+ // for most plugin types, their names are defined in core_plugin lang file
+ return get_string('type_' . $type . '_plural', 'core_plugin');
+
+ } else if ($parent = $this->get_parent_of_subplugin($type)) {
+ // if this is a subplugin, try to ask the parent plugin for the name
+ if (get_string_manager()->string_exists('subplugintype_' . $type . '_plural', $parent)) {
+ return $this->plugin_name($parent) . ' / ' . get_string('subplugintype_' . $type . '_plural', $parent);
+ } else {
+ return $this->plugin_name($parent) . ' / ' . $type;
+ }
+
+ } else {
+ return $type;
+ }
+ }
+
+ /**
+ * Defines a white list of all plugins shipped in the standard Moodle distribution
+ *
+ * @return false|array array of standard plugins or false if the type is unknown
+ */
+ public static function standard_plugins_list($type) {
+ static $standard_plugins = array(
+
+ 'assignment' => array(
+ 'offline', 'online', 'upload', 'uploadsingle'
+ ),
+
+ 'auth' => array(
+ 'cas', 'db', 'email', 'fc', 'imap', 'ldap', 'manual', 'mnet',
+ 'nntp', 'nologin', 'none', 'pam', 'pop3', 'radius',
+ 'shibboleth', 'webservice'
+ ),
+
+ 'block' => array(
+ 'activity_modules', 'admin_bookmarks', 'blog_menu',
+ 'blog_recent', 'blog_tags', 'calendar_month',
+ 'calendar_upcoming', 'comments', 'community',
+ 'completionstatus', 'course_list', 'course_overview',
+ 'course_summary', 'feedback', 'glossary_random', 'html',
+ 'login', 'mentees', 'messages', 'mnet_hosts', 'myprofile',
+ 'navigation', 'news_items', 'online_users', 'participants',
+ 'private_files', 'quiz_results', 'recent_activity',
+ 'rss_client', 'search', 'search_forums', 'section_links',
+ 'selfcompletion', 'settings', 'site_main_menu',
+ 'social_activities', 'tag_flickr', 'tag_youtube', 'tags'
+ ),
+
+ 'coursereport' => array(
+ 'completion', 'log', 'outline', 'participation', 'progress', 'stats'
+ ),
+
+ 'datafield' => array(
+ 'checkbox', 'date', 'file', 'latlong', 'menu', 'multimenu',
+ 'number', 'picture', 'radiobutton', 'text', 'textarea', 'url'
+ ),
+
+ 'datapreset' => array(
+ 'imagegallery'
+ ),
+
+ 'editor' => array(
+ 'textarea', 'tinymce'
+ ),
+
+ 'enrol' => array(
+ 'authorize', 'category', 'cohort', 'database', 'flatfile',
+ 'guest', 'imsenterprise', 'ldap', 'manual', 'meta', 'mnet',
+ 'paypal', 'self'
+ ),
+
+ 'filter' => array(
+ 'activitynames', 'algebra', 'censor', 'emailprotect',
+ 'emoticon', 'mediaplugin', 'multilang', 'tex', 'tidy',
+ 'urltolink', 'mod_data', 'mod_glossary'
+ ),
+
+ 'format' => array(
+ 'scorm', 'social', 'topics', 'weeks'
+ ),
+
+ 'gradeexport' => array(
+ 'ods', 'txt', 'xls', 'xml'
+ ),
+
+ 'gradeimport' => array(
+ 'csv', 'xml'
+ ),
+
+ 'gradereport' => array(
+ 'grader', 'outcomes', 'overview', 'user'
+ ),
+
+ 'local' => array(
+ ),
+
+ 'message' => array(
+ 'email', 'jabber', 'popup'
+ ),
+
+ 'mnetservice' => array(
+ 'enrol'
+ ),
+
+ 'mod' => array(
+ 'assignment', 'chat', 'choice', 'data', 'feedback', 'folder',
+ 'forum', 'glossary', 'imscp', 'label', 'lesson', 'page',
+ 'quiz', 'resource', 'scorm', 'survey', 'url', 'wiki', 'workshop'
+ ),
+
+ 'plagiarism' => array(
+ ),
+
+ 'portfolio' => array(
+ 'boxnet', 'download', 'flickr', 'googledocs', 'mahara', 'picasa'
+ ),
+
+ 'profilefield' => array(
+ 'checkbox', 'datetime', 'menu', 'text', 'textarea'
+ ),
+
+ 'qformat' => array(
+ 'aiken', 'blackboard', 'blackboard_six', 'examview', 'gift',
+ 'learnwise', 'missingword', 'multianswer', 'qti_two', 'webct',
+ 'xhtml', 'xml'
+ ),
+
+ 'qtype' => array(
+ 'calculated', 'calculatedmulti', 'calculatedsimple',
+ 'description', 'essay', 'match', 'missingtype', 'multianswer',
+ 'multichoice', 'numerical', 'random', 'randomsamatch',
+ 'shortanswer', 'truefalse'
+ ),
+
+ 'quiz' => array(
+ 'grading', 'overview', 'responses', 'statistics'
+ ),
+
+ 'report' => array(
+ 'backups', 'capability', 'configlog', 'courseoverview',
+ 'customlang', 'log', 'profiling', 'questioninstances',
+ 'security', 'spamcleaner', 'stats', 'unittest', 'unsuproles'
+ ),
+
+ 'repository' => array(
+ 'alfresco', 'boxnet', 'coursefiles', 'dropbox', 'filesystem',
+ 'flickr', 'flickr_public', 'googledocs', 'local', 'merlot',
+ 'picasa', 'recent', 's3', 'upload', 'url', 'user', 'webdav',
+ 'wikimedia', 'youtube'
+ ),
+
+ 'theme' => array(
+ 'anomaly', 'arialist', 'base', 'binarius', 'boxxie', 'brick',
+ 'canvas', 'formal_white', 'formfactor', 'fusion',
+ 'leatherbound', 'magazine', 'nimble', 'nonzero', 'overlay',
+ 'serenity', 'sky_high', 'splash', 'standard', 'standardold'
+ ),
+
+ 'webservice' => array(
+ 'amf', 'rest', 'soap', 'xmlrpc'
+ ),
+
+ 'workshopallocation' => array(
+ 'manual', 'random'
+ ),
+
+ 'workshopeval' => array(
+ 'best'
+ ),
+
+ 'workshopform' => array(
+ 'accumulative', 'comments', 'numerrors', 'rubric'
+ )
+ );
+
+ if (isset($standard_plugins[$type])) {
+ return $standard_plugins[$type];
+
+ } else {
+ return false;
+ }
+ }
+}
+
+/**
+ * All classes that represent a plugin of some type must implement this interface
+ */
+interface plugintype_interface {
+
+ /**
+ * Gathers and returns the information about all plugins of the given type
+ *
+ * Passing the parameter $typeclass allows us to reach the same effect as with the
+ * late binding in PHP 5.3. Once PHP 5.3 is required, we can refactor this to use
+ * {@example $plugin = new static();} instead of {@example $plugin = new $typeclass()}
+ *
+ * @param string $type the name of the plugintype, eg. mod, auth or workshopform
+ * @param string $typerootdir full path to the location of the plugin dir
+ * @param string $typeclass the name of the actually called class
+ * @return array of plugintype classes, indexed by the plugin name
+ */
+ public static function get_plugins($type, $typerootdir, $typeclass);
+
+ /**
+ * Sets $displayname property to a localized name of the plugin
+ *
+ * @return void
+ */
+ public function set_display_name();
+
+ /**
+ * Sets $versiondisk property to a numerical value representing the
+ * version of the plugin's source code.
+ *
+ * If the value is null after calling this method, either the plugin
+ * does not use versioning (typically does not have any database
+ * data) or is missing from disk.
+ *
+ * @return void
+ */
+ public function set_version_disk();
+
+ /**
+ * Sets $versiondb property to a numerical value representing the
+ * currently installed version of the plugin.
+ *
+ * If the value is null after calling this method, either the plugin
+ * does not use versioning (typically does not have any database
+ * data) or has not been installed yet.
+ *
+ * @return void
+ */
+ public function set_version_db();
+
+ /**
+ * Sets $versionrequires property to a numerical value representing
+ * the version of Moodle core that this plugin requires.
+ *
+ * @return void
+ */
+ public function set_version_requires();
+
+ /**
+ * Sets $source property to one of plugin_manager::PLUGIN_SOURCE_xxx
+ * constants.
+ *
+ * If the property's value is null after calling this method, then
+ * the type of the plugin has not been recognized and you should throw
+ * an exception.
+ *
+ * @return void
+ */
+ public function set_source();
+
+ /**
+ * Returns true if the plugin is shipped with the official distribution
+ * of the current Moodle version, false otherwise.
+ *
+ * @return bool
+ */
+ public function is_standard();
+
+ /**
+ * Returns the status of the plugin
+ *
+ * @return string one of plugin_manager::PLUGIN_STATUS_xxx constants
+ */
+ public function get_status();
+
+ /**
+ * Returns the information about plugin availability
+ *
+ * True means that the plugin is enabled. False means that the plugin is
+ * disabled. Null means that the information is not available, or the
+ * plugin does not support configurable availability or the availability
+ * can not be changed.
+ *
+ * @return null|bool
+ */
+ public function is_enabled();
+
+ /**
+ * Returns the URL of the plugin settings screen
+ *
+ * Null value means that the plugin either does not have the settings screen
+ * or its location is not available via this library.
+ *
+ * @return null|moodle_url
+ */
+ public function get_settings_url();
+
+ /**
+ * 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. Null value means that the
+ * plugin either does not support uninstallation, or does not require any
+ * database cleanup or the location of the screen is not available via this
+ * library.
+ *
+ * @return null|moodle_url
+ */
+ public function get_uninstall_url();
+
+ /**
+ * Returns relative directory of the plugin with heading '/'
+ *
+ * @example /mod/workshop
+ * @return string
+ */
+ public function get_dir();
+}
+
+/**
+ * Defines public properties that all plugintype classes must have
+ * and provides default implementation of required methods.
+ */
+abstract class plugintype_base {
+
+ /** @var string the plugintype name, eg. mod, auth or workshopform */
+ public $type;
+ /** @var string full path to the location of all the plugins of this type */
+ public $typerootdir;
+ /** @var string the plugin name, eg. assignment, ldap */
+ public $name;
+ /** @var string the localized plugin name */
+ public $displayname;
+ /** @var string the plugin source, one of plugin_manager::PLUGIN_SOURCE_xxx constants */
+ public $source;
+ /** @var fullpath to the location of this plugin */
+ public $rootdir;
+ /** @var int|string the version of the plugin's source code */
+ public $versiondisk;
+ /** @var int|string the version of the installed plugin */
+ public $versiondb;
+ /** @var int|float|string required version of Moodle core */
+ public $versionrequires;
+ /** @var int number of instances of the plugin - not supported yet */
+ public $instances;
+ /** @var int order of the plugin among other plugins of the same type - not supported yet */
+ public $sortorder;
+
+ /**
+ * @see plugintype_interface::get_plugins()
+ */
+ public static function get_plugins($type, $typerootdir, $typeclass) {
+
+ // get the information about plugins at the disk
+ $plugins = get_plugin_list($type);
+ $ondisk = array();
+ foreach ($plugins as $pluginname => $pluginrootdir) {
+ $plugin = new $typeclass();
+ $plugin->type = $type;
+ $plugin->typerootdir = $typerootdir;
+ $plugin->name = $pluginname;
+ $plugin->rootdir = $pluginrootdir;
+
+ $plugin->set_display_name();
+ $plugin->set_version_disk();
+ $plugin->set_version_db();
+ $plugin->set_version_requires();
+ $plugin->set_source();
+
+ $ondisk[$pluginname] = $plugin;
+ }
+ return $ondisk;
+ }
+
+ /**
+ * @see plugintype_interface::set_display_name()
+ */
+ public function set_display_name() {
+ if (! get_string_manager()->string_exists('pluginname', $this->type . '_' . $this->name)) {
+ $this->displayname = '[pluginname,' . $this->type . '_' . $this->name . ']';
+ } else {
+ $this->displayname = get_string('pluginname', $this->type . '_' . $this->name);
+ }
+ }
+
+ /**
+ * @see plugintype_interface::set_version_disk()
+ */
+ public function set_version_disk() {
+
+ if (empty($this->rootdir)) {
+ return;
+ }
+
+ $versionfile = $this->rootdir . '/version.php';
+
+ if (is_readable($versionfile)) {
+ include($versionfile);
+ if (isset($plugin->version)) {
+ $this->versiondisk = $plugin->version;
+ }
+ }
+ }
+
+ /**
+ * @see plugintype_interface::set_version_db()
+ */
+ public function set_version_db() {
+
+ if ($ver = self::get_version_from_config_plugins($this->type . '_' . $this->name)) {
+ $this->versiondb = $ver;
+ }
+ }
+
+ /**
+ * @see plugintype_interface::set_version_requires()
+ */
+ public function set_version_requires() {
+
+ if (empty($this->rootdir)) {
+ return;
+ }
+
+ $versionfile = $this->rootdir . '/version.php';
+
+ if (is_readable($versionfile)) {
+ include($versionfile);
+ if (isset($plugin->requires)) {
+ $this->versionrequires = $plugin->requires;
+ }
+ }
+ }
+
+ /**
+ * @see plugintype_interface::set_source()
+ */
+ public function set_source() {
+
+ $standard = plugin_manager::standard_plugins_list($this->type);
+
+ if ($standard !== false) {
+ $standard = array_flip($standard);
+ if (isset($standard[$this->name])) {
+ $this->source = plugin_manager::PLUGIN_SOURCE_STANDARD;
+ } else {
+ $this->source = plugin_manager::PLUGIN_SOURCE_EXTENSION;
+ }
+ }
+ }
+
+ /**
+ * @see plugintype_interface::is_standard()
+ */
+ public function is_standard() {
+ return $this->source === plugin_manager::PLUGIN_SOURCE_STANDARD;
+ }
+
+ /**
+ * @see plugintype_interface::get_status()
+ */
+ public function get_status() {
+
+ if (is_null($this->versiondb) and is_null($this->versiondisk)) {
+ return plugin_manager::PLUGIN_STATUS_NODB;
+
+ } else if (is_null($this->versiondb) and !is_null($this->versiondisk)) {
+ return plugin_manager::PLUGIN_STATUS_NEW;
+
+ } else if (!is_null($this->versiondb) and is_null($this->versiondisk)) {
+ return plugin_manager::PLUGIN_STATUS_MISSING;
+
+ } else if ((string)$this->versiondb === (string)$this->versiondisk) {
+ return plugin_manager::PLUGIN_STATUS_UPTODATE;
+
+ } else if ($this->versiondb < $this->versiondisk) {
+ return plugin_manager::PLUGIN_STATUS_UPGRADE;
+
+ } else if ($this->versiondb > $this->versiondisk) {
+ return plugin_manager::PLUGIN_STATUS_DOWNGRADE;
+
+ } else {
+ // $version = pi(); and similar funny jokes - hopefully Donald E. Knuth will never contribute to Moodle ;-)
+ throw new coding_exception('Unable to determine plugin state, check the plugin versions');
+ }
+ }
+
+ /**
+ * @see plugintype_interface::is_enabled()
+ */
+ public function is_enabled() {
+ return null;
+ }
+
+ /**
+ * @see plugintype_interface::get_settings_url()
+ */
+ public function get_settings_url() {
+ return null;
+ }
+
+ /**
+ * @see plugintype_interface::get_uninstall_url()
+ */
+ public function get_uninstall_url() {
+ return null;
+ }
+
+ /**
+ * @see plugintype_interface::get_dir()
+ */
+ public function get_dir() {
+ global $CFG;
+
+ return substr($this->rootdir, strlen($CFG->dirroot));
+ }
+
+ /**
+ * Provides access to plugin versions from {config_plugins}
+ *
+ * @param string $plugin plugin name
+ * @param double $disablecache optional, defaults to false
+ * @return int|false the stored value or false if not found
+ */
+ protected function get_version_from_config_plugins($plugin, $disablecache=false) {
+ global $DB;
+ static $pluginversions = null;
+
+ if (is_null($pluginversions) or $disablecache) {
+ $pluginversions = $DB->get_records_menu('config_plugins', array('name' => 'version'), 'plugin', 'plugin,value');
+ }
+
+ if (!array_key_exists($plugin, $pluginversions)) {
+ return false;
+ }
+
+ return $pluginversions[$plugin];
+ }
+}
+
+/**
+ * General class for all plugin types that do not have their own class
+ */
+class plugintype_general extends plugintype_base implements plugintype_interface {
+
+}
+
+/**
+ * Class for page side blocks
+ */
+class plugintype_block extends plugintype_base implements plugintype_interface {
+
+ /**
+ * @see plugintype_interface::get_plugins()
+ */
+ public static function get_plugins($type, $typerootdir, $typeclass) {
+
+ // get the information about blocks at the disk
+ $blocks = parent::get_plugins($type, $typerootdir, $typeclass);
+
+ // add blocks missing from disk
+ $blocksinfo = self::get_blocks_info();
+ foreach ($blocksinfo as $blockname => $blockinfo) {
+ if (isset($blocks[$blockname])) {
+ continue;
+ }
+ $plugin = new $typeclass();
+ $plugin->type = $type;
+ $plugin->typerootdir = $typerootdir;
+ $plugin->name = $blockname;
+ $plugin->rootdir = null;
+ $plugin->displayname = $blockname;
+ $plugin->versiondb = $blockinfo->version;
+ $plugin->set_source();
+
+ $blocks[$blockname] = $plugin;
+ }
+
+ return $blocks;
+ }
+
+ /**
+ * @see plugintype_interface::set_display_name()
+ */
+ public function set_display_name() {
+
+ if (get_string_manager()->string_exists('pluginname', 'block_' . $this->name)) {
+ $this->displayname = get_string('pluginname', 'block_' . $this->name);
+
+ } else if (($block = block_instance($this->name)) !== false) {
+ $this->displayname = $block->get_title();
+
+ } else {
+ parent::set_display_name();
+ }
+ }
+
+ /**
+ * @see plugintype_interface::set_version_db()
+ */
+ public function set_version_db() {
+ global $DB;
+
+ $blocksinfo = self::get_blocks_info();
+ if (isset($blocksinfo[$this->name]->version)) {
+ $this->versiondb = $blocksinfo[$this->name]->version;
+ }
+ }
+
+ /**
+ * @see plugintype_interface::is_enabled()
+ */
+ public function is_enabled() {
+
+ $blocksinfo = self::get_blocks_info();
+ if (isset($blocksinfo[$this->name]->visible)) {
+ if ($blocksinfo[$this->name]->visible) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return parent::is_enabled();
+ }
+ }
+
+ /**
+ * @see plugintype_interface::get_settings_url()
+ */
+ public function get_settings_url() {
+
+ if (($block = block_instance($this->name)) === false) {
+ return parent::get_settings_url();
+
+ } else if ($block->has_config()) {
+ if (!empty($this->rootdir) and file_exists($this->rootdir . '/settings.php')) {
+ return new moodle_url('/admin/settings.php', array('section' => 'blocksetting' . $this->name));
+ } else {
+ $blocksinfo = self::get_blocks_info();
+ return new moodle_url('/admin/block.php', array('block' => $blocksinfo[$this->name]->id));
+ }
+
+ } else {
+ return parent::get_settings_url();
+ }
+ }
+
+ /**
+ * @see plugintype_interface::get_uninstall_url()
+ */
+ 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()));
+ }
+
+ /**
+ * Provides access to the records in {block} table
+ *
+ * @param bool $disablecache do not use internal static cache
+ * @return array array of stdClasses
+ */
+ protected static function get_blocks_info($disablecache=false) {
+ global $DB;
+ static $blocksinfocache = null;
+
+ if (is_null($blocksinfocache) or $disablecache) {
+ $blocksinfocache = $DB->get_records('block', null, 'name', 'name,id,version,visible');
+ }
+
+ return $blocksinfocache;
+ }
+}
+
+/**
+ * Class for text filters
+ */
+class plugintype_filter extends plugintype_base implements plugintype_interface {
+
+ /**
+ * @see plugintype_interface::get_plugins()
+ */
+ public static function get_plugins($type, $typerootdir, $typeclass) {
+ global $CFG;
+
+ $filters = array();
+
+ // get the list of filters from both /filter and /mod location
+ $installed = filter_get_all_installed();
+
+ foreach ($installed as $filterlegacyname => $displayname) {
+ $plugin = new $typeclass();
+ $plugin->type = $type;
+ $plugin->typerootdir = $typerootdir;
+ $plugin->name = self::normalize_legacy_name($filterlegacyname);
+ $plugin->rootdir = $CFG->dirroot . '/' . $filterlegacyname;
+ $plugin->displayname = $displayname;
+
+ $plugin->set_version_disk();
+ $plugin->set_version_db();
+ $plugin->set_version_requires();
+ $plugin->set_source();
+
+ $filters[$plugin->name] = $plugin;
+ }
+
+ // make sure that all installed filters are registered
+ $globalstates = self::get_global_states();
+ $needsreload = false;
+ foreach (array_keys($installed) as $filterlegacyname) {
+ if (!isset($globalstates[self::normalize_legacy_name($filterlegacyname)])) {
+ filter_set_global_state($filterlegacyname, TEXTFILTER_DISABLED);
+ $needsreload = true;
+ }
+ }
+ if ($needsreload) {
+ $globalstates = self::get_global_states(true);
+ }
+
+ // make sure that all registered filters are installed, just in case
+ foreach ($globalstates as $name => $info) {
+ if (!isset($filters[$name])) {
+ // oops, there is a record in filter_active but the filter is not installed
+ $plugin = new $typeclass();
+ $plugin->type = $type;
+ $plugin->typerootdir = $typerootdir;
+ $plugin->name = $name;
+ $plugin->rootdir = $CFG->dirroot . '/' . $info->legacyname;
+ $plugin->displayname = $info->legacyname;
+
+ $plugin->set_version_db();
+
+ if (is_null($plugin->versiondb)) {
+ // this is a hack to stimulate 'Missing from disk' error
+ // because $plugin->versiondisk will be null !== false
+ $plugin->versiondb = false;
+ }
+
+ $filters[$plugin->name] = $plugin;
+ }
+ }
+
+ return $filters;
+ }
+
+ /**
+ * @see plugintype_interface::set_display_name()
+ */
+ public function set_display_name() {
+ // do nothing, the name is set in self::get_plugins()
+ }
+
+ /**
+ * @see plugintype_interface::set_version_disk()
+ */
+ public function set_version_disk() {
+
+ if (strpos($this->name, 'mod_') === 0) {
+ // filters bundled with modules do not use versioning
+ return;
+ }
+
+ return parent::set_version_disk();
+ }
+
+ /**
+ * @see plugintype_interface::set_version_requires()
+ */
+ public function set_version_requires() {
+
+ if (strpos($this->name, 'mod_') === 0) {
+ // filters bundled with modules do not use versioning
+ return;
+ }
+
+ return parent::set_version_requires();
+ }
+
+ /**
+ * @see plugintype_interface::is_enabled()
+ */
+ public function is_enabled() {
+
+ $globalstates = self::get_global_states();
+
+ foreach ($globalstates as $filterlegacyname => $info) {
+ $name = self::normalize_legacy_name($filterlegacyname);
+ if ($name === $this->name) {
+ if ($info->active == TEXTFILTER_DISABLED) {
+ return false;
+ } else {
+ // it may be 'On' or 'Off, but available'
+ return null;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * @see plugintype_interface::get_settings_url()
+ */
+ public function get_settings_url() {
+
+ $globalstates = self::get_global_states();
+ $legacyname = $globalstates[$this->name]->legacyname;
+ if (filter_has_global_settings($legacyname)) {
+ return new moodle_url('/admin/settings.php', array('section' => 'filtersetting' . str_replace('/', '', $legacyname)));
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * @see plugintype_interface::get_uninstall_url()
+ */
+ public function get_uninstall_url() {
+
+ if (strpos($this->name, 'mod_') === 0) {
+ return null;
+ } else {
+ $globalstates = self::get_global_states();
+ $legacyname = $globalstates[$this->name]->legacyname;
+ return new moodle_url('/admin/filters.php', array('sesskey' => sesskey(), 'filterpath' => $legacyname, 'action' => 'delete'));
+ }
+ }
+
+ /**
+ * Convert legacy filter names like 'filter/foo' or 'mod/bar' into frankenstyle
+ *
+ * @param string $legacyfiltername legacy filter name
+ * @return string frankenstyle-like name
+ */
+ protected static function normalize_legacy_name($legacyfiltername) {
+
+ $name = str_replace('/', '_', $legacyfiltername);
+ if (strpos($name, 'filter_') === 0) {
+ $name = substr($name, 7);
+ if (empty($name)) {
+ throw new coding_exception('Unable to determine filter name: ' . $legacyfiltername);
+ }
+ }
+
+ return $name;
+ }
+
+ /**
+ * Provides access to the results of {@link filter_get_global_states()}
+ * but indexed by the normalized filter name
+ *
+ * The legacy filter name is available as ->legacyname property.
+ *
+ * @param bool $disablecache
+ * @return array
+ */
+ protected static function get_global_states($disablecache=false) {
+ global $DB;
+ static $globalstatescache = null;
+
+ if ($disablecache or is_null($globalstatescache)) {
+
+ if (!$DB->get_manager()->table_exists('filter_active')) {
+ // we're upgrading from 1.9 and the table used by {@link filter_get_global_states()}
+ // does not exist yet
+ $globalstatescache = array();
+
+ } else {
+ foreach (filter_get_global_states() as $legacyname => $info) {
+ $name = self::normalize_legacy_name($legacyname);
+ $filterinfo = new stdClass();
+ $filterinfo->legacyname = $legacyname;
+ $filterinfo->active = $info->active;
+ $filterinfo->sortorder = $info->sortorder;
+ $globalstatescache[$name] = $filterinfo;
+ }
+ }
+ }
+
+ return $globalstatescache;
+ }
+}
+
+/**
+ * Class for activity modules
+ */
+class plugintype_mod extends plugintype_base implements plugintype_interface {
+
+ /**
+ * @see plugintype_interface::get_plugins()
+ */
+ public static function get_plugins($type, $typerootdir, $typeclass) {
+
+ // get the information about plugins at the disk
+ $modules = parent::get_plugins($type, $typerootdir, $typeclass);
+
+ // add modules missing from disk
+ $modulesinfo = self::get_modules_info();
+ foreach ($modulesinfo as $modulename => $moduleinfo) {
+ if (isset($modules[$modulename])) {
+ continue;
+ }
+ $plugin = new $typeclass();
+ $plugin->type = $type;
+ $plugin->typerootdir = $typerootdir;
+ $plugin->name = $modulename;
+ $plugin->rootdir = null;
+ $plugin->displayname = $modulename;
+ $plugin->versiondb = $moduleinfo->version;
+ $plugin->set_source();
+
+ $modules[$modulename] = $plugin;
+ }
+
+ return $modules;
+ }
+
+ /**
+ * @see plugintype_interface::set_display_name()
+ */
+ public function set_display_name() {
+ if (get_string_manager()->string_exists('pluginname', $this->type . '_' . $this->name)) {
+ $this->displayname = get_string('pluginname', $this->type . '_' . $this->name);
+ } else {
+ $this->displayname = get_string('modulename', $this->type . '_' . $this->name);
+ }
+ }
+
+ /**
+ * @see plugintype_interface::set_version_disk()
+ */
+ public function set_version_disk() {
+
+ if (empty($this->rootdir)) {
+ return;
+ }
+
+ $versionfile = $this->rootdir . '/version.php';
+
+ if (is_readable($versionfile)) {
+ include($versionfile);
+ if (isset($module->version)) {
+ $this->versiondisk = $module->version;
+ }
+ }
+ }
+
+ /**
+ * @see plugintype_interface::set_version_db()
+ */
+ public function set_version_db() {
+ global $DB;
+
+ $modulesinfo = self::get_modules_info();
+ if (isset($modulesinfo[$this->name]->version)) {
+ $this->versiondb = $modulesinfo[$this->name]->version;
+ }
+ }
+
+ /**
+ * @see plugintype_interface::set_version_requires()
+ */
+ public function set_version_requires() {
+
+ if (empty($this->rootdir)) {
+ return;
+ }
+
+ $versionfile = $this->rootdir . '/version.php';
+
+ if (is_readable($versionfile)) {
+ include($versionfile);
+ if (isset($module->requires)) {
+ $this->versionrequires = $module->requires;
+ }
+ }
+ }
+
+ /**
+ * @see plugintype_interface::is_enabled()
+ */
+ public function is_enabled() {
+
+ $modulesinfo = self::get_modules_info();
+ if (isset($modulesinfo[$this->name]->visible)) {
+ if ($modulesinfo[$this->name]->visible) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return parent::is_enabled();