view = &$view; $this->display = &$display; if (is_object($display->handler)) { $options = $display->handler->get_option('cache'); // Overlay incoming options on top of defaults $this->unpack_options($this->options, $options); } } /** * Return a string to display as the clickable title for the * access control. */ function summary_title() { return t('Unknown'); } /** * Determine the expiration time of the cache type, or NULL if no expire. * * Plugins must override this to implement expiration. * * @param $type * The cache type, either 'query', 'result' or 'output'. */ function cache_expire($type) { } /** * Determine expiration time in the cache table of the cache type * or CACHE_PERMANENT if item shouldn't be removed automatically from cache. * * Plugins must override this to implement expiration in the cache table. * * @param $type * The cache type, either 'query', 'result' or 'output'. */ function cache_set_expire($type) { return CACHE_PERMANENT; } /** * Save data to the cache. * * A plugin should override this to provide specialized caching behavior. */ function cache_set($type) { switch ($type) { case 'query': // Not supported currently, but this is certainly where we'd put it. break; case 'results': if ($this->get_results_key() !== FALSE) { $data = array( 'result' => $this->view->result, 'total_rows' => $this->view->total_rows, 'current_page' => $this->view->get_current_page(), ); cache_set($this->get_results_key(), $data, $this->table, $this->cache_set_expire($type)); } break; case 'output': $this->gather_headers(); $this->storage['output'] = $this->view->display_handler->output; cache_set($this->get_output_key(), $this->storage, $this->table, $this->cache_set_expire($type)); break; } } /** * Retrieve data from the cache. * * A plugin should override this to provide specialized caching behavior. */ function cache_get($type) { $cutoff = $this->cache_expire($type); switch ($type) { case 'query': // Not supported currently, but this is certainly where we'd put it. return FALSE; case 'results': // Values to set: $view->result, $view->total_rows, $view->execute_time, // $view->current_page. $results_key = $this->get_results_key(); if ($results_key === FALSE) { return FALSE; } else if ($cache = cache_get($results_key, $this->table)) { if (!$cutoff || $cache->created > $cutoff) { $this->view->result = $cache->data['result']; $this->view->total_rows = $cache->data['total_rows']; $this->view->set_current_page($cache->data['current_page']); $this->view->execute_time = 0; return TRUE; } } return FALSE; case 'output': if ($cache = cache_get($this->get_output_key(), $this->table)) { if (!$cutoff || $cache->created > $cutoff) { $this->storage = $cache->data; $this->view->display_handler->output = $cache->data['output']; $this->restore_headers(); return TRUE; } } return FALSE; } } /** * Clear out cached data for a view. * * We're just going to nuke anything related to the view, regardless of display, * to be sure that we catch everything. Maybe that's a bad idea. */ function cache_flush() { cache_clear_all($this->view->name . ':', $this->table, TRUE); } /** * Post process any rendered data. * * This can be valuable to be able to cache a view and still have some level of * dynamic output. In an ideal world, the actual output will include HTML * comment based tokens, and then the post process can replace those tokens. * * Example usage. If it is known that the view is a node view and that the * primary field will be a nid, you can do something like this: * * * * And then in the post render, create an array with the text that should * go there: * * strtr($output, array('', 'output for FIELD of nid 1'); * * All of the cached result data will be available in $view->result, as well, * so all ids used in the query should be discoverable. */ function post_render(&$output) { } /** * Start caching javascript, css and other out of band info. * * This takes a snapshot of the current system state so that we don't * duplicate it. Later on, when gather_headers() is run, this information * will be removed so that we don't hold onto it. */ function cache_start() { $this->storage['head'] = drupal_set_html_head(); $this->storage['css'] = drupal_add_css(); foreach (array('header', 'footer') as $scope) { $this->storage['js'][$scope] = drupal_add_js(NULL, NULL, $scope); } } /** * Gather out of band data, compare it to what we started with and store the difference. */ function gather_headers() { // Simple replacement for head $this->storage['head'] = str_replace($this->storage['head'], '', drupal_set_html_head()); // Slightly less simple for CSS: $css = drupal_add_css(); $start = $this->storage['css']; $this->storage['css'] = array(); foreach ($css as $media => $medias) { foreach ($medias as $type => $types) { foreach ($types as $path => $preprocess) { if (!isset($start[$media][$type][$path])) { $this->storage['css'][] = array($path, $type, $media, $preprocess); } } } } $js = array(); // A little less simple for js foreach (array('header', 'footer') as $scope) { $js[$scope] = drupal_add_js(NULL, NULL, $scope); } $start = $this->storage['js']; $this->storage['js'] = array(); foreach ($js as $scope => $scopes) { foreach ($scopes as $type => $types) { foreach ($types as $id => $info) { if (!isset($start[$scope][$type][$id])) { switch ($type) { case 'setting': $this->storage['js'][] = array($info, $type, $scope); break; case 'inline': $this->storage['js'][] = array($info['code'], $type, $scope, $info['defer']); break; default: $this->storage['js'][] = array($id, $type, $scope, $info['defer'], $info['cache']); } } } } } } /** * Restore out of band data saved to cache. Copied from Panels. */ function restore_headers() { if (!empty($this->storage['head'])) { drupal_set_html_head($this->storage['head']); } if (!empty($this->storage['css'])) { foreach ($this->storage['css'] as $args) { call_user_func_array('drupal_add_css', $args); } } if (!empty($this->storage['js'])) { foreach ($this->storage['js'] as $args) { call_user_func_array('drupal_add_js', $args); } } } function get_results_key() { global $user; if (!isset($this->_results_key)) { $cache_info = $this->view->query->get_cache_info(); if ($cache_info === FALSE) { $this->_results_key = FALSE; } else { $key_data = array( 'build_info' => $this->view->build_info, 'cache_info' => $this->view->query->get_cache_info(), 'roles' => array_keys($user->roles), 'super-user' => $user->uid == 1, // special caching for super user. 'language' => $GLOBALS['language'], ); foreach (array('exposed_info', 'page', 'sort', 'order') as $key) { if (isset($_GET[$key])) { $key_data[$key] = $_GET[$key]; } } $this->_results_key = $this->view->name . ':' . $this->display->id . ':results:' . md5(serialize($key_data)); } } return $this->_results_key; } function get_output_key() { global $user; if (!isset($this->_output_key)) { $key_data = array( 'result' => $this->view->result, 'roles' => array_keys($user->roles), 'super-user' => $user->uid == 1, // special caching for super user. 'theme' => $GLOBALS['theme'], 'language' => $GLOBALS['language'], ); $this->_output_key = $this->view->name . ':' . $this->display->id . ':output:' . md5(serialize($key_data)); } return $this->_output_key; } }