From 0d45e4e39e1929d218f685f35b9b0d5415fa96b8 Mon Sep 17 00:00:00 2001
Message-Id: <0d45e4e39e1929d218f685f35b9b0d5415fa96b8.1339699676.git.dmitriy.trt@gmail.com>
From: "Dmitriy.trt" <dmitriy.trt@gmail.com>
Date: Fri, 15 Jun 2012 01:30:36 +0700
Subject: [PATCH] Issue #1055616: Fix cached output for different input with
 the same results

---
 plugins/views_plugin_cache.inc |   53 ++++++++++++++++----------------
 tests/views_cache.test         |   65 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 92 insertions(+), 26 deletions(-)

diff --git a/plugins/views_plugin_cache.inc b/plugins/views_plugin_cache.inc
index 23ab5e1..61e7127 100644
--- a/plugins/views_plugin_cache.inc
+++ b/plugins/views_plugin_cache.inc
@@ -241,56 +241,57 @@ class views_plugin_cache extends views_plugin {
     }
   }
 
-  function get_results_key() {
+  /**
+   * Returns cache key.
+   *
+   * @param string $cache_type
+   * @param array $key_data
+   *   Additional data for cache segmentation and/or overrides for default
+   *   segmentation.
+   *
+   * @return string
+   */
+  function get_key($cache_type, $key_data = array()) {
     global $user;
 
-    if (!isset($this->_results_key)) {
+    $key_data += array(
+      'roles' => array_keys($user->roles),
+      'super-user' => $user->uid == 1, // special caching for super user.
+      'language' => $GLOBALS['language']->language,
+      'base_url' => $GLOBALS['base_url'],
+    );
 
+    if (empty($key_data['build_info'])) {
       $build_info = $this->view->build_info;
-
-      $query_plugin = $this->view->display_handler->get_plugin('query');
-
       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 SelectQueryInterface) {
           $query = clone $build_info[$index];
           $query->preExecute();
-          $build_info[$index] = (string)$query;
-        }
-      }
-      $key_data = array(
-        'build_info' => $build_info,
-        'roles' => array_keys($user->roles),
-        'super-user' => $user->uid == 1, // special caching for super user.
-        'language' => $GLOBALS['language']->language,
-        'base_url' => $GLOBALS['base_url'],
-      );
-      foreach (array('exposed_info', 'page', 'sort', 'order', 'items_per_page', 'offset') as $key) {
-        if (isset($_GET[$key])) {
-          $key_data[$key] = $_GET[$key];
+          $key_data['build_info'][$index] = strtr($query, $query->getArguments());
         }
       }
+    }
+    $key = $this->view->name . ':' . $this->display->id . ':' . $cache_type . ':' . md5(serialize($key_data));
+    return $key;
+  }
 
-      $this->_results_key = $this->view->name . ':' . $this->display->id . ':results:' . md5(serialize($key_data));
+  function get_results_key() {
+    if (!isset($this->_results_key)) {
+      $this->_results_key = $this->get_key('results');
     }
 
     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']->language,
-        'base_url' => $GLOBALS['base_url'],
       );
-
-      $this->_output_key = $this->view->name . ':' . $this->display->id . ':output:' . md5(serialize($key_data));
+      $this->_output_key = $this->get_key('output', $key_data);
     }
 
     return $this->_output_key;
diff --git a/tests/views_cache.test b/tests/views_cache.test
index 5f3076e..80e8876 100644
--- a/tests/views_cache.test
+++ b/tests/views_cache.test
@@ -211,4 +211,69 @@ class ViewsCacheTest extends ViewsSqlTest {
 
   }
 
+  /**
+   * Test caching of different exposed filter values with the same view result.
+   *
+   * Make sure the output is different.
+   */
+  function testExposedFilterSameResultsCaching() {
+    // Create the view with time-based cache with hour lifetimes and add exposed
+    // filter to it with "Starts with" operator.
+    $view = $this->getBasicView();
+    $view->set_display();
+    $view->display_handler->override_option('cache', array(
+      'type' => 'time',
+      'results_lifespan' => '3600',
+      'output_lifespan' => '3600',
+    ));
+    $view->display_handler->override_option('filters', array(
+      'name' => array(
+        'id' => 'name',
+        'table' => 'views_test',
+        'field' => 'name',
+        'relationship' => 'none',
+        'operator' => 'starts',
+        'exposed' => TRUE,
+        'expose' => array(
+          'operator_id' => 'name_op',
+          'operator' => 'name_op',
+          'identifier' => 'name',
+        ),
+      ),
+    ));
+
+    // Clone the view before setting exposed input.
+    $clone = $view->copy();
+
+    // Pass "Rin" to the exposed filter and check that only one row returned.
+    $view->set_exposed_input(array(
+      'name' => 'Rin',
+    ));
+    $this->executeView($view);
+    $first_result = $view->result;
+    $first_output = $view->render();
+    $this->assertEqual(1, count($first_result), t('The number of rows returned by the first view match.'));
+
+    // Pass full "Ringo" to the exposed filter at the second time and make sure
+    // results are the same.
+    $clone->set_exposed_input(array(
+      'name' => 'Ringo',
+    ));
+    $this->executeView($clone);
+    $second_result = $clone->result;
+    $second_output = $clone->render();
+    $this->assertEqual($first_result, $second_result, t('Results of both views are the same.'));
+
+    // Check that output is not the same and it contains full "Ringo" word in
+    // default value of exposed input.
+    $this->assertNotEqual($first_output, $second_output, t('Output of the second view is different.'));
+    $document = new DOMDocument();
+    $html = '<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/></head><body><div>' . $second_output . '</div></body>';
+    $this->assertTrue($document->loadHTML($html), t('HTML has been loaded to DOM parser.'));
+    $xpath = new DOMXPath($document);
+    $this->assertEqual("Ringo", $xpath->evaluate('string(//input[@name="name"]/@value)'), t('Input field of exposed filter has the second value.'));
+
+    $view->destroy();
+    $clone->destroy();
+  }
 }
-- 
1.7.10

