You are here

abstract class CachePluginBase in Zircon Profile 8

Same name and namespace in other branches
  1. 8.0 core/modules/views/src/Plugin/views/cache/CachePluginBase.php \Drupal\views\Plugin\views\cache\CachePluginBase

The base plugin to handle caching.

Hierarchy

Expanded class hierarchy of CachePluginBase

Related topics

5 files declare their use of CachePluginBase
DisplayKernelTest.php in core/modules/views/src/Tests/Plugin/DisplayKernelTest.php
Contains \Drupal\views\Tests\Plugin\DisplayKernelTest.
test_basetheme.theme in core/modules/system/tests/themes/test_basetheme/test_basetheme.theme
Add hooks for tests to use.
test_subtheme.theme in core/modules/system/tests/themes/test_subtheme/test_subtheme.theme
Add hooks for tests to use.
views.api.php in core/modules/views/views.api.php
Describes hooks and plugins provided by the Views module.
views_test_data.views_execution.inc in core/modules/views/tests/modules/views_test_data/views_test_data.views_execution.inc
Provides views data and hooks for views_test_data module.

File

core/modules/views/src/Plugin/views/cache/CachePluginBase.php, line 34
Contains \Drupal\views\Plugin\views\cache\CachePluginBase.

Namespace

Drupal\views\Plugin\views\cache
View source
abstract class CachePluginBase extends PluginBase {

  /**
   * Contains all data that should be written/read from cache.
   */
  var $storage = array();

  /**
   * Which cache bin to store query results in.
   *
   * @var string
   */
  protected $resultsBin = 'data';

  /**
   * Stores the cache ID used for the results cache.
   *
   * The cache ID is stored in generateResultsKey() got executed.
   *
   * @var string
   *
   * @see \Drupal\views\Plugin\views\cache\CachePluginBase::generateResultsKey()
   */
  protected $resultsKey;

  /**
   * Returns the resultsKey property.
   *
   * @return string
   *   The resultsKey property.
   */
  public function getResultsKey() {
    return $this->resultsKey;
  }

  /**
   * Return a string to display as the clickable title for the
   * access control.
   */
  public function summaryTitle() {
    return $this
      ->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'.
   */
  protected function cacheExpire($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'.
   */
  protected function cacheSetMaxAge($type) {
    return Cache::PERMANENT;
  }

  /**
   * Save data to the cache.
   *
   * A plugin should override this to provide specialized caching behavior.
   */
  public function cacheSet($type) {
    switch ($type) {
      case 'query':

        // Not supported currently, but this is certainly where we'd put it.
        break;
      case 'results':
        $data = array(
          'result' => $this
            ->prepareViewResult($this->view->result),
          'total_rows' => isset($this->view->total_rows) ? $this->view->total_rows : 0,
          'current_page' => $this->view
            ->getCurrentPage(),
        );
        $expire = $this
          ->cacheSetMaxAge($type) === Cache::PERMANENT ? Cache::PERMANENT : (int) $this->view
          ->getRequest()->server
          ->get('REQUEST_TIME') + $this
          ->cacheSetMaxAge($type);
        \Drupal::cache($this->resultsBin)
          ->set($this
          ->generateResultsKey(), $data, $expire, $this
          ->getCacheTags());
        break;
    }
  }

  /**
   * Retrieve data from the cache.
   *
   * A plugin should override this to provide specialized caching behavior.
   */
  public function cacheGet($type) {
    $cutoff = $this
      ->cacheExpire($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.
        if ($cache = \Drupal::cache($this->resultsBin)
          ->get($this
          ->generateResultsKey())) {
          if (!$cutoff || $cache->created > $cutoff) {
            $this->view->result = $cache->data['result'];

            // Load entities for each result.
            $this->view->query
              ->loadEntities($this->view->result);
            $this->view->total_rows = $cache->data['total_rows'];
            $this->view
              ->setCurrentPage($cache->data['current_page'], TRUE);
            $this->view->execute_time = 0;
            return TRUE;
          }
        }
        return FALSE;
    }
  }

  /**
   * Clear out cached data for a view.
   */
  public function cacheFlush() {
    Cache::invalidateTags($this->view->storage
      ->getCacheTagsToInvalidate());
  }

  /**
   * 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:
   *
   * <!--post-FIELD-NID-->
   *
   * And then in the post render, create an array with the text that should
   * go there:
   *
   * strtr($output, array('<!--post-FIELD-1-->', '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.
   */
  public function postRender(&$output) {
  }

  /**
   * Calculates and sets a cache ID used for the result cache.
   *
   * @return string
   *   The generated cache ID.
   */
  public function generateResultsKey() {
    if (!isset($this->resultsKey)) {
      $build_info = $this->view->build_info;
      foreach (array(
        'query',
        'count_query',
      ) as $index) {

        // If the default query back-end is used generate SQL query strings from
        // the query objects.
        if ($build_info[$index] instanceof Select) {
          $query = clone $build_info[$index];
          $query
            ->preExecute();
          $build_info[$index] = array(
            'query' => (string) $query,
            'arguments' => $query
              ->getArguments(),
          );
        }
      }
      $key_data = [
        'build_info' => $build_info,
      ];

      // @todo https://www.drupal.org/node/2433591 might solve it to not require
      //    the pager information here.
      $key_data['pager'] = [
        'page' => $this->view
          ->getCurrentPage(),
        'items_per_page' => $this->view
          ->getItemsPerPage(),
        'offset' => $this->view
          ->getOffset(),
      ];
      $key_data += \Drupal::service('cache_contexts_manager')
        ->convertTokensToKeys($this->displayHandler
        ->getCacheMetadata()
        ->getCacheContexts())
        ->getKeys();
      $this->resultsKey = $this->view->storage
        ->id() . ':' . $this->displayHandler->display['id'] . ':results:' . hash('sha256', serialize($key_data));
    }
    return $this->resultsKey;
  }

  /**
   * Gets an array of cache tags for the current view.
   *
   * @return string[]
   *   An array of cache tags based on the current view.
   */
  public function getCacheTags() {
    $tags = $this->view->storage
      ->getCacheTags();

    // The list cache tags for the entity types listed in this view.
    $entity_information = $this->view
      ->getQuery()
      ->getEntityTableInfo();
    if (!empty($entity_information)) {

      // Add the list cache tags for each entity type used by this view.
      foreach ($entity_information as $table => $metadata) {
        $tags = Cache::mergeTags($tags, \Drupal::entityManager()
          ->getDefinition($metadata['entity_type'])
          ->getListCacheTags());
      }
    }
    $tags = Cache::mergeTags($tags, $this->view
      ->getQuery()
      ->getCacheTags());
    return $tags;
  }

  /**
   * Gets the max age for the current view.
   *
   * @return int
   */
  public function getCacheMaxAge() {
    $max_age = $this
      ->getDefaultCacheMaxAge();
    $max_age = Cache::mergeMaxAges($max_age, $this->view
      ->getQuery()
      ->getCacheMaxAge());
    return $max_age;
  }

  /**
   * Returns the default cache max age.
   */
  protected function getDefaultCacheMaxAge() {

    // The default cache backend is not caching anything.
    return 0;
  }

  /**
   * Prepares the view result before putting it into cache.
   *
   * @param \Drupal\views\ResultRow[] $result
   *   The result containing loaded entities.
   *
   * @return \Drupal\views\ResultRow[] $result
   *   The result without loaded entities.
   */
  protected function prepareViewResult(array $result) {
    $return = [];

    // Clone each row object and remove any loaded entities, to keep the
    // original result rows intact.
    foreach ($result as $key => $row) {
      $clone = clone $row;
      $clone
        ->resetEntityData();
      $return[$key] = $clone;
    }
    return $return;
  }

  /**
   * Alters the cache metadata of a display upon saving a view.
   *
   * @param \Drupal\Core\Cache\CacheableMetadata $cache_metadata
   *   The cache metadata.
   */
  public function alterCacheMetadata(CacheableMetadata $cache_metadata) {
  }

  /**
   * Returns the row cache tags.
   *
   * @param ResultRow $row
   *   A result row.
   *
   * @return string[]
   *   The row cache tags.
   */
  public function getRowCacheTags(ResultRow $row) {
    $tags = !empty($row->_entity) ? $row->_entity
      ->getCacheTags() : [];
    if (!empty($row->_relationship_entities)) {
      foreach ($row->_relationship_entities as $entity) {
        $tags = Cache::mergeTags($tags, $entity
          ->getCacheTags());
      }
    }
    return $tags;
  }

  /**
   * Returns the row cache keys.
   *
   * @param \Drupal\views\ResultRow $row
   *   A result row.
   *
   * @return string[]
   *   The row cache keys.
   */
  public function getRowCacheKeys(ResultRow $row) {
    return [
      'views',
      'fields',
      $this->view
        ->id(),
      $this->view->current_display,
      $this
        ->getRowId($row),
    ];
  }

  /**
   * Returns a unique identifier for the specified row.
   *
   * @param \Drupal\views\ResultRow $row
   *   A result row.
   *
   * @return string
   *   The row identifier.
   */
  public function getRowId(ResultRow $row) {

    // Here we compute a unique identifier for the row by computing the hash of
    // its data. We exclude the current index, since the same row could have a
    // different result index depending on the user permissions. We exclude also
    // entity data, since serializing entity objects is very expensive. Instead
    // we include entity cache tags, which are enough to identify all the
    // entities associated with the row.
    $row_data = array_diff_key((array) $row, array_flip([
      'index',
      '_entity',
      '_relationship_entities',
    ])) + $this
      ->getRowCacheTags($row);

    // This ensures that we get a unique identifier taking field handler access
    // into account: users having access to different sets of fields will get
    // different row identifiers.
    $field_ids = array_keys($this->view->field);
    $row_data += array_flip($field_ids);

    // Finally we compute a hash of row data and return it as row identifier.
    return hash('sha256', serialize($row_data));
  }

}

Members

Namesort descending Modifiers Type Description Overrides
CachePluginBase::$resultsBin protected property Which cache bin to store query results in.
CachePluginBase::$resultsKey protected property Stores the cache ID used for the results cache.
CachePluginBase::$storage property Contains all data that should be written/read from cache.
CachePluginBase::alterCacheMetadata public function Alters the cache metadata of a display upon saving a view.
CachePluginBase::cacheExpire protected function Determine the expiration time of the cache type, or NULL if no expire. 2
CachePluginBase::cacheFlush public function Clear out cached data for a view.
CachePluginBase::cacheGet public function Retrieve data from the cache. 1
CachePluginBase::cacheSet public function Save data to the cache. 1
CachePluginBase::cacheSetMaxAge protected function Determine expiration time in the cache table of the cache type or CACHE_PERMANENT if item shouldn't be removed automatically from cache. 1
CachePluginBase::generateResultsKey public function Calculates and sets a cache ID used for the result cache.
CachePluginBase::getCacheMaxAge public function Gets the max age for the current view.
CachePluginBase::getCacheTags public function Gets an array of cache tags for the current view.
CachePluginBase::getDefaultCacheMaxAge protected function Returns the default cache max age. 2
CachePluginBase::getResultsKey public function Returns the resultsKey property.
CachePluginBase::getRowCacheKeys public function Returns the row cache keys.
CachePluginBase::getRowCacheTags public function Returns the row cache tags.
CachePluginBase::getRowId public function Returns a unique identifier for the specified row.
CachePluginBase::postRender public function Post process any rendered data.
CachePluginBase::prepareViewResult protected function Prepares the view result before putting it into cache.
CachePluginBase::summaryTitle public function Return a string to display as the clickable title for the access control. Overrides PluginBase::summaryTitle 3
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
PluginBase::$configuration protected property Configuration information passed into the plugin. 2
PluginBase::$definition public property Plugins's definition
PluginBase::$displayHandler public property The display object this plugin is for.
PluginBase::$options public property Options for this plugin will be held here.
PluginBase::$pluginDefinition protected property The plugin implementation definition.
PluginBase::$pluginId protected property The plugin_id.
PluginBase::$renderer protected property Stores the render API renderer. 2
PluginBase::$usesOptions protected property Denotes whether the plugin has an additional options form. 8
PluginBase::$view public property The top object of a view. 1
PluginBase::buildOptionsForm public function Provide a form to edit options for this plugin. Overrides ViewsPluginInterface::buildOptionsForm 16
PluginBase::calculateDependencies public function Calculates dependencies for the configured plugin. Overrides DependentPluginInterface::calculateDependencies 20
PluginBase::create public static function Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface::create 50
PluginBase::defineOptions protected function Information about options for all kinds of purposes will be held here. 18
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::destroy public function Clears a plugin. Overrides ViewsPluginInterface::destroy 2
PluginBase::doFilterByDefinedOptions protected function Do the work to filter out stored options depending on the defined options.
PluginBase::filterByDefinedOptions public function Filter out stored options depending on the defined options. Overrides ViewsPluginInterface::filterByDefinedOptions
PluginBase::getAvailableGlobalTokens public function Returns an array of available token replacements. Overrides ViewsPluginInterface::getAvailableGlobalTokens
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::getProvider public function Returns the plugin provider. Overrides ViewsPluginInterface::getProvider
PluginBase::getRenderer protected function Returns the render API renderer. 1
PluginBase::globalTokenForm public function Adds elements for available core tokens to a form. Overrides ViewsPluginInterface::globalTokenForm
PluginBase::globalTokenReplace public function Returns a string with any core tokens replaced. Overrides ViewsPluginInterface::globalTokenReplace
PluginBase::INCLUDE_ENTITY constant Include entity row languages when listing languages.
PluginBase::INCLUDE_NEGOTIATED constant Include negotiated languages when listing languages.
PluginBase::init public function Initialize the plugin. Overrides ViewsPluginInterface::init 8
PluginBase::listLanguages protected function Makes an array of languages, optionally including special languages.
PluginBase::pluginTitle public function Return the human readable name of the display. Overrides ViewsPluginInterface::pluginTitle
PluginBase::preRenderAddFieldsetMarkup public static function Moves form elements into fieldsets for presentation purposes. Overrides ViewsPluginInterface::preRenderAddFieldsetMarkup
PluginBase::preRenderFlattenData public static function Flattens the structure of form elements. Overrides ViewsPluginInterface::preRenderFlattenData
PluginBase::query public function Add anything to the query that we might need to. Overrides ViewsPluginInterface::query 8
PluginBase::queryLanguageSubstitutions public static function Returns substitutions for Views queries for languages.
PluginBase::setOptionDefaults protected function Fills up the options of the plugin with defaults.
PluginBase::submitOptionsForm public function Handle any special handling on the validate form. Overrides ViewsPluginInterface::submitOptionsForm 16
PluginBase::themeFunctions public function Provide a full list of possible theme templates used by this style. Overrides ViewsPluginInterface::themeFunctions 1
PluginBase::unpackOptions public function Unpack options over our existing defaults, drilling down into arrays so that defaults don't get totally blown away. Overrides ViewsPluginInterface::unpackOptions
PluginBase::usesOptions public function Returns the usesOptions property. Overrides ViewsPluginInterface::usesOptions 8
PluginBase::validate public function Validate that the plugin is correct and can be saved. Overrides ViewsPluginInterface::validate 5
PluginBase::validateOptionsForm public function Validate the options form. Overrides ViewsPluginInterface::validateOptionsForm 15
PluginBase::viewsTokenReplace protected function Replaces Views' tokens in a given string. The resulting string will be sanitized with Xss::filterAdmin. 1
PluginBase::VIEWS_QUERY_LANGUAGE_SITE_DEFAULT constant Query string to indicate the site default language.
PluginBase::__construct public function Constructs a PluginBase object. Overrides PluginBase::__construct
StringTranslationTrait::$stringTranslation protected property The string translation service.
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.