=== modified file 'modules/field/api.field.php' --- modules/field/api.field.php 2009-02-05 03:42:56 +0000 +++ modules/field/api.field.php 2009-02-05 16:08:57 +0000 @@ -402,13 +402,35 @@ function hook_field_attach_form($obj_typ } /** - * Act on field_attach_load. This hook is invoked after the field module - * has performed the operation. + * Act on field_attach_load. This hook allows modules to load data + * before the Field Storage API, preventing the field storage module + * from doing so. * - * See field_attach_load() for details and arguments. TODO: - * Currently, this hook only accepts a single object a time. + * @param $obj_type + * The type of objects for which to load fields; e.g. 'node' or + * 'user'. + * @param $objects + * An array of objects for which to load fields. The keys for + * primary id and bundle name to load are identified by + * hook_fieldable_info for $obj_type. + * @param $age + * FIELD_LOAD_CURRENT to load the most recent revision for all + * fields, or FIELD_LOAD_REVISION to load the version indicated by + * each object. + * @param $skip_fields + * An array of whose keys are field names whose data has already + * been loaded and therefore should not be loaded again. + * @return + * An array with two keys: + * - 'fields': An array of whose keys are the field names that were + * loaded by this function and should not be loaded by subsequent + * functions. + * - 'additions': An array whose keys are object ids for which data + * was loaded, and whose values are arrays whose keys are field + * names loaded for the object and whose values are the field data + * items loaded for the object.n */ -function hook_field_attach_load($obj_type, $object) { +function hook_field_attach_load($obj_type, $objects, $age, $skip_fields) { } /** @@ -439,23 +461,43 @@ function hook_field_attach_presave($obj_ } /** - * Act on field_attach_insert. This hook is invoked after the field module - * has performed the operation. + * Act on field_attach_insert. This hook allows modules to store data + * before the Field Storage API, preventing the field storage module + * from doing so. * - * See field_attach_insert() for details and arguments. + * @param $obj_type + * The type of $object; e.g. 'node' or 'user'. + * @param $object + * The object with fields to save. + * @param $skip_fields + * An array whose keys are field names whose data has already + * been saved and therefore should not be saved again. + * @return + * An array whose keys are field names that were saved by this + * function and therefore should not be saved again. */ -function hook_field_attach_insert($obj_type, $object) { +function hook_field_attach_insert($obj_type, $object, $skip_fields) { } - + /** - * Act on field_attach_update. This hook is invoked after the field module - * has performed the operation. + * Act on field_attach_update. This hook allows modules to store data + * before the Field Storage API, preventing the field storage module + * from doing so. * - * See field_attach_update() for details and arguments. + * @param $obj_type + * The type of $object; e.g. 'node' or 'user'. + * @param $object + * The object with fields to save. + * @param $skip_fields + * An array whose keys are field names whose data has already + * been saved and therefore should not be saved again. + * @return + * An array whose keys are field names that were saved by this + * function and therefore should not be saved again. */ -function hook_field_attach_update($obj_type, $object) { +function hook_field_attach_update($obj_type, $object, $skip_fields) { } - + /** * Act on field_attach_delete. This hook is invoked after the field module * has performed the operation. === modified file 'modules/field/field.attach.inc' --- modules/field/field.attach.inc 2009-02-05 03:42:56 +0000 +++ modules/field/field.attach.inc 2009-02-05 16:13:54 +0000 @@ -201,7 +201,7 @@ function _field_attach_form($obj_type, $ function _field_attach_load($obj_type, $objects, $age = FIELD_LOAD_CURRENT) { $queried_objects = array(); - // Fetch avaliable nodes from cache. + // 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"; @@ -214,18 +214,36 @@ function _field_attach_load($obj_type, $ $queried_objects[$id] = $objects[$id]; } } - // Fetch other nodes from the database. + // Fetch other objects from the database. if ($queried_objects) { + // Let any module load field data before the storage engine, + // accumulating along the way. + $loaded = array('fields' => array(), 'additions' => array()); // We need the raw additions to be able to cache them, so - // content_storage_load() and hook_field_load() must not alter - // nodes directly but return their additions. - $additions = module_invoke(variable_get('field_storage_module', 'field_sql_storage'), 'field_storage_load', $obj_type, $queried_objects, $age); + // hook_field_storage_load() and hook_field_attach_load() must not + // alter objects directly but return their additions. + foreach (module_implements('field_attach_load') as $module) { + $function = $module . '_field_attach_load'; + $return = $function($obj_type, $queried_objects, $age, $loaded['fields']); + $loaded = array_merge_recursive($loaded, $return); + } + + // The field storage engine loads the rest. + $additions = module_invoke(variable_get('field_storage_module', 'field_sql_storage'), 'field_storage_load', $obj_type, $queried_objects, $age, $loaded['fields']); + foreach ($additions as $id => $obj_additions) { foreach ($obj_additions as $key => $value) { $queried_objects[$id]->$key = $value; } } + foreach ($loaded['additions'] as $id => $obj_additions) { + foreach ($obj_additions as $key => $value) { + $queried_objects[$id]->$key = $value; + $additions[$id][$key] = $value; + } + } + // TODO D7 : to be consistent we might want to make hook_field_load() accept // multiple objects too. Which forbids going through _field_invoke(), but // requires manually iterating the instances instead. @@ -247,15 +265,6 @@ function _field_attach_load($obj_type, $ $additions[$id][$key] = $value; } - // Let other modules act on loading the object. - // TODO : this currently doesn't get cached (we cache $additions). - // This should either be called after we fetch from cache, or return an - // array of additions. - foreach (module_implements('field_attach_load') as $module) { - $function = $module . '_field_attach_load'; - $function($obj_type, $queried_objects[$id]); - } - // Cache the data. if ($cacheable) { $cid = "field:$obj_type:$id:$vid"; @@ -374,14 +383,19 @@ function _field_attach_presave($obj_type */ function _field_attach_insert($obj_type, &$object) { - // Let other modules act on inserting the object. + _field_invoke('insert', $obj_type, $object); + + // Let other modules act on inserting the object, accumulating saved + // fields along the way. + $saved = array(); foreach (module_implements('field_attach_insert') as $module) { $function = $module . '_field_attach_insert'; - $function($obj_type, $object); + $return = $function($obj_type, $object, $saved); + $saved = array_merge($saved, $return); } - _field_invoke('insert', $obj_type, $object); - module_invoke(variable_get('field_storage_module', 'field_sql_storage'), 'field_storage_write', $obj_type, $object); + // Field storage module saves any remaining unsaved fields. + module_invoke(variable_get('field_storage_module', 'field_sql_storage'), 'field_storage_write', $obj_type, $object, FALSE, $saved); list($id, $vid, $bundle, $cacheable) = field_attach_extract_ids($obj_type, $object); if ($cacheable) { @@ -399,14 +413,18 @@ function _field_attach_insert($obj_type, */ function _field_attach_update($obj_type, &$object) { - // Let other modules act on updating the object. + _field_invoke('update', $obj_type, $object); + + // Let other modules act on updating the object, accumulating saved + // fields along the way. + $saved = array(); foreach (module_implements('field_attach_update') as $module) { $function = $module . '_field_attach_update'; $function($output, $obj_type, $object); } - _field_invoke('update', $obj_type, $object); - module_invoke(variable_get('field_storage_module', 'field_sql_storage'), 'field_storage_write', $obj_type, $object, TRUE); + // Field storage module saves any remaining unsaved fields. + module_invoke(variable_get('field_storage_module', 'field_sql_storage'), 'field_storage_write', $obj_type, $object, TRUE, $saved); list($id, $vid, $bundle, $cacheable) = field_attach_extract_ids($obj_type, $object); if ($cacheable) { @@ -600,7 +618,7 @@ function _field_attach_delete_bundle($bu /** * Helper function to extract id, vid, and bundle name from an object. - * + * * @param $obj_type * The type of $object; e.g. 'node' or 'user'. * @param $object === modified file 'modules/field/field.crud.inc' --- modules/field/field.crud.inc 2009-02-05 03:42:56 +0000 +++ modules/field/field.crud.inc 2009-02-05 16:08:57 +0000 @@ -329,10 +329,11 @@ function field_create_instance($instance _field_write_instance($instance); - module_invoke_all('field_create_instance', $instance); - // Clear caches field_cache_clear(); + + module_invoke_all('field_create_instance', $instance); + return FALSE; } @@ -555,4 +556,4 @@ function field_delete_instance($field_na /** * @} End of "defgroup field_crud". - */ \ No newline at end of file + */ === modified file 'modules/field/modules/field_sql_storage/field_sql_storage.module' --- modules/field/modules/field_sql_storage/field_sql_storage.module 2009-02-05 03:42:56 +0000 +++ modules/field/modules/field_sql_storage/field_sql_storage.module 2009-02-05 16:08:57 +0000 @@ -179,11 +179,14 @@ function field_sql_storage_field_storage * FIELD_LOAD_CURRENT to load the most recent revision for all * fields, or FIELD_LOAD_REVISION to load the version indicated by * each object. + * @param $skip_fields + * An array of field names for which data has already been loaded + * and so should not be loaded by this function. * @return * An array of field data for the objects, keyed by entity id, field * name, and item delta number. */ -function field_sql_storage_field_storage_load($obj_type, $objects, $age) { +function field_sql_storage_field_storage_load($obj_type, $objects, $age, $skip_fields = array()) { $etid = _field_sql_storage_etid($obj_type); $load_current = $age == FIELD_LOAD_CURRENT; @@ -200,6 +203,10 @@ function field_sql_storage_field_storage $additions = array(); foreach ($field_ids as $field_name => $ids) { + if (isset($skip_fields[$field_name])) { + continue; + } + $field = field_info_field($field_name); $table = $load_current ? _field_sql_storage_tablename($field_name) : _field_sql_storage_revision_tablename($field_name); @@ -229,13 +236,16 @@ function field_sql_storage_field_storage return $additions; } -function field_sql_storage_field_storage_write($obj_type, $object, $update = FALSE) { +function field_sql_storage_field_storage_write($obj_type, $object, $update = FALSE, $skip_fields = array()) { list($id, $vid, $bundle) = field_attach_extract_ids($obj_type, $object); $etid = _field_sql_storage_etid($obj_type); $instances = field_info_instances($bundle); foreach ($instances as $instance) { $field_name = $instance['field_name']; + if (isset($skip_fields[$field_name])) { + continue; + } $table_name = _field_sql_storage_tablename($field_name); $revision_name = _field_sql_storage_revision_tablename($field_name); $field = field_read_field($field_name); @@ -385,4 +395,4 @@ function field_sql_storage_field_storage ->condition('bundle', $bundle_old) ->execute(); } -} \ No newline at end of file +} === modified file 'modules/simpletest/drupal_web_test_case.php' --- modules/simpletest/drupal_web_test_case.php 2009-02-03 17:30:10 +0000 +++ modules/simpletest/drupal_web_test_case.php 2009-02-05 16:08:57 +0000 @@ -928,6 +928,9 @@ class DrupalWebTestCase { module_list(TRUE); module_implements(MODULE_IMPLEMENTS_CLEAR_CACHE); + // Reset the Field API. + field_cache_clear(); + // Rebuild caches. $this->refreshVariables();