diff --git a/includes/cache.inc b/includes/cache.inc index 2323ad4..daf5e93 100644 --- a/includes/cache.inc +++ b/includes/cache.inc @@ -93,63 +93,25 @@ function _views_fetch_plugin_data($type = NULL, $plugin = NULL) { /** * 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 a class implementing ArrayAccess. For PHP < 5.0 + * returns an array of all default views. */ -function _views_discover_default_views() { - static $cache = NULL; - - if (!isset($cache)) { - $index = views_cache_get('views_default_views_index', TRUE); - - // Retrieve each cached default view - if (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(); - - 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); +function _views_discover_default_views($reset = FALSE) { + static $php5; - // 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); - } - } + // ArrayAccess 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/php5'); + } + else { + module_load_include('inc', 'views', 'includes/php4'); + } + return _views_default_views_cache(); } /** diff --git a/includes/php4.inc b/includes/php4.inc new file mode 100644 index 0000000..6da776c --- /dev/null +++ b/includes/php4.inc @@ -0,0 +1,186 @@ +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; +} + +function _views_get_all_views($reset = FALSE) { + static $views = array(); + + if (empty($views) || $reset) { + $views = array(); + + // First, get all applicable views. + views_include('view'); + $views = view::load_views(); + + // Get all default views. + $status = variable_get('views_defaults', array()); + + foreach (views_discover_default_views() as $view) { + // Determine if default view is enabled or disabled. + if (isset($status[$view->name])) { + $view->disabled = $status[$view->name]; + } + + // If overridden, also say so. + if (!empty($views[$view->name])) { + $views[$view->name]->type = t('Overridden'); + } + else { + $view->type = t('Default'); + $views[$view->name] = $view; + } + } + + } + return $views; + +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; +} + +function _views_get_all_views($reset = FALSE) { + static $views = array(); + + if (empty($views) || $reset) { + $views = array(); + + // First, get all applicable views. + views_include('view'); + $views = view::load_views(); + + // Get all default views. + $status = variable_get('views_defaults', array()); + + foreach (views_discover_default_views() as $view) { + // Determine if default view is enabled or disabled. + if (isset($status[$view->name])) { + $view->disabled = $status[$view->name]; + } + + // If overridden, also say so. + if (!empty($views[$view->name])) { + $views[$view->name]->type = t('Overridden'); + } + else { + $view->type = t('Default'); + $views[$view->name] = $view; + } + } + + } + return $views; + diff --git a/includes/php5.inc b/includes/php5.inc new file mode 100644 index 0000000..b92db70 --- /dev/null +++ b/includes/php5.inc @@ -0,0 +1,207 @@ + module pairs to locate views quicker when requested. + */ + protected $index = array(); + + function __construct() { + // To improve lookup times for individual views, maintain an index of which + // module provides each view. + if ($cached = views_cache_get('views_default_index')) { + $this->index = $cached->data; + } + } + + function offsetGet($offset) { + // If the view is cached, add it to $this->storage, this will + // retain the view in memory for the rest of the request. + if ($cached = views_cache_get('views_default:' . $offset, TRUE)) { + $this->storage[$offset] = $cached->data; + return $cached->data; + } + else { + // The default view exists, but is not cached. + return $this->resolveCacheMiss($offset); + } + } + + function offsetExists($offset) { + return (bool) $this->offsetGet($offset); + } + + function offsetSet($offset, $value) { + $this->storage[$offset] = $value; + } + + function offsetUnset($offset) { + unset($this->storage[$offset]); + } + + function resolveCacheMiss($offset) { + views_include_default_views(); + + // $this->index holds an array keyed by view_name with the module providing + // the view as value. There is no way to find out which view belongs to + // which module without iterating over all views until we find it. However + // since this class does not store views that were not specifically + // requested in memory, instead we keep an index of views and modules so + // that some of the iteration can be avoided when more than one view is + // requested on the page. + if (isset($this->index[$offset])) { + $views = views_initialize_module_views($this->index[$offset]); + $this->storage[$offset] = $views[$offset]; + $view_clone = clone $views[$offset]; + $view_clone->destroy(); + views_cache_set('views_default:' . $offset, $view_clone, TRUE); + return $views[$offset]; + } + else { + $modules = module_implements('views_default_views'); + foreach ($modules as $module) { + $views = views_initialize_module_views($module); + foreach ($views as $key => $view) { + $this->index[$key] = $module; + if ($key == $offset) { + $this->storage[$offset] = $view; + $return = $view; + $view_clone = clone $view; + $view_clone->destroy(); + views_cache_set('views_default:' . $offset, $view_clone, TRUE); + // Do not break or return here. This allows all views provided + // by a module to be indexed so that subsequent lookups for views + // provided by the same module do not require foreaching again. + } + } + // If another process is also building the index, it may have more + // items than this request has accumulated. Compare before overwriting. + $cached = views_cache_get('views_default_index'); + if (!$cached || (count($cached->data) <= count($this->index))) { + views_cache_set('views_default_index', $this->index); + } + + if (!empty($return)) { + return $return; + } + } + // If no view was eligible, cache FALSE. + $this->storage[$offset] = FALSE; + views_cache_set('views_default:' . $offset, FALSE, TRUE); + } + } +} + +function _views_get_all_views($reset = FALSE) { + return new ViewsAllViews(); +} + +class ViewsAllViews implements Iterator { + protected $views = array(); + protected $dbViews = array(); + protected $modules; + + public function __construct() { + views_include_default_views(); + $this->modules = module_implements('views_default_views'); + views_include('view'); + $this->dbViews = view::load_views(); + // Populate each view from the database with default/overriden. + foreach ($this->dbViews as $key => $view) { + $this->dbViews[$key] = views_get_view($key); + } + $this->views = $this->dbViews; + } + + function rewind() { + $this->views = $this->dbViews; + $module = reset($this->modules); + $default_views = views_initialize_module_views($module); + foreach ($default_views as $key => $view) { + if (!isset($this->dbViews[$key])) { + $this->views[$key] = $view; + } + } + } + + function current() { + return current($this->views); + } + + function key() { + return key($this->views); + } + + function next() { + if (!next($this->views) && $module = next($this->modules)) { + $this->views = views_initialize_module_views($module); + // Don't iterate over views that have already been returned from the + // database. + foreach ($this->views as $key => $view) { + if (isset($this->dbViews[$key])) { + unset($this->views[$key]); + } + } + reset($this->views); + // There is a possibility that the module provides no default views + // or that all the views have been overridden. If this is the case + // call the function recursively to get to the next one. + if (empty($this->views)) { + $this->next(); + } + } + } + + function valid() { + return (bool) current($this->views); + } +} + +/** + * 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($module) { + $views = array(); + $function = $module . '_views_default_views'; + $result = $function(); + if ($result) { + drupal_alter('views_default_views', $result); + foreach ($result as $key => $view) { + if (!empty($view->api_version) && $view->api_version >= 2) { + $views[$key] = $view; + } + } + } + return $views; +} diff --git a/views.module b/views.module index 4a587f4..19e31c1 100644 --- a/views.module +++ b/views.module @@ -747,7 +747,7 @@ function views_get_plugin($type, $plugin) { * @return * A view object or NULL if it is not available. */ -function &views_get_default_view($view_name) { +function views_get_default_view($view_name) { $null = NULL; // Attempt to load individually cached view from cache. @@ -854,36 +854,20 @@ function views_get_applicable_views($type) { * If TRUE, reset the static cache forcing views to be reloaded. */ function views_get_all_views($reset = FALSE) { - static $views = array(); - - if (empty($views) || $reset) { - $views = array(); - - // First, get all applicable views. - views_include('view'); - $views = view::load_views(); - - // Get all default views. - $status = variable_get('views_defaults', array()); - - foreach (views_discover_default_views() as $view) { - // Determine if default view is enabled or disabled. - if (isset($status[$view->name])) { - $view->disabled = $status[$view->name]; - } - - // If overridden, also say so. - if (!empty($views[$view->name])) { - $views[$view->name]->type = t('Overridden'); - } - else { - $view->type = t('Default'); - $views[$view->name] = $view; - } - } + static $php5; + // 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', '>='); + } + if ($php5) { + module_load_include('inc', 'views', 'includes/php5'); + } + else { + module_load_include('inc', 'views', 'includes/php4'); } - return $views; + return _views_get_all_views(); } /**