Search moodle.org's
Developer Documentation


  • Bug fixes for general core bugs in 2.8.x ended 9 November 2015 (12 months).
  • Bug fixes for security issues in 2.8.x ended 9 May 2016 (18 months).
  • minimum PHP 5.4.4 (always use latest PHP 5.4.x or 5.5.x on Windows - http://windows.php.net/download/), PHP 7 is NOT supported
  • Differences Between: [Versions 28 and 29] [Versions 28 and 30] [Versions 28 and 31] [Versions 28 and 32] [Versions 28 and 33] [Versions 28 and 34] [Versions 28 and 35] [Versions 28 and 36] [Versions 28 and 37]

       1  <?php
       2  // This file is part of Moodle - http://moodle.org/
       3  //
       4  // Moodle is free software: you can redistribute it and/or modify
       5  // it under the terms of the GNU General Public License as published by
       6  // the Free Software Foundation, either version 3 of the License, or
       7  // (at your option) any later version.
       8  //
       9  // Moodle is distributed in the hope that it will be useful,
      10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12  // GNU General Public License for more details.
      13  //
      14  // You should have received a copy of the GNU General Public License
      15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
      16  
      17  /**
      18   * Cache helper class
      19   *
      20   * This file is part of Moodle's cache API, affectionately called MUC.
      21   * It contains the components that are requried in order to use caching.
      22   *
      23   * @package    core
      24   * @category   cache
      25   * @copyright  2012 Sam Hemelryk
      26   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      27   */
      28  
      29  defined('MOODLE_INTERNAL') || die();
      30  
      31  /**
      32   * The cache helper class.
      33   *
      34   * The cache helper class provides common functionality to the cache API and is useful to developers within to interact with
      35   * the cache API in a general way.
      36   *
      37   * @package    core
      38   * @category   cache
      39   * @copyright  2012 Sam Hemelryk
      40   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      41   */
      42  class cache_helper {
      43  
      44      /**
      45       * Statistics gathered by the cache API during its operation will be used here.
      46       * @static
      47       * @var array
      48       */
      49      protected static $stats = array();
      50  
      51      /**
      52       * The instance of the cache helper.
      53       * @var cache_helper
      54       */
      55      protected static $instance;
      56  
      57      /**
      58       * The site identifier used by the cache.
      59       * Set the first time get_site_identifier is called.
      60       * @var string
      61       */
      62      protected static $siteidentifier = null;
      63  
      64      /**
      65       * Returns true if the cache API can be initialised before Moodle has finished initialising itself.
      66       *
      67       * This check is essential when trying to cache the likes of configuration information. It checks to make sure that the cache
      68       * configuration file has been created which allows use to set up caching when ever is required.
      69       *
      70       * @return bool
      71       */
      72      public static function ready_for_early_init() {
      73          return cache_config::config_file_exists();
      74      }
      75  
      76      /**
      77       * Returns an instance of the cache_helper.
      78       *
      79       * This is designed for internal use only and acts as a static store.
      80       * @staticvar null $instance
      81       * @return cache_helper
      82       */
      83      protected static function instance() {
      84          if (is_null(self::$instance)) {
      85              self::$instance = new cache_helper();
      86          }
      87          return self::$instance;
      88      }
      89  
      90      /**
      91       * Constructs an instance of the cache_helper class. Again for internal use only.
      92       */
      93      protected function __construct() {
      94          // Nothing to do here, just making sure you can't get an instance of this.
      95      }
      96  
      97      /**
      98       * Used as a data store for initialised definitions.
      99       * @var array
     100       */
     101      protected $definitions = array();
     102  
     103      /**
     104       * Used as a data store for initialised cache stores
     105       * We use this because we want to avoid establishing multiple instances of a single store.
     106       * @var array
     107       */
     108      protected $stores = array();
     109  
     110      /**
     111       * Returns the class for use as a cache loader for the given mode.
     112       *
     113       * @param int $mode One of cache_store::MODE_
     114       * @return string
     115       * @throws coding_exception
     116       */
     117      public static function get_class_for_mode($mode) {
     118          switch ($mode) {
     119              case cache_store::MODE_APPLICATION :
     120                  return 'cache_application';
     121              case cache_store::MODE_REQUEST :
     122                  return 'cache_request';
     123              case cache_store::MODE_SESSION :
     124                  return 'cache_session';
     125          }
     126          throw new coding_exception('Unknown cache mode passed. Must be one of cache_store::MODE_*');
     127      }
     128  
     129      /**
     130       * Returns the cache stores to be used with the given definition.
     131       * @param cache_definition $definition
     132       * @return array
     133       */
     134      public static function get_cache_stores(cache_definition $definition) {
     135          $instance = cache_config::instance();
     136          $stores = $instance->get_stores_for_definition($definition);
     137          $stores = self::initialise_cachestore_instances($stores, $definition);
     138          return $stores;
     139      }
     140  
     141      /**
     142       * Internal function for initialising an array of stores against a given cache definition.
     143       *
     144       * @param array $stores
     145       * @param cache_definition $definition
     146       * @return cache_store[]
     147       */
     148      protected static function initialise_cachestore_instances(array $stores, cache_definition $definition) {
     149          $return = array();
     150          $factory = cache_factory::instance();
     151          foreach ($stores as $name => $details) {
     152              $store = $factory->create_store_from_config($name, $details, $definition);
     153              if ($store !== false) {
     154                  $return[] = $store;
     155              }
     156          }
     157          return $return;
     158      }
     159  
     160      /**
     161       * Returns a cache_lock instance suitable for use with the store.
     162       *
     163       * @param cache_store $store
     164       * @return cache_lock_interface
     165       */
     166      public static function get_cachelock_for_store(cache_store $store) {
     167          $instance = cache_config::instance();
     168          $lockconf = $instance->get_lock_for_store($store->my_name());
     169          $factory = cache_factory::instance();
     170          return $factory->create_lock_instance($lockconf);
     171      }
     172  
     173      /**
     174       * Returns an array of plugins without using core methods.
     175       *
     176       * This function explicitly does NOT use core functions as it will in some circumstances be called before Moodle has
     177       * finished initialising. This happens when loading configuration for instance.
     178       *
     179       * @return string
     180       */
     181      public static function early_get_cache_plugins() {
     182          global $CFG;
     183          $result = array();
     184          $ignored = array('CVS', '_vti_cnf', 'simpletest', 'db', 'yui', 'tests');
     185          $fulldir = $CFG->dirroot.'/cache/stores';
     186          $items = new DirectoryIterator($fulldir);
     187          foreach ($items as $item) {
     188              if ($item->isDot() or !$item->isDir()) {
     189                  continue;
     190              }
     191              $pluginname = $item->getFilename();
     192              if (in_array($pluginname, $ignored)) {
     193                  continue;
     194              }
     195              if (!is_valid_plugin_name($pluginname)) {
     196                  // Better ignore plugins with problematic names here.
     197                  continue;
     198              }
     199              $result[$pluginname] = $fulldir.'/'.$pluginname;
     200              unset($item);
     201          }
     202          unset($items);
     203          return $result;
     204      }
     205  
     206      /**
     207       * Invalidates a given set of keys from a given definition.
     208       *
     209       * @todo Invalidating by definition should also add to the event cache so that sessions can be invalidated (when required).
     210       *
     211       * @param string $component
     212       * @param string $area
     213       * @param array $identifiers
     214       * @param array $keys
     215       * @return boolean
     216       */
     217      public static function invalidate_by_definition($component, $area, array $identifiers = array(), $keys = array()) {
     218          $cache = cache::make($component, $area, $identifiers);
     219          if (is_array($keys)) {
     220              $cache->delete_many($keys);
     221          } else if (is_scalar($keys)) {
     222              $cache->delete($keys);
     223          } else {
     224              throw new coding_exception('cache_helper::invalidate_by_definition only accepts $keys as array, or scalar.');
     225          }
     226          return true;
     227      }
     228  
     229      /**
     230       * Invalidates a given set of keys by means of an event.
     231       *
     232       * @todo add support for identifiers to be supplied and utilised.
     233       *
     234       * @param string $event
     235       * @param array $keys
     236       */
     237      public static function invalidate_by_event($event, array $keys) {
     238          $instance = cache_config::instance();
     239          $invalidationeventset = false;
     240          $factory = cache_factory::instance();
     241          $inuse = $factory->get_caches_in_use();
     242          foreach ($instance->get_definitions() as $name => $definitionarr) {
     243              $definition = cache_definition::load($name, $definitionarr);
     244              if ($definition->invalidates_on_event($event)) {
     245                  // First up check if there is a cache loader for this definition already.
     246                  // If there is we need to invalidate the keys from there.
     247                  $definitionkey = $definition->get_component().'/'.$definition->get_area();
     248                  if (isset($inuse[$definitionkey])) {
     249                      $inuse[$definitionkey]->delete_many($keys);
     250                  }
     251  
     252                  // We should only log events for application and session caches.
     253                  // Request caches shouldn't have events as all data is lost at the end of the request.
     254                  // Events should only be logged once of course and likely several definitions are watching so we
     255                  // track its logging with $invalidationeventset.
     256                  $logevent = ($invalidationeventset === false && $definition->get_mode() !== cache_store::MODE_REQUEST);
     257  
     258                  if ($logevent) {
     259                      // Get the event invalidation cache.
     260                      $cache = cache::make('core', 'eventinvalidation');
     261                      // Get any existing invalidated keys for this cache.
     262                      $data = $cache->get($event);
     263                      if ($data === false) {
     264                          // There are none.
     265                          $data = array();
     266                      }
     267                      // Add our keys to them with the current cache timestamp.
     268                      foreach ($keys as $key) {
     269                          $data[$key] = cache::now();
     270                      }
     271                      // Set that data back to the cache.
     272                      $cache->set($event, $data);
     273                      // This only needs to occur once.
     274                      $invalidationeventset = true;
     275                  }
     276              }
     277          }
     278      }
     279  
     280      /**
     281       * Purges the cache for a specific definition.
     282       *
     283       * @param string $component
     284       * @param string $area
     285       * @param array $identifiers
     286       * @return bool
     287       */
     288      public static function purge_by_definition($component, $area, array $identifiers = array()) {
     289          // Create the cache.
     290          $cache = cache::make($component, $area, $identifiers);
     291          // Initialise, in case of a store.
     292          if ($cache instanceof cache_store) {
     293              $factory = cache_factory::instance();
     294              $definition = $factory->create_definition($component, $area, null);
     295              $definition->set_identifiers($identifiers);
     296              $cache->initialise($definition);
     297          }
     298          // Purge baby, purge.
     299          $cache->purge();
     300          return true;
     301      }
     302  
     303      /**
     304       * Purges a cache of all information on a given event.
     305       *
     306       * @param string $event
     307       */
     308      public static function purge_by_event($event) {
     309          $instance = cache_config::instance();
     310          $invalidationeventset = false;
     311          $factory = cache_factory::instance();
     312          $inuse = $factory->get_caches_in_use();
     313          foreach ($instance->get_definitions() as $name => $definitionarr) {
     314              $definition = cache_definition::load($name, $definitionarr);
     315              if ($definition->invalidates_on_event($event)) {
     316                  // First up check if there is a cache loader for this definition already.
     317                  // If there is we need to invalidate the keys from there.
     318                  $definitionkey = $definition->get_component().'/'.$definition->get_area();
     319                  if (isset($inuse[$definitionkey])) {
     320                      $inuse[$definitionkey]->purge();
     321                  } else {
     322                      cache::make($definition->get_component(), $definition->get_area())->purge();
     323                  }
     324  
     325                  // We should only log events for application and session caches.
     326                  // Request caches shouldn't have events as all data is lost at the end of the request.
     327                  // Events should only be logged once of course and likely several definitions are watching so we
     328                  // track its logging with $invalidationeventset.
     329                  $logevent = ($invalidationeventset === false && $definition->get_mode() !== cache_store::MODE_REQUEST);
     330  
     331                  // We need to flag the event in the "Event invalidation" cache if it hasn't already happened.
     332                  if ($logevent && $invalidationeventset === false) {
     333                      // Get the event invalidation cache.
     334                      $cache = cache::make('core', 'eventinvalidation');
     335                      // Create a key to invalidate all.
     336                      $data = array(
     337                          'purged' => cache::now()
     338                      );
     339                      // Set that data back to the cache.
     340                      $cache->set($event, $data);
     341                      // This only needs to occur once.
     342                      $invalidationeventset = true;
     343                  }
     344              }
     345          }
     346      }
     347  
     348      /**
     349       * Ensure that the stats array is ready to collect information for the given store and definition.
     350       * @param string $store
     351       * @param string $definition
     352       */
     353      protected static function ensure_ready_for_stats($store, $definition) {
     354          // This function is performance-sensitive, so exit as quickly as possible
     355          // if we do not need to do anything.
     356          if (isset(self::$stats[$definition][$store])) {
     357              return;
     358          }
     359          if (!array_key_exists($definition, self::$stats)) {
     360              self::$stats[$definition] = array(
     361                  $store => array(
     362                      'hits' => 0,
     363                      'misses' => 0,
     364                      'sets' => 0,
     365                  )
     366              );
     367          } else if (!array_key_exists($store, self::$stats[$definition])) {
     368              self::$stats[$definition][$store] = array(
     369                  'hits' => 0,
     370                  'misses' => 0,
     371                  'sets' => 0,
     372              );
     373          }
     374      }
     375  
     376      /**
     377       * Record a cache hit in the stats for the given store and definition.
     378       *
     379       * @internal
     380       * @param string $store
     381       * @param string $definition
     382       * @param int $hits The number of hits to record (by default 1)
     383       */
     384      public static function record_cache_hit($store, $definition, $hits = 1) {
     385          self::ensure_ready_for_stats($store, $definition);
     386          self::$stats[$definition][$store]['hits'] += $hits;
     387      }
     388  
     389      /**
     390       * Record a cache miss in the stats for the given store and definition.
     391       *
     392       * @internal
     393       * @param string $store
     394       * @param string $definition
     395       * @param int $misses The number of misses to record (by default 1)
     396       */
     397      public static function record_cache_miss($store, $definition, $misses = 1) {
     398          self::ensure_ready_for_stats($store, $definition);
     399          self::$stats[$definition][$store]['misses'] += $misses;
     400      }
     401  
     402      /**
     403       * Record a cache set in the stats for the given store and definition.
     404       *
     405       * @internal
     406       * @param string $store
     407       * @param string $definition
     408       * @param int $sets The number of sets to record (by default 1)
     409       */
     410      public static function record_cache_set($store, $definition, $sets = 1) {
     411          self::ensure_ready_for_stats($store, $definition);
     412          self::$stats[$definition][$store]['sets'] += $sets;
     413      }
     414  
     415      /**
     416       * Return the stats collected so far.
     417       * @return array
     418       */
     419      public static function get_stats() {
     420          return self::$stats;
     421      }
     422  
     423      /**
     424       * Purge all of the cache stores of all of their data.
     425       *
     426       * Think twice before calling this method. It will purge **ALL** caches regardless of whether they have been used recently or
     427       * anything. This will involve full setup of the cache + the purge operation. On a site using caching heavily this WILL be
     428       * painful.
     429       *
     430       * @param bool $usewriter If set to true the cache_config_writer class is used. This class is special as it avoids
     431       *      it is still usable when caches have been disabled.
     432       *      Please use this option only if you really must. It's purpose is to allow the cache to be purged when it would be
     433       *      otherwise impossible.
     434       */
     435      public static function purge_all($usewriter = false) {
     436          $factory = cache_factory::instance();
     437          $config = $factory->create_config_instance($usewriter);
     438          foreach ($config->get_all_stores() as $store) {
     439              self::purge_store($store['name'], $config);
     440          }
     441      }
     442  
     443      /**
     444       * Purges a store given its name.
     445       *
     446       * @param string $storename
     447       * @param cache_config $config
     448       * @return bool
     449       */
     450      public static function purge_store($storename, cache_config $config = null) {
     451          if ($config === null) {
     452              $config = cache_config::instance();
     453          }
     454  
     455          $stores = $config->get_all_stores();
     456          if (!array_key_exists($storename, $stores)) {
     457              // The store does not exist.
     458              return false;
     459          }
     460  
     461          $store = $stores[$storename];
     462          $class = $store['class'];
     463  
     464          // Found the store: is it ready?
     465          /* @var cache_store $instance */
     466          $instance = new $class($store['name'], $store['configuration']);
     467          // We check are_requirements_met although we expect is_ready is going to check as well.
     468          if (!$instance::are_requirements_met() || !$instance->is_ready()) {
     469              unset($instance);
     470              return false;
     471          }
     472  
     473          foreach ($config->get_definitions_by_store($storename) as $id => $definition) {
     474              $definition = cache_definition::load($id, $definition);
     475              $definitioninstance = clone($instance);
     476              $definitioninstance->initialise($definition);
     477              $definitioninstance->purge();
     478              unset($definitioninstance);
     479          }
     480  
     481          return true;
     482      }
     483  
     484      /**
     485       * Purges all of the stores used by a definition.
     486       *
     487       * Unlike cache_helper::purge_by_definition this purges all of the data from the stores not
     488       * just the data relating to the definition.
     489       * This function is useful when you must purge a definition that requires setup but you don't
     490       * want to set it up.
     491       *
     492       * @param string $component
     493       * @param string $area
     494       */
     495      public static function purge_stores_used_by_definition($component, $area) {
     496          $factory = cache_factory::instance();
     497          $config = $factory->create_config_instance();
     498          $definition = $factory->create_definition($component, $area);
     499          $stores = $config->get_stores_for_definition($definition);
     500          foreach ($stores as $store) {
     501              self::purge_store($store['name']);
     502          }
     503      }
     504  
     505      /**
     506       * Returns the translated name of the definition.
     507       *
     508       * @param cache_definition $definition
     509       * @return lang_string
     510       */
     511      public static function get_definition_name($definition) {
     512          if ($definition instanceof cache_definition) {
     513              return $definition->get_name();
     514          }
     515          $identifier = 'cachedef_'.clean_param($definition['area'], PARAM_STRINGID);
     516          $component = $definition['component'];
     517          if ($component === 'core') {
     518              $component = 'cache';
     519          }
     520          return new lang_string($identifier, $component);
     521      }
     522  
     523      /**
     524       * Hashes a descriptive key to make it shorter and still unique.
     525       * @param string|int $key
     526       * @param cache_definition $definition
     527       * @return string
     528       */
     529      public static function hash_key($key, cache_definition $definition) {
     530          if ($definition->uses_simple_keys()) {
     531              if (debugging() && preg_match('#[^a-zA-Z0-9_]#', $key)) {
     532                  throw new coding_exception('Cache definition '.$definition->get_id().' requires simple keys. Invalid key provided.', $key);
     533              }
     534              // We put the key first so that we can be sure the start of the key changes.
     535              return (string)$key . '-' . $definition->generate_single_key_prefix();
     536          }
     537          $key = $definition->generate_single_key_prefix() . '-' . $key;
     538          return sha1($key);
     539      }
     540  
     541      /**
     542       * Finds all definitions and updates them within the cache config file.
     543       *
     544       * @param bool $coreonly If set to true only core definitions will be updated.
     545       */
     546      public static function update_definitions($coreonly = false) {
     547          global $CFG;
     548          // Include locallib.
     549          require_once($CFG->dirroot.'/cache/locallib.php');
     550          // First update definitions
     551          cache_config_writer::update_definitions($coreonly);
     552          // Second reset anything we have already initialised to ensure we're all up to date.
     553          cache_factory::reset();
     554      }
     555  
     556      /**
     557       * Update the site identifier stored by the cache API.
     558       *
     559       * @param string $siteidentifier
     560       * @return string The new site identifier.
     561       */
     562      public static function update_site_identifier($siteidentifier) {
     563          global $CFG;
     564          // Include locallib.
     565          require_once($CFG->dirroot.'/cache/locallib.php');
     566          $factory = cache_factory::instance();
     567          $factory->updating_started();
     568          $config = $factory->create_config_instance(true);
     569          $siteidentifier = $config->update_site_identifier($siteidentifier);
     570          $factory->updating_finished();
     571          cache_factory::reset();
     572          return $siteidentifier;
     573      }
     574  
     575      /**
     576       * Returns the site identifier.
     577       *
     578       * @return string
     579       */
     580      public static function get_site_identifier() {
     581          global $CFG;
     582          if (!is_null(self::$siteidentifier)) {
     583              return self::$siteidentifier;
     584          }
     585          // If site identifier hasn't been collected yet attempt to get it from the cache config.
     586          $factory = cache_factory::instance();
     587          // If the factory is initialising then we don't want to try to get it from the config or we risk
     588          // causing the cache to enter an infinite initialisation loop.
     589          if (!$factory->is_initialising()) {
     590              $config = $factory->create_config_instance();
     591              self::$siteidentifier = $config->get_site_identifier();
     592          }
     593          if (is_null(self::$siteidentifier)) {
     594              // If the site identifier is still null then config isn't aware of it yet.
     595              // We'll see if the CFG is loaded, and if not we will just use unknown.
     596              // It's very important here that we don't use get_config. We don't want an endless cache loop!
     597              if (!empty($CFG->siteidentifier)) {
     598                  self::$siteidentifier = self::update_site_identifier($CFG->siteidentifier);
     599              } else {
     600                  // It's not being recorded in MUC's config and the config data hasn't been loaded yet.
     601                  // Likely we are initialising.
     602                  return 'unknown';
     603              }
     604          }
     605          return self::$siteidentifier;
     606      }
     607  
     608      /**
     609       * Returns the site version.
     610       *
     611       * @return string
     612       */
     613      public static function get_site_version() {
     614          global $CFG;
     615          return (string)$CFG->version;
     616      }
     617  
     618      /**
     619       * Runs cron routines for MUC.
     620       */
     621      public static function cron() {
     622          self::clean_old_session_data(true);
     623      }
     624  
     625      /**
     626       * Cleans old session data from cache stores used for session based definitions.
     627       *
     628       * @param bool $output If set to true output will be given.
     629       */
     630      public static function clean_old_session_data($output = false) {
     631          global $CFG;
     632          if ($output) {
     633              mtrace('Cleaning up stale session data from cache stores.');
     634          }
     635          $factory = cache_factory::instance();
     636          $config = $factory->create_config_instance();
     637          $definitions = $config->get_definitions();
     638          $purgetime = time() - $CFG->sessiontimeout;
     639          foreach ($definitions as $definitionarray) {
     640              // We are only interested in session caches.
     641              if (!($definitionarray['mode'] & cache_store::MODE_SESSION)) {
     642                  continue;
     643              }
     644              $definition = $factory->create_definition($definitionarray['component'], $definitionarray['area']);
     645              $stores = $config->get_stores_for_definition($definition);
     646              // Turn them into store instances.
     647              $stores = self::initialise_cachestore_instances($stores, $definition);
     648              // Initialise all of the stores used for that definition.
     649              foreach ($stores as $store) {
     650                  // If the store doesn't support searching we can skip it.
     651                  if (!($store instanceof cache_is_searchable)) {
     652                      debugging('Cache stores used for session definitions should ideally be searchable.', DEBUG_DEVELOPER);
     653                      continue;
     654                  }
     655                  // Get all of the keys.
     656                  $keys = $store->find_by_prefix(cache_session::KEY_PREFIX);
     657                  $todelete = array();
     658                  foreach ($store->get_many($keys) as $key => $value) {
     659                      if (strpos($key, cache_session::KEY_PREFIX) !== 0 || !is_array($value) || !isset($value['lastaccess'])) {
     660                          continue;
     661                      }
     662                      if ((int)$value['lastaccess'] < $purgetime || true) {
     663                          $todelete[] = $key;
     664                      }
     665                  }
     666                  if (count($todelete)) {
     667                      $outcome = (int)$store->delete_many($todelete);
     668                      if ($output) {
     669                          $strdef = s($definition->get_id());
     670                          $strstore = s($store->my_name());
     671                          mtrace("- Removed {$outcome} old {$strdef} sessions from the '{$strstore}' cache store.");
     672                      }
     673                  }
     674              }
     675          }
     676      }
     677  
     678      /**
     679       * Returns an array of stores that would meet the requirements for every definition.
     680       *
     681       * These stores would be 100% suitable to map as defaults for cache modes.
     682       *
     683       * @return array[] An array of stores, keys are the store names.
     684       */
     685      public static function get_stores_suitable_for_mode_default() {
     686          $factory = cache_factory::instance();
     687          $config = $factory->create_config_instance();
     688          $requirements = 0;
     689          foreach ($config->get_definitions() as $definition) {
     690              $definition = cache_definition::load($definition['component'].'/'.$definition['area'], $definition);
     691              $requirements = $requirements | $definition->get_requirements_bin();
     692          }
     693          $stores = array();
     694          foreach ($config->get_all_stores() as $name => $store) {
     695              if (!empty($store['features']) && ($store['features'] & $requirements)) {
     696                  $stores[$name] = $store;
     697              }
     698          }
     699          return $stores;
     700      }
     701  
     702      /**
     703       * Returns stores suitable for use with a given definition.
     704       *
     705       * @param cache_definition $definition
     706       * @return cache_store[]
     707       */
     708      public static function get_stores_suitable_for_definition(cache_definition $definition) {
     709          $factory = cache_factory::instance();
     710          $stores = array();
     711          if ($factory->is_initialising() || $factory->stores_disabled()) {
     712              // No suitable stores here.
     713              return $stores;
     714          } else {
     715              $stores = self::get_cache_stores($definition);
     716              // If mappingsonly is set, having 0 stores is ok.
     717              if ((count($stores) === 0) && (!$definition->is_for_mappings_only())) {
     718                  // No suitable stores we found for the definition. We need to come up with a sensible default.
     719                  // If this has happened we can be sure that the user has mapped custom stores to either the
     720                  // mode of the definition. The first alternative to try is the system default for the mode.
     721                  // e.g. the default file store instance for application definitions.
     722                  $config = $factory->create_config_instance();
     723                  foreach ($config->get_stores($definition->get_mode()) as $name => $details) {
     724                      if (!empty($details['default'])) {
     725                          $stores[] = $factory->create_store_from_config($name, $details, $definition);
     726                          break;
     727                      }
     728                  }
     729              }
     730          }
     731          return $stores;
     732      }
     733  
     734      /**
     735       * Returns an array of warnings from the cache API.
     736       *
     737       * The warning returned here are for things like conflicting store instance configurations etc.
     738       * These get shown on the admin notifications page for example.
     739       *
     740       * @param array|null $stores An array of stores to get warnings for, or null for all.
     741       * @return string[]
     742       */
     743      public static function warnings(array $stores = null) {
     744          global $CFG;
     745          if ($stores === null) {
     746              require_once($CFG->dirroot.'/cache/locallib.php');
     747              $stores = cache_administration_helper::get_store_instance_summaries();
     748          }
     749          $warnings = array();
     750          foreach ($stores as $store) {
     751              if (!empty($store['warnings'])) {
     752                  $warnings = array_merge($warnings, $store['warnings']);
     753              }
     754          }
     755          return $warnings;
     756      }
     757  }
    

    Search This Site: