You are here

trait SearchApiCachePluginTrait in Search API 8

Provides a trait to use in Views cache plugins for Search API queries.

Hierarchy

File

src/Plugin/views/cache/SearchApiCachePluginTrait.php, line 16

Namespace

Drupal\search_api\Plugin\views\cache
View source
trait SearchApiCachePluginTrait {

  /**
   * The cache backend.
   *
   * @var \Drupal\Core\Cache\CacheBackendInterface|null
   */
  protected $cacheBackend;

  /**
   * The cache contexts manager.
   *
   * @var \Drupal\Core\Cache\Context\CacheContextsManager|null
   */
  protected $cacheContextsManager;

  /**
   * The query helper.
   *
   * @var \Drupal\search_api\Utility\QueryHelperInterface|null
   */
  protected $queryHelper;

  /**
   * Retrieves the cache backend.
   *
   * @return \Drupal\Core\Cache\CacheBackendInterface
   *   The cache backend.
   */
  public function getCacheBackend() {
    return $this->cacheBackend ?: \Drupal::cache($this->resultsBin);
  }

  /**
   * Sets the cache backend.
   *
   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
   *   The new cache backend.
   *
   * @return $this
   */
  public function setCacheBackend(CacheBackendInterface $cache_backend) {
    $this->cacheBackend = $cache_backend;
    return $this;
  }

  /**
   * Retrieves the cache contexts manager.
   *
   * @return \Drupal\Core\Cache\Context\CacheContextsManager
   *   The cache contexts manager.
   */
  public function getCacheContextsManager() {
    return $this->cacheContextsManager ?: \Drupal::service('cache_contexts_manager');
  }

  /**
   * Sets the cache contexts manager.
   *
   * @param \Drupal\Core\Cache\Context\CacheContextsManager $cache_contexts_manager
   *   The new cache contexts manager.
   *
   * @return $this
   */
  public function setCacheContextsManager(CacheContextsManager $cache_contexts_manager) {
    $this->cacheContextsManager = $cache_contexts_manager;
    return $this;
  }

  /**
   * Retrieves the query helper.
   *
   * @return \Drupal\search_api\Utility\QueryHelperInterface
   *   The query helper.
   */
  public function getQueryHelper() {
    return $this->queryHelper ?: \Drupal::service('search_api.query_helper');
  }

  /**
   * Sets the query helper.
   *
   * @param \Drupal\search_api\Utility\QueryHelperInterface $query_helper
   *   The new query helper.
   *
   * @return $this
   */
  public function setQueryHelper(QueryHelperInterface $query_helper) {
    $this->queryHelper = $query_helper;
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function cacheSet($type) {
    if ($type != 'results') {
      parent::cacheSet($type);
      return;
    }
    $view = $this
      ->getView();
    $data = [
      'result' => $view->result,
      'total_rows' => $view->total_rows ?? 0,
      'current_page' => $view
        ->getCurrentPage(),
      'search_api results' => $this
        ->getQuery()
        ->getSearchApiResults(),
    ];
    $expire = $this
      ->cacheSetMaxAge($type);
    if ($expire !== Cache::PERMANENT) {
      $expire += (int) $view
        ->getRequest()->server
        ->get('REQUEST_TIME');
    }
    $this
      ->getCacheBackend()
      ->set($this
      ->generateResultsKey(), $data, $expire, $this
      ->getCacheTags());
  }

  /**
   * {@inheritdoc}
   */
  public function cacheGet($type) {
    if ($type != 'results') {
      return parent::cacheGet($type);
    }

    // Values to set: $view->result, $view->total_rows, $view->execute_time,
    // $view->current_page.
    if ($cache = $this
      ->getCacheBackend()
      ->get($this
      ->generateResultsKey())) {
      $cutoff = $this
        ->cacheExpire($type);
      if (!$cutoff || $cache->created > $cutoff) {
        $view = $this
          ->getView();
        $view->result = $cache->data['result'];
        $view->total_rows = $cache->data['total_rows'];
        $view
          ->setCurrentPage($cache->data['current_page']);
        $view->execute_time = 0;

        // Trick Search API into believing a search happened, to make faceting
        // et al. work.

        /** @var \Drupal\search_api\Query\ResultSetInterface $results */
        $results = $cache->data['search_api results'];
        $this
          ->getQueryHelper()
          ->addResults($results);
        try {
          $this
            ->getQuery()
            ->setSearchApiQuery($results
            ->getQuery());
        } catch (SearchApiException $e) {

          // Ignore.
        }
        return TRUE;
      }
    }
    return FALSE;
  }

  /**
   * {@inheritdoc}
   */
  public function generateResultsKey() {
    if (!isset($this->resultsKey)) {
      $this
        ->getQuery()
        ->getSearchApiQuery()
        ->preExecute();
      $view = $this
        ->getView();
      $build_info = $view->build_info;
      $key_data = [
        'build_info' => $build_info,
        'pager' => [
          'page' => $view
            ->getCurrentPage(),
          'items_per_page' => $view
            ->getItemsPerPage(),
          'offset' => $view
            ->getOffset(),
        ],
      ];

      // Vary the results key by the cache contexts of the display handler.
      // These cache contexts are calculated when the view is saved in the Views
      // UI and stored in the view config entity.
      $display_handler_cache_contexts = $this->displayHandler
        ->getCacheMetadata()
        ->getCacheContexts();
      $key_data += $this
        ->getCacheContextsManager()
        ->convertTokensToKeys($display_handler_cache_contexts)
        ->getKeys();
      $this->resultsKey = $view->storage
        ->id() . ':' . $this->displayHandler->display['id'] . ':results:' . Crypt::hashBase64(serialize($key_data));
    }
    return $this->resultsKey;
  }

  /**
   * Retrieves the view to which this plugin belongs.
   *
   * @return \Drupal\views\ViewExecutable
   *   The view.
   */
  protected function getView() {
    return $this->view;
  }

  /**
   * Retrieves the Search API Views query for the current view.
   *
   * @return \Drupal\search_api\Plugin\views\query\SearchApiQuery|null
   *   The Search API Views query associated with the current view.
   *
   * @throws \Drupal\search_api\SearchApiException
   *   Thrown if there is no current Views query, or it is no Search API query.
   */
  protected function getQuery() {
    $query = $this
      ->getView()
      ->getQuery();
    if ($query instanceof SearchApiQuery) {
      return $query;
    }
    throw new SearchApiException('No matching Search API Views query found in view.');
  }

}

Members

Namesort descending Modifiers Type Description Overrides
SearchApiCachePluginTrait::$cacheBackend protected property The cache backend.
SearchApiCachePluginTrait::$cacheContextsManager protected property The cache contexts manager.
SearchApiCachePluginTrait::$queryHelper protected property The query helper.
SearchApiCachePluginTrait::cacheGet public function
SearchApiCachePluginTrait::cacheSet public function
SearchApiCachePluginTrait::generateResultsKey public function
SearchApiCachePluginTrait::getCacheBackend public function Retrieves the cache backend.
SearchApiCachePluginTrait::getCacheContextsManager public function Retrieves the cache contexts manager.
SearchApiCachePluginTrait::getQuery protected function Retrieves the Search API Views query for the current view.
SearchApiCachePluginTrait::getQueryHelper public function Retrieves the query helper.
SearchApiCachePluginTrait::getView protected function Retrieves the view to which this plugin belongs.
SearchApiCachePluginTrait::setCacheBackend public function Sets the cache backend.
SearchApiCachePluginTrait::setCacheContextsManager public function Sets the cache contexts manager.
SearchApiCachePluginTrait::setQueryHelper public function Sets the query helper.