### Eclipse Workspace Patch 1.0
#P drupal_test_7
Index: modules/field/field.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/field.test,v
retrieving revision 1.17
diff -u -r1.17 field.test
--- modules/field/field.test	3 May 2009 09:49:32 -0000	1.17
+++ modules/field/field.test	7 May 2009 23:55:02 -0000
@@ -71,10 +71,8 @@
     // Preparation: create three revisions and store them in $revision array.
     for ($revision_id = 0; $revision_id < 3; $revision_id++) {
       $revision[$revision_id] = field_test_create_stub_entity(0, $revision_id, $this->instance['bundle']);
-      // Note: we try to insert one extra value ('<=' instead of '<').
-      for ($delta = 0; $delta <= $this->field['cardinality']; $delta++) {
-        $values[$revision_id][$delta]['value'] = mt_rand(1, 127);
-      }
+      // Note: we try to insert one extra value.
+      $values[$revision_id] = $this->_generateTestFieldValues($this->field['cardinality'] + 1);
       $current_revision = $revision_id;
       // If this is the first revision do an insert.
       if (!$revision_id) {
@@ -139,7 +137,7 @@
     // Add some real data.
     field_cache_clear();
     $entity = clone($entity_init);
-    $values = array(0 => array('value' => mt_rand(1, 127)));
+    $values = $this->_generateTestFieldValues(1);
     $entity->{$this->field_name} = $values;
     field_attach_insert($entity_type, $entity);
 
@@ -203,10 +201,7 @@
     $entity = field_test_create_stub_entity(0, 0, $this->instance['bundle']);
 
     // Populate values to be displayed.
-    $values = array();
-    for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
-      $values[$delta]['value'] = mt_rand(1, 127);
-    }
+    $values = $this->_generateTestFieldValues($this->field['cardinality']);
     $entity->{$this->field_name} = $values;
 
     // Simple formatter, label displayed.
@@ -253,7 +248,6 @@
       'full' => array(
         'label' => 'above',
         'type' => 'hidden',
-
       ),
     );
     field_update_instance($this->instance);
@@ -301,10 +295,7 @@
     $rev[0] = field_test_create_stub_entity(0, 0, $this->instance['bundle']);
 
     // Create revision 0
-    $values = array();
-    for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
-      $values[$delta]['value'] = mt_rand(1, 127);
-    }
+    $values = $this->_generateTestFieldValues($this->field['cardinality']);
     $rev[0]->{$this->field_name} = $values;
     field_attach_insert($entity_type, $rev[0]);
 
@@ -347,7 +338,7 @@
     }
     $read = field_test_create_stub_entity(0, 2, $this->instance['bundle']);
     field_attach_load($entity_type, array(0 => $read));
-      $this->assertIdentical($read->{$this->field_name}, array(), "The test object current revision is deleted.");
+    $this->assertIdentical($read->{$this->field_name}, array(), "The test object current revision is deleted.");
   }
 
   function testFieldAttachCreateRenameBundle() {
@@ -362,10 +353,7 @@
 
     // Save an object with data in the field.
     $entity = field_test_create_stub_entity(0, 0, $this->instance['bundle']);
-    $values = array();
-    for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
-      $values[$delta]['value'] = mt_rand(1, 127);
-    }
+    $values = $this->_generateTestFieldValues($this->field['cardinality']);
     $entity->{$this->field_name} = $values;
     $entity_type = 'test_entity';
     field_attach_insert($entity_type, $entity);
@@ -419,12 +407,9 @@
 
     // Save an object with data for both fields
     $entity = field_test_create_stub_entity(0, 0, $this->instance['bundle']);
-    $values = array();
-    for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
-      $values[$delta]['value'] = mt_rand(1, 127);
-    }
+    $values = $this->_generateTestFieldValues($this->field['cardinality']);
     $entity->{$this->field_name} = $values;
-    $entity->{$field_name} = array(0 => array('value' => 99));
+    $entity->{$field_name} = $this->_generateTestFieldValues(1);
     $entity_type = 'test_entity';
     field_attach_insert($entity_type, $entity);
 
@@ -449,50 +434,74 @@
     $this->assertFalse(field_read_instance($field_name, $instance['bundle']), "Second field is deleted");
   }
 
+  /**
+   * Test that the field cache is correctly set in field_attach_load().
+   */
   function testFieldAttachCache() {
     // Create a revision
-    $entity = field_test_create_stub_entity(0, 0, $this->instance['bundle']);
-    $values = array();
-    for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
-      $values[$delta]['value'] = mt_rand(1, 127);
-    }
+    $entity = field_test_create_stub_entity(1, 1, $this->instance['bundle']);
+    $values = $this->_generateTestFieldValues($this->field['cardinality']);
     $entity->{$this->field_name} = $values;
 
     $noncached_type = 'test_entity';
     $cached_type = 'test_cacheable_entity';
 
-    // Non-cached type:
-    $cid = "field:$noncached_type:0:0";
+    // Non-cacheable entity type.
+    $cid = "field:$noncached_type:{$entity->ftid}";
 
-    // Confirm no initial cache entry
-    $this->assertFalse(cache_get($cid, 'cache_field'), 'Non-cached: no initial cache entry');
+    // Check that no initial cache entry is present.
+    $this->assertFalse(cache_get($cid, 'cache_field'), t('Non-cached: no initial cache entry'));
 
-    // Save, and confirm no cache entry
+    // Save, and check that no cache entry is present.
     field_attach_insert($noncached_type, $entity);
-    $this->assertFalse(cache_get($cid, 'cache_field'), 'Non-cached: no cache entry on save');
+    $this->assertFalse(cache_get($cid, 'cache_field'), t('Non-cached: no cache entry on insert'));
 
-    // Load, and confirm no cache entry
-    field_attach_load($noncached_type, array(0 => $entity));
-    $this->assertFalse(cache_get($cid, 'cache_field'), 'Non-cached: no cache entry on load');
+    // Load, and check that no cache entry is present.
+    field_attach_load($noncached_type, array($entity->ftid => $entity));
+    $this->assertFalse(cache_get($cid, 'cache_field'), t('Non-cached: no cache entry on load'));
 
-    // Cached type:
-    $cid = "field:$cached_type:0:0";
+    // Cacheable entity type.
+    $cid = "field:$cached_type:{$entity->ftid}";
 
-    // Confirm no initial cache entry
-    $this->assertFalse(cache_get($cid, 'cache_field'), 'Cached: no initial cache entry');
+    // Check that no initial cache entry is present.
+    $this->assertFalse(cache_get($cid, 'cache_field'), t('Cached: no initial cache entry'));
 
-    // Save, and confirm no cache entry
+    // Save, and check that no cache entry is present.
     field_attach_insert($cached_type, $entity);
-    $this->assertFalse(cache_get($cid, 'cache_field'), 'Cached: no cache entry on save');
+    $this->assertFalse(cache_get($cid, 'cache_field'), t('Cached: no cache entry on insert'));
+
+    // Load, and check that a cache entry is present with the expected values.
+    field_attach_load($cached_type, array($entity->ftid => $entity));
+    $cache = cache_get($cid, 'cache_field');
+    $this->assertEqual($cache->data[$this->field_name], $values, t('Cached: correct cache entry on load'));
+
+    // Update with different values, and check that the cache entry is wiped.
+    $values = $this->_generateTestFieldValues($this->field['cardinality']);
+    $entity->{$this->field_name} = $values;
+    field_attach_update($cached_type, $entity);
+    $this->assertFalse(cache_get($cid, 'cache_field'), t('Cached: no cache entry on update'));
+
+    // Load, and check that a cache entry is present with the expected values.
+    field_attach_load($cached_type, array($entity->ftid => $entity));
+    $cache = cache_get($cid, 'cache_field');
+    $this->assertEqual($cache->data[$this->field_name], $values, t('Cached: correct cache entry on load'));
 
-    // Load, and confirm cache entry
-    field_attach_load($cached_type, array(0 => $entity));
+    // Create a new revision, and check that the cache entry is wiped.
+    $values = $this->_generateTestFieldValues($this->field['cardinality']);
+    $entity->{$this->field_name} = $values;
+    $entity->ftvid = 2;
+    field_attach_update($cached_type, $entity);
+    $cache = cache_get($cid, 'cache_field');
+    $this->assertFalse(cache_get($cid, 'cache_field'), t('Cached: no cache entry on new revision creation'));
+
+    // Load, and check that a cache entry is present with the expected values.
+    field_attach_load($cached_type, array($entity->ftid => $entity));
     $cache = cache_get($cid, 'cache_field');
-    $this->assertEqual($cache->data[$this->field_name], $values, 'Cached: correct cache entry on load');
+    $this->assertEqual($cache->data[$this->field_name], $values, t('Cached: correct cache entry on load'));
 
-    // Delete, and confirm no cache entry
+    // Delete, and check that the cache entry is wiped.
     field_attach_delete($cached_type, $entity);
-    $this->assertFalse(cache_get($cid, 'cache_field'), 'Cached: no cache entry on save');
+    $this->assertFalse(cache_get($cid, 'cache_field'), t('Cached: no cache entry after delete'));
   }
 
   // Verify that field_attach_validate() invokes the correct
@@ -582,6 +591,23 @@
     }
     $this->assertIdentical($entity->{$this->field_name}, $expected_values, 'Submit filters empty values');
   }
+
+  /**
+   * Generate random values for a field_test field.
+   *
+   * @param $cardinality
+   *   Number of values to generate.
+   * @return
+   *  An array of random values, in the format expected for field values.
+   */
+  function _generateTestFieldValues($cardinality) {
+    $values = array();
+    for ($i = 0; $i < $cardinality; $i++) {
+      // field_test fields treat 0 as 'empty value'.
+      $values[$i]['value'] = mt_rand(1, 127);
+    }
+    return $values;
+  }
 }
 
 class FieldInfoTestCase extends DrupalWebTestCase {
@@ -930,7 +956,7 @@
       $field_values[$weight]['value'] = (string)$value;
       $pattern[$weight] = "<input [^>]*value=\"$value\" [^>]*";
     }
-     // Press 'add more' button through AHAH.
+    // Press 'add more' button through AHAH.
     $path = 'field/js_add_more/' . str_replace('_', '-', $this->instance['bundle']) . '/' . str_replace('_', '-', $this->instance['field_name']);
     $this->_fieldPostAhah($path, $edit, t('Add another item'));
 
Index: modules/field/field.attach.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/field.attach.inc,v
retrieving revision 1.13
diff -u -r1.13 field.attach.inc
--- modules/field/field.attach.inc	1 May 2009 15:28:13 -0000	1.13
+++ modules/field/field.attach.inc	7 May 2009 23:55:01 -0000
@@ -255,21 +255,29 @@
  *   appropriate set of fields added.
  */
 function _field_attach_load($obj_type, $objects, $age = FIELD_LOAD_CURRENT) {
-  $queried_objects = array();
+  $load_current = $age == FIELD_LOAD_CURRENT;
+
+  $info = field_info_fieldable_types($obj_type);
+  $cacheable = $load_current && $info['cacheable'];
 
+  $queried_objects = array();
   // Fetch avaliable objects from cache.
-  foreach ($objects as $object) {
-    list($id, $vid, $bundle, $cacheable) = field_attach_extract_ids($obj_type, $object);
-    $cid = "field:$obj_type:$id:$vid";
-    if ($cacheable && $cached = cache_get($cid, 'cache_field')) {
-      foreach ($cached->data as $key => $value) {
-        $object->$key = $value;
+  if ($cacheable) {
+    foreach ($objects as $id => $object) {
+      $cid = "field:$obj_type:$id";
+      if ($cacheable && $cached = cache_get($cid, 'cache_field')) {
+        foreach ($cached->data as $key => $value) {
+          $object->$key = $value;
+        }
+      }
+      else {
+        $queried_objects[$id] = $objects[$id];
       }
-    }
-    else {
-      $queried_objects[$id] = $objects[$id];
     }
   }
+  else {
+    $queried_objects = $objects;
+  }
 
   // Fetch other objects from the database.
   if ($queried_objects) {
@@ -314,7 +322,7 @@
     // multiple objects too. Which forbids going through _field_invoke(), but
     // requires manually iterating the instances instead.
     foreach ($queried_objects as $id => $object) {
-      list($id, $vid, $bundle, $cacheable) = field_attach_extract_ids($obj_type, $object);
+      list($id, $vid, $bundle) = field_attach_extract_ids($obj_type, $object);
 
       // Make sure empty fields are present as empty arrays.
       $instances = field_info_instances($bundle);
@@ -344,7 +352,7 @@
 
       // Cache the data.
       if ($cacheable) {
-        $cid = "field:$obj_type:$id:$vid";
+        $cid = "field:$obj_type:$id";
         $data = isset($additions[$id]) ? $additions[$id] : array();
         cache_set($cid, $data, 'cache_field');
       }
@@ -531,7 +539,7 @@
 
   list($id, $vid, $bundle, $cacheable) = field_attach_extract_ids($obj_type, $object);
   if ($cacheable) {
-    cache_clear_all("field:$obj_type:$id:", 'cache_field', TRUE);
+    cache_clear_all("field:$obj_type:$id", 'cache_field');
   }
 }
 
@@ -544,7 +552,6 @@
  *   The object with fields to save.
  */
 function _field_attach_update($obj_type, &$object) {
-
   _field_invoke('update', $obj_type, $object);
 
   // Let other modules act on updating the object, accumulating saved
@@ -560,7 +567,7 @@
 
   list($id, $vid, $bundle, $cacheable) = field_attach_extract_ids($obj_type, $object);
   if ($cacheable) {
-    cache_clear_all("field:$obj_type:$id:$vid", 'cache_field');
+    cache_clear_all("field:$obj_type:$id", 'cache_field');
   }
 }
 
@@ -585,7 +592,7 @@
 
   list($id, $vid, $bundle, $cacheable) = field_attach_extract_ids($obj_type, $object);
   if ($cacheable) {
-    cache_clear_all("field:$obj_type:$id:", 'cache_field', TRUE);
+    cache_clear_all("field:$obj_type:$id", 'cache_field');
   }
 }
 
@@ -607,11 +614,6 @@
     $function = $module . '_field_attach_delete_revision';
     $function($obj_type, $object);
   }
-
-  list($id, $vid, $bundle, $cacheable) = field_attach_extract_ids($obj_type, $object);
-  if ($cacheable) {
-    cache_clear_all("field:$obj_type:$id:$vid", 'cache_field');
-  }
 }
 
 /**
@@ -773,7 +775,7 @@
   // If no bundle key provided, then we assume a single bundle, named after the
   // type of the object.
   $bundle = $info['bundle key'] ? $object->{$info['bundle key']} : $object_type;
-  $cacheable = isset($info['cacheable']) ? $info['cacheable'] : FALSE;
+  $cacheable = $info['cacheable'];
   return array($id, $vid, $bundle, $cacheable);
 }
 
