diff --git a/includes/cache.inc b/includes/cache.inc index 590592d..2ce5488 100644 --- a/includes/cache.inc +++ b/includes/cache.inc @@ -93,63 +93,27 @@ function _views_fetch_plugin_data($type = NULL, $plugin = NULL, $reset = FALSE) /** * Scan all modules for default views and rebuild the default views cache. * - * @return An associative array of all known default views. + * + * + * @return + * For PHP > 5.0, returns an ArrayObject. For PHP < 5.0 + * returns an array of all default views. */ function _views_discover_default_views($reset = FALSE) { - static $cache = NULL; - - if (!isset($cache) || $reset) { - $index = views_cache_get('views_default_views_index', TRUE); - - // Retrieve each cached default view - if (!$reset && isset($index->data) && is_array($index->data)) { - $cache = array(); - foreach ($index->data as $view_name) { - $data = views_cache_get('views_default:' . $view_name, TRUE); - if (isset($data->data) && is_object($data->data)) { - $cache[$view_name] = $data->data; - } - } - } - // If missing index, rebuild the cache - else { - views_include_default_views(); - $cache = array(); + static $php5; - foreach (module_implements('views_default_views') as $module) { - $results = call_user_func($module . "_views_default_views"); - if (!empty($results) && is_array($results)) { - foreach($results as $name => $view) { - // Only views with a sufficiently high api version are eligible. - if (!empty($view->api_version) && $view->api_version >= 2) { - // Do not cache dead handlers. - $view->destroy(); - if (!isset($cache[$name])) { - $cache[$name] = $view; - } - else { - watchdog('view', "View name '@name' is already taken", array('@name' => $name), WATCHDOG_ERROR); - } - } - } - } - } - - // Allow modules to modify default views before they are cached. - drupal_alter('views_default_views', $cache); - - // Cache the index - $index = array_keys($cache); - views_cache_set('views_default_views_index', $index, TRUE); - - // Cache each view - foreach ($cache as $name => $view) { - views_cache_set('views_default:' . $name, $view, TRUE); - } - } + // ArrayObject is not available in PHP < 5.0. Therefore this function + // supports separate code paths depending on version. + if (!isset($php5)) { + $php5 = version_compare(PHP_VERSION, '5.0', '>='); } - - return $cache; + if ($php5) { + module_load_include('inc', 'views', 'includes/cache.php5'); + } + else { + module_load_include('inc', 'views', 'includes/cache.php4'); + } + return _views_default_views_cache($reset = FALSE); } /** diff --git a/includes/cache.php4.inc b/includes/cache.php4.inc new file mode 100644 index 0000000..734650f --- /dev/null +++ b/includes/cache.php4.inc @@ -0,0 +1,60 @@ +data) && is_array($index->data)) { + $cache = array(); + foreach ($index->data as $view_name) { + $data = views_cache_get('views_default:' . $view_name, TRUE); + if (isset($data->data) && is_object($data->data)) { + $cache[$view_name] = $data->data; + } + } + } + // If missing index, rebuild the cache + else { + views_include_default_views(); + $cache = array(); + + foreach (module_implements('views_default_views') as $module) { + $results = call_user_func($module . "_views_default_views"); + if (!empty($results) && is_array($results)) { + foreach($results as $name => $view) { + // Only views with a sufficiently high api version are eligible. + if (!empty($view->api_version) && $view->api_version >= 2) { + // Do not cache dead handlers. + $view->destroy(); + if (!isset($cache[$name])) { + $cache[$name] = $view; + } + else { + watchdog('view', "View name '@name' is already taken", array('@name' => $name), WATCHDOG_ERROR); + } + } + } + } + } + + // Allow modules to modify default views before they are cached. + drupal_alter('views_default_views', $cache); + + // Cache the index + $index = array_keys($cache); + views_cache_set('views_default_views_index', $index, TRUE); + + // Cache each view + foreach ($cache as $name => $view) { + views_cache_set('views_default:' . $name, $view, TRUE); + } + } + } + + return $cache; +} diff --git a/includes/cache.php5.inc b/includes/cache.php5.inc new file mode 100644 index 0000000..c977905 --- /dev/null +++ b/includes/cache.php5.inc @@ -0,0 +1,164 @@ +setIteratorClass('ViewsDefaultIterator'); + } + return $cache; +} + +/** + * Extends ArrayObject to support lazy-loading of default views. + */ +class ViewsDefaultViewsCache extends ArrayObject { + function offsetGet($offset) { + // If the view is cached, add it to the ArrayObject storage, this will + // retain the view in memory for the rest of the request. + if ($cached = views_cache_get('views_default:' . $offset, TRUE)) { + $this->offsetSet($offset, $cached->data); + return $cached->data; + } + else { + // The default view exists, but is not cached. + return $this->resolveCacheMiss($offset); + } + } + + function resolveCacheMiss($offset) { + views_include_default_views(); + if (isset($this->index[$offset])) { + $views = views_initialize($index[$offset]); + $this->offsetSet($offset, $view); + $view_clone = clone $view; + $view_clone->destroy(); + views_cache_set('views_default:' . $offset, $view_clone, TRUE); + return $view; + } + else { + foreach (module_implements('views_default_views') as $module) { + $views = views_initialize($module); + foreach ($views as $key => $view) { + $index[$key] = $module; + if ($index == $offset) { + $this->offsetSet($offset, $view); + $return = $view; + $view_clone = clone $view; + $view_clone->destroy(); + views_cache_set('views_default:' . $offset, $view_clone, TRUE); + } + } + // If one of the views provided by the module is the one we're looking + // for, cache it then return. + if (isset($index[$offset])) { + return $return; + } + } + } + // If no view was eligible, cache FALSE. + $this->offsetSet($offset, FALSE); + views_cache_set('views_default:' . $offset, FALSE, TRUE); + return FALSE; + } +} + +class ViewsDefaultIterator extends ArrayIterator { + + /** + * The default views currently available in the class. + */ + protected $views; + + /** + * The list of modules that implement hook_views_default_views(). + */ + protected $modules; + + function __construct() { + $modules = module_implements('views_default_views'); + $views = initializeViews(current($this->modules)); + parent::__construct(array('modules' => $modules, 'views' => $views)); + } + + function current() { + return current($this->offsetGet('views')); + } + + function next() { + // If there are views from the current module not iterated yet, return the + // next one. + if ($view = next($this->offsetGet('views'))) { + return $view; + } + // If there are modules with default views available not iterated yet, return + // the first view from those views. + if ($module = next($this->offsetGet('modules'))) { + $this->offsetSet('views', views_initialize($module)); + // A module may implement the hook but not actually provide any valid + // ones. + if ($view = next($this->offsetGet('views'))) { + return $view; + } + else { + // Call the method recursively to start with the next module. + return $this->next(); + } + } + // If no view, and no module is left, just return FALSE. + return FALSE; + } + + function rewind() { + $this->offsetSet('modules', module_implements('views_default_views')); + if ($this->offsetGet('modules')) { + $this->offsetSet('views', views_initialize(current($this->offsetGet('modules')))); + } + else { + $this->offsetSet('views', array()); + } + } + + function key() { + return key($this->offsetGet('views')); + } + + function valid() { + if ($this->offsetGet('views')) { + return (bool) current($this->offsetGet('views')); + } + else { + return FALSE; + } + } +} + +/** + * Initialize views for a module. + * + * @param $module + * A module that implements hook_default_views(). + * + * @return + * An array of default views provided by the module. + */ +function views_initialize($module) { + $views = array(); + $function = $module . '_views_default_views'; + $result = $function(); + drupal_alter('views_default_views', $result); + foreach ($result as $key => $view) { + if (!empty($view->api_version) && $view->api_version >= 2) { + $views[$key] = $result; + } + } + return $views; +}