diff --git a/admin/blocks.php b/admin/blocks.php index 5b5c3a17be9..f2017b912a1 100644 --- a/admin/blocks.php +++ b/admin/blocks.php @@ -30,6 +30,9 @@ $strprotect = get_string('blockprotect', 'admin'); $strunprotect = get_string('blockunprotect', 'admin'); + // Purge all caches related to blocks administration. + cache::make('core', 'plugininfo_block')->purge(); + /// If data submitted, then process and store. if (!empty($hide) && confirm_sesskey()) { diff --git a/admin/filters.php b/admin/filters.php index 0dbb4150d59..6c585046ab9 100644 --- a/admin/filters.php +++ b/admin/filters.php @@ -44,6 +44,9 @@ $returnurl = "$CFG->wwwroot/$CFG->admin/filters.php"; admin_externalpage_setup('managefilters'); + // Purge all caches related to filter administration. + cache::make('core', 'plugininfo_filter')->purge(); + $filters = filter_get_global_states(); // In case any new filters have been installed, but not put in the table yet. diff --git a/admin/modules.php b/admin/modules.php index 3ad0a72cc6e..33d2fbbff4e 100644 --- a/admin/modules.php +++ b/admin/modules.php @@ -29,6 +29,9 @@ $stractivitymodule = get_string("activitymodule"); $strshowmodulecourse = get_string('showmodulecourse'); + // Purge all caches related to activity modules administration. + cache::make('core', 'plugininfo_mod')->purge(); + /// If data submitted, then process and store. if (!empty($hide) and confirm_sesskey()) { diff --git a/admin/portfolio.php b/admin/portfolio.php index 16aa66183ed..1811f5f774f 100644 --- a/admin/portfolio.php +++ b/admin/portfolio.php @@ -43,6 +43,9 @@ $configstr = get_string('manageportfolios', 'portfolio'); $return = true; // direct back to the main page +// Purge all caches related to portfolio administration. +cache::make('core', 'plugininfo_portfolio')->purge(); + /** * Helper function that generates a moodle_url object * relevant to the portfolio diff --git a/admin/repository.php b/admin/repository.php index a4cdd220b92..26f1ba46ced 100644 --- a/admin/repository.php +++ b/admin/repository.php @@ -61,6 +61,9 @@ if (!empty($action)) { require_sesskey(); } +// Purge all caches related to repositories administration. +cache::make('core', 'plugininfo_repository')->purge(); + /** * Helper function that generates a moodle_url object * relevant to the repository diff --git a/filter/manage.php b/filter/manage.php index 89ba5ca8ffc..0bea014ba08 100644 --- a/filter/manage.php +++ b/filter/manage.php @@ -36,6 +36,9 @@ require_login($course, false, $cm); require_capability('moodle/filter:manage', $context); $PAGE->set_context($context); +// Purge all caches related to filter administration. +cache::make('core', 'plugininfo_filter')->purge(); + $args = array('contextid'=>$contextid); $baseurl = new moodle_url('/filter/manage.php', $args); if (!empty($forfilter)) { diff --git a/lang/en/cache.php b/lang/en/cache.php index dfd28f6e92e..aec3fe82e2a 100644 --- a/lang/en/cache.php +++ b/lang/en/cache.php @@ -41,6 +41,14 @@ $string['cachedef_eventinvalidation'] = 'Event invalidation'; $string['cachedef_groupdata'] = 'Course group information'; $string['cachedef_htmlpurifier'] = 'HTML Purifier - cleaned content'; $string['cachedef_locking'] = 'Locking'; +$string['cachedef_plugininfo_base'] = 'Plugin info - base'; +$string['cachedef_plugininfo_block'] = 'Plugin info - blocks'; +$string['cachedef_plugininfo_filter'] = 'Plugin info - filters'; +$string['cachedef_plugininfo_mod'] = 'Plugin info - activity modules'; +$string['cachedef_plugininfo_portfolio'] = 'Plugin info - portfolios'; +$string['cachedef_plugininfo_repository'] = 'Plugin info - repositories'; +$string['cachedef_pluginlist'] = 'Plugin list'; +$string['cachedef_plugintypes'] = 'Plugin types'; $string['cachedef_questiondata'] = 'Question definitions'; $string['cachedef_string'] = 'Language string cache'; $string['cachedef_yuimodules'] = 'YUI Module definitions'; diff --git a/lib/db/caches.php b/lib/db/caches.php index cd138e6eadc..77e46788ef9 100644 --- a/lib/db/caches.php +++ b/lib/db/caches.php @@ -105,7 +105,8 @@ $definitions = array( 'persistent' => true, // Likely there will be a couple of calls to this. 'persistmaxsize' => 2, // The original cache used 1, we've increased that to two. ), - // Used to cache calendar subscriptions. + + // Used to cache calendar subscriptions. 'calendar_subscriptions' => array( 'mode' => cache_store::MODE_APPLICATION, 'simplekeys' => true, @@ -119,4 +120,82 @@ $definitions = array( 'mode' => cache_store::MODE_APPLICATION, 'persistent' => true, ), + + // Cache for the list of known plugin and subplugin types - {@see get_plugin_types()}. + // Contains two arrays of (string)pluginname => (string)location. The first array with + // the key 0 contains locations relative to $CFG->dirroot. The second array with the + // key 1 contains absolute paths. + 'plugintypes' => array( + 'mode' => cache_store::MODE_APPLICATION, + 'simplekeys' => true, // 0 or 1 depending on the requested location type. + 'simpledata' => true, // Array of strings. + 'persistent' => true, // Likely there will be a couple of calls to this. + 'persistmaxsize' => 2, // Both arrays should stay loaded in memory. + ), + + // Cache for the list of installed plugins - {@see get_plugin_list()}. + // The key consists of the plugin type string (e.g. mod, block, enrol etc). + // The value is an associative array of plugin name => plugin location. + 'pluginlist' => array( + 'mode' => cache_store::MODE_APPLICATION, + 'simplekeys' => true, + 'simpledata' => true, + 'persistent' => true, + 'persistentmaxsize' => 2, + ), + + // Cache used by the {@link plugininfo_base} class. + 'plugininfo_base' => array( + 'mode' => cache_store::MODE_APPLICATION, + 'simplekeys' => true, + 'simpledata' => true, + 'persistent' => true, + 'persistentmaxsize' => 2, + ), + + // Cache used by the {@link plugininfo_mod} class. + 'plugininfo_mod' => array( + 'mode' => cache_store::MODE_APPLICATION, + 'simplekeys' => true, + 'simpledata' => true, + 'persistent' => true, + 'persistentmaxsize' => 1, + ), + + // Cache used by the {@link plugininfo_block} class. + 'plugininfo_block' => array( + 'mode' => cache_store::MODE_APPLICATION, + 'simplekeys' => true, + 'simpledata' => true, + 'persistent' => true, + 'persistentmaxsize' => 1, + ), + + // Cache used by the {@link plugininfo_filter} class. + 'plugininfo_filter' => array( + 'mode' => cache_store::MODE_APPLICATION, + 'simplekeys' => true, + 'simpledata' => true, + 'persistent' => true, + 'persistentmaxsize' => 1, + ), + + // Cache used by the {@link plugininfo_repository} class. + 'plugininfo_repository' => array( + 'mode' => cache_store::MODE_APPLICATION, + 'simplekeys' => true, + 'simpledata' => true, + 'persistent' => true, + 'persistentmaxsize' => 1, + ), + + // Cache used by the {@link plugininfo_portfolio} class. + 'plugininfo_portfolio' => array( + 'mode' => cache_store::MODE_APPLICATION, + 'simplekeys' => true, + 'simpledata' => true, + 'persistent' => true, + 'persistentmaxsize' => 1, + ), + ); diff --git a/lib/moodlelib.php b/lib/moodlelib.php index 5e894392e4f..a53a8de8fb8 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -8183,10 +8183,18 @@ function get_core_subsystems() { function get_plugin_types($fullpaths=true) { global $CFG; - static $info = null; - static $fullinfo = null; + $cache = cache::make('core', 'plugintypes'); - if (!$info) { + if ($fullpaths) { + $cached = $cache->get(1); + } else { + $cached = $cache->get(0); + } + + if ($cached !== false) { + return $cached; + + } else { $info = array('qtype' => 'question/type', 'mod' => 'mod', 'auth' => 'auth', @@ -8235,9 +8243,12 @@ function get_plugin_types($fullpaths=true) { foreach ($info as $type => $dir) { $fullinfo[$type] = $CFG->dirroot.'/'.$dir; } - } - return ($fullpaths ? $fullinfo : $info); + $cache->set(0, $info); + $cache->set(1, $fullinfo); + + return ($fullpaths ? $fullinfo : $info); + } } /** @@ -8248,6 +8259,12 @@ function get_plugin_types($fullpaths=true) { function get_plugin_list($plugintype) { global $CFG; + $cache = cache::make('core', 'pluginlist'); + $cached = $cache->get($plugintype); + if ($cached !== false) { + return $cached; + } + $ignored = array('CVS', '_vti_cnf', 'simpletest', 'db', 'yui', 'tests'); if ($plugintype == 'auth') { // Historically we have had an auth plugin called 'db', so allow a special case. @@ -8281,10 +8298,12 @@ function get_plugin_list($plugintype) { } else { $types = get_plugin_types(true); if (!array_key_exists($plugintype, $types)) { + $cache->set($plugintype, array()); return array(); } $fulldir = $types[$plugintype]; if (!file_exists($fulldir)) { + $cache->set($plugintype, array()); return array(); } $fulldirs[] = $fulldir; @@ -8317,6 +8336,7 @@ function get_plugin_list($plugintype) { //TODO: implement better sorting once we migrated all plugin names to 'pluginname', ksort does not work for unicode, that is why we have to sort by the dir name, not the strings! ksort($result); + $cache->set($plugintype, $result); return $result; } @@ -9119,7 +9139,18 @@ function moodle_needs_upgrading() { return true; } - // main versio nfirst + // We have to purge plugin related caches now to be sure we have fresh data + // and new plugins can be detected. + cache::make('core', 'plugintypes')->purge(); + cache::make('core', 'pluginlist')->purge(); + cache::make('core', 'plugininfo_base')->purge(); + cache::make('core', 'plugininfo_mod')->purge(); + cache::make('core', 'plugininfo_block')->purge(); + cache::make('core', 'plugininfo_filter')->purge(); + cache::make('core', 'plugininfo_repository')->purge(); + cache::make('core', 'plugininfo_portfolio')->purge(); + + // Check the main version first. $version = null; include($CFG->dirroot.'/version.php'); // defines $version and upgrades if ($version > $CFG->version) { diff --git a/lib/pluginlib.php b/lib/pluginlib.php index 087b6cb4b6b..f5fba435048 100644 --- a/lib/pluginlib.php +++ b/lib/pluginlib.php @@ -360,8 +360,17 @@ class plugin_manager { * @return bool */ public static function is_deleted_standard_plugin($type, $name) { - static $plugins = array( - // do not add 1.9-2.2 plugin removals here + + // Example of the array structure: + // $plugins = array( + // 'block' => array('admin', 'admin_tree'), + // 'mod' => array('assignment'), + // ); + // Do not include plugins that were removed during upgrades to versions that are + // not supported as source versions for upgrade any more. For example, at MOODLE_23_STABLE + // branch, listed should be no plugins that were removed at 1.9.x - 2.1.x versions as + // Moodle 2.3 supports upgrades from 2.2.x only. + $plugins = array( 'qformat' => array('blackboard'), ); @@ -378,7 +387,7 @@ class plugin_manager { * @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( + $standard_plugins = array( 'assignment' => array( 'offline', 'online', 'upload', 'uploadsingle' @@ -2161,15 +2170,28 @@ abstract class plugininfo_base { /** * Load the data from version.php. * + * @param bool $disablecache do not attempt to obtain data from the cache * @return stdClass the object called $plugin defined in version.php */ - protected function load_version_php() { + protected function load_version_php($disablecache=false) { + + $cache = cache::make('core', 'plugininfo_base'); + + $versionsphp = $cache->get('versions_php'); + + if (!$disablecache and $versionsphp !== false and isset($versionsphp[$this->component])) { + return $versionsphp[$this->component]; + } + $versionfile = $this->full_path('version.php'); $plugin = new stdClass(); if (is_readable($versionfile)) { include($versionfile); } + $versionsphp[$this->component] = $plugin; + $cache->set('versions_php', $versionsphp); + return $plugin; } @@ -2461,30 +2483,34 @@ abstract class plugininfo_base { } /** - * Provides access to plugin versions from {config_plugins} + * Provides access to plugin versions from the {config_plugins} table * * @param string $plugin plugin name - * @param double $disablecache optional, defaults to false - * @return int|false the stored value or false if not found + * @param bool $disablecache do not attempt to obtain data from the cache + * @return int|bool 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) { + $cache = cache::make('core', 'plugininfo_base'); + + $pluginversions = $cache->get('versions_db'); + + if ($pluginversions === false or $disablecache) { try { $pluginversions = $DB->get_records_menu('config_plugins', array('name' => 'version'), 'plugin', 'plugin,value'); } catch (dml_exception $e) { // before install $pluginversions = array(); } + $cache->set('versions_db', $pluginversions); } - if (!array_key_exists($plugin, $pluginversions)) { + if (isset($pluginversions[$plugin])) { + return $pluginversions[$plugin]; + } else { return false; } - - return $pluginversions[$plugin]; } } @@ -2621,23 +2647,27 @@ class plugininfo_block extends plugininfo_base { /** * Provides access to the records in {block} table * - * @param bool $disablecache do not use internal static cache + * @param bool $disablecache do not attempt to obtain data from the 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) { + $cache = cache::make('core', 'plugininfo_block'); + + $blocktypes = $cache->get('blocktypes'); + + if ($blocktypes === false or $disablecache) { try { - $blocksinfocache = $DB->get_records('block', null, 'name', 'name,id,version,visible'); + $blocktypes = $DB->get_records('block', null, 'name', 'name,id,version,visible'); } catch (dml_exception $e) { // before install - $blocksinfocache = array(); + $blocktypes = array(); } + $cache->set('blocktypes', $blocktypes); } - return $blocksinfocache; + return $blocktypes; } } @@ -2705,13 +2735,6 @@ class plugininfo_filter extends plugininfo_base { // do nothing, the name is set in self::get_plugins() } - /** - * @see load_version_php() - */ - protected function load_version_php() { - return parent::load_version_php(); - } - public function is_enabled() { $globalstates = self::get_global_states(); @@ -2761,35 +2784,42 @@ class plugininfo_filter extends plugininfo_base { * * The legacy filter name is available as ->legacyname property. * - * @param bool $disablecache + * @param bool $disablecache do not attempt to obtain data from the cache * @return array */ protected static function get_global_states($disablecache=false) { global $DB; - static $globalstatescache = null; - if ($disablecache or is_null($globalstatescache)) { - $globalstatescache = array(); + $cache = cache::make('core', 'plugininfo_filter'); + + $globalstates = $cache->get('globalstates'); + + if ($globalstates === false or $disablecache) { if (!$DB->get_manager()->table_exists('filter_active')) { // Not installed yet. - return $globalstatescache; + $cache->set('globalstates', array()); + return array(); } + $globalstates = array(); + foreach (filter_get_global_states() as $name => $info) { if (strpos($name, '/') !== false) { // Skip existing before upgrade to new names. continue; } - $filterinfo = new stdClass(); - $filterinfo->active = $info->active; - $filterinfo->sortorder = $info->sortorder; - $globalstatescache[$name] = $filterinfo; + $filterinfo = new stdClass(); + $filterinfo->active = $info->active; + $filterinfo->sortorder = $info->sortorder; + $globalstates[$name] = $filterinfo; } + + $cache->set('globalstates', $globalstates); } - return $globalstatescache; + return $globalstates; } } @@ -2852,9 +2882,20 @@ class plugininfo_mod extends plugininfo_base { /** * Load the data from version.php. + * + * @param bool $disablecache do not attempt to obtain data from the cache * @return object the data object defined in version.php. */ - protected function load_version_php() { + protected function load_version_php($disablecache=false) { + + $cache = cache::make('core', 'plugininfo_base'); + + $versionsphp = $cache->get('versions_php'); + + if (!$disablecache and $versionsphp !== false and isset($versionsphp[$this->component])) { + return $versionsphp[$this->component]; + } + $versionfile = $this->full_path('version.php'); $module = new stdClass(); @@ -2865,6 +2906,9 @@ class plugininfo_mod extends plugininfo_base { if (!isset($module->version) and isset($plugin->version)) { $module = $plugin; } + $versionsphp[$this->component] = $module; + $cache->set('versions_php', $versionsphp); + return $module; } @@ -2925,23 +2969,27 @@ class plugininfo_mod extends plugininfo_base { /** * Provides access to the records in {modules} table * - * @param bool $disablecache do not use internal static cache + * @param bool $disablecache do not attempt to obtain data from the cache * @return array array of stdClasses */ protected static function get_modules_info($disablecache=false) { global $DB; - static $modulesinfocache = null; - if (is_null($modulesinfocache) or $disablecache) { + $cache = cache::make('core', 'plugininfo_mod'); + + $modulesinfo = $cache->get('modulesinfo'); + + if ($modulesinfo === false or $disablecache) { try { - $modulesinfocache = $DB->get_records('modules', null, 'name', 'name,id,version,visible'); + $modulesinfo = $DB->get_records('modules', null, 'name', 'name,id,version,visible'); } catch (dml_exception $e) { // before install - $modulesinfocache = array(); + $modulesinfo = array(); } + $cache->set('modulesinfo', $modulesinfo); } - return $modulesinfocache; + return $modulesinfo; } } @@ -3000,17 +3048,13 @@ class plugininfo_auth extends plugininfo_base { public function is_enabled() { global $CFG; - /** @var null|array list of enabled authentication plugins */ - static $enabled = null; if (in_array($this->name, array('nologin', 'manual'))) { // these two are always enabled and can't be disabled return null; } - if (is_null($enabled)) { - $enabled = array_flip(explode(',', $CFG->auth)); - } + $enabled = array_flip(explode(',', $CFG->auth)); return isset($enabled[$this->name]); } @@ -3052,17 +3096,13 @@ class plugininfo_enrol extends plugininfo_base { public function is_enabled() { global $CFG; - /** @var null|array list of enabled enrolment plugins */ - static $enabled = null; // We do not actually need whole enrolment classes here so we do not call // {@link enrol_get_plugins()}. Note that this may produce slightly different // results, for example if the enrolment plugin does not contain lib.php // but it is listed in $CFG->enrol_plugins_enabled - if (is_null($enabled)) { - $enabled = array_flip(explode(',', $CFG->enrol_plugins_enabled)); - } + $enabled = array_flip(explode(',', $CFG->enrol_plugins_enabled)); return isset($enabled[$this->name]); } @@ -3190,18 +3230,22 @@ class plugininfo_repository extends plugininfo_base { /** * Provides access to the records in {repository} table * - * @param bool $disablecache do not use internal static cache + * @param bool $disablecache do not attempt to obtain data from the cache * @return array array of stdClasses */ protected static function get_enabled_repositories($disablecache=false) { global $DB; - static $repositories = null; - if (is_null($repositories) or $disablecache) { - $repositories = $DB->get_records('repository', null, 'type', 'type,visible,sortorder'); + $cache = cache::make('core', 'plugininfo_repository'); + + $enabled = $cache->get('enabled'); + + if ($enabled === false or $disablecache) { + $enabled = $DB->get_records('repository', null, 'type', 'type,visible,sortorder'); + $cache->set('enabled', $enabled); } - return $repositories; + return $enabled; } } @@ -3219,30 +3263,38 @@ class plugininfo_portfolio extends plugininfo_base { } /** - * Provides access to the records in {portfolio_instance} table + * Returns list of enabled portfolio plugins * - * @param bool $disablecache do not use internal static cache - * @return array array of stdClasses + * Portfolio plugin is enabled if there is at least one record in the {portfolio_instance} + * table for it. + * + * @param bool $disablecache do not attempt to obtain data from the cache + * @return array array of stdClasses with properties plugin and visible indexed by plugin */ protected static function get_enabled_portfolios($disablecache=false) { global $DB; - static $portfolios = null; - if (is_null($portfolios) or $disablecache) { - $portfolios = array(); - $instances = $DB->get_recordset('portfolio_instance', null, 'plugin'); + $cache = cache::make('core', 'plugininfo_portfolio'); + + $enabled = $cache->get('enabled'); + + if ($enabled === false or $disablecache) { + $enabled = array(); + $instances = $DB->get_recordset('portfolio_instance', null, '', 'plugin,visible'); foreach ($instances as $instance) { - if (isset($portfolios[$instance->plugin])) { + if (isset($enabled[$instance->plugin])) { if ($instance->visible) { - $portfolios[$instance->plugin]->visible = $instance->visible; + $enabled[$instance->plugin]->visible = $instance->visible; } } else { - $portfolios[$instance->plugin] = $instance; + $enabled[$instance->plugin] = $instance; } } + $instances->close(); + $cache->set('enabled', $enabled); } - return $portfolios; + return $enabled; } } diff --git a/lib/tests/pluginlib_test.php b/lib/tests/pluginlib_test.php index 1552d9369c7..141191386a3 100644 --- a/lib/tests/pluginlib_test.php +++ b/lib/tests/pluginlib_test.php @@ -338,7 +338,7 @@ class testable_plugininfo_mod extends plugininfo_mod { $this->versiondisk = 2012030500; } - protected function load_version_php() { + protected function load_version_php($disablecache=false) { return (object)array( 'version' => 2012030500, 'requires' => 2012010100, diff --git a/user/portfolio.php b/user/portfolio.php index 653131e365d..a84935ce458 100644 --- a/user/portfolio.php +++ b/user/portfolio.php @@ -57,6 +57,9 @@ $display = true; // set this to false in the conditions to stop processing require_login($course, false); +// Purge all caches related to portfolio administration. +cache::make('core', 'plugininfo_portfolio')->purge(); + $PAGE->set_url($url); $PAGE->set_context(context_user::instance($user->id)); $PAGE->set_title("$course->fullname: $fullname: $strportfolios"); diff --git a/version.php b/version.php index 019a23733b6..3b8664c5a73 100644 --- a/version.php +++ b/version.php @@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2013031400.05; // YYYYMMDD = weekly release date of this DEV branch +$version = 2013032000.00; // YYYYMMDD = weekly release date of this DEV branch // RR = release increments - 00 in DEV branches // .XX = incremental changes