diff options
Diffstat (limited to 'modules/field/field.attach.inc')
-rw-r--r-- | modules/field/field.attach.inc | 160 |
1 files changed, 129 insertions, 31 deletions
diff --git a/modules/field/field.attach.inc b/modules/field/field.attach.inc index 7571ee4fc..e2726a776 100644 --- a/modules/field/field.attach.inc +++ b/modules/field/field.attach.inc @@ -44,17 +44,16 @@ class FieldQueryException extends FieldException {} * @{ * Implement a storage engine for Field API data. * - * The Field Attach API uses the Field Storage API to perform all - * "database access". Each Field Storage API hook function defines a - * primitive database operation such as read, write, or delete. The - * default field storage module, field_sql_storage.module, uses the - * local SQL database to implement these operations, but alternative - * field storage engines can choose to represent the data in SQL - * differently or use a completely different storage mechanism such as - * a cloud-based database. + * The Field Attach API uses the Field Storage API to perform all "database + * access". Each Field Storage API hook function defines a primitive database + * operation such as read, write, or delete. The default field storage module, + * field_sql_storage.module, uses the local SQL database to implement these + * operations, but alternative field storage backends can choose to represent + * the data in SQL differently or use a completely different storage mechanism + * such as a cloud-based database. * - * The Drupal system variable field_storage_module identifies the - * field storage module to use. + * Each field defines which storage backend it uses. The Drupal system variable + * 'field_default_storage' identifies the storage backend used by default. */ /** @@ -525,9 +524,8 @@ function field_attach_form($obj_type, $object, &$form, &$form_state, $langcode = * - 'deleted': If TRUE, the function will operate on deleted fields * as well as non-deleted fields. If unset or FALSE, only * non-deleted fields are operated on. - * @returns - * Loaded field values are added to $objects. Fields with no values should be - * set as an empty array. + * @return + * Loaded field values are added to $objects. */ function field_attach_load($obj_type, $objects, $age = FIELD_LOAD_CURRENT, $options = array()) { $load_current = $age == FIELD_LOAD_CURRENT; @@ -578,7 +576,7 @@ function field_attach_load($obj_type, $objects, $age = FIELD_LOAD_CURRENT, $opti if ($queried_objects) { // The invoke order is: // - hook_field_attach_pre_load() - // - storage engine's hook_field_storage_load() + // - storage backend's hook_field_storage_load() // - field-type module's hook_field_load() // - hook_field_attach_load() @@ -590,9 +588,39 @@ function field_attach_load($obj_type, $objects, $age = FIELD_LOAD_CURRENT, $opti $function($obj_type, $queried_objects, $age, $skip_fields, $options); } - // Invoke the storage engine's hook_field_storage_load(): the field storage - // engine loads the rest. - module_invoke(variable_get('field_storage_module', 'field_sql_storage'), 'field_storage_load', $obj_type, $queried_objects, $age, $skip_fields, $options); + // Collect the storage backends used by the remaining fields in the objects. + $storages = array(); + foreach ($queried_objects as $obj) { + list($id, $vid, $bundle) = field_extract_ids($obj_type, $obj); + if ($options['deleted']) { + $instances = field_read_instances(array('bundle' => $bundle), array('include_deleted' => $options['deleted'])); + } + else { + $instances = field_info_instances($bundle); + } + + foreach ($instances as $instance) { + if (!isset($options['field_id']) || $options['field_id'] == $instance['field_id']) { + $field_name = $instance['field_name']; + $field_id = $instance['field_id']; + // Make sure all fields are present at least as empty arrays. + if (!isset($queried_objects[$id]->{$field_name})) { + $queried_objects[$id]->{$field_name} = array(); + } + // Collect the storage backend if the field has not been loaded yet. + if (!isset($skip_fields[$field_id])) { + $field = field_info_field_by_id($field_id); + $storages[$field['storage']['type']][$field_id][] = $load_current ? $id : $vid; + } + } + } + } + + // Invoke hook_field_storage_load() on the relevant storage backends. + foreach ($storages as $storage => $fields) { + $storage_info = field_info_storage_types($storage); + module_invoke($storage_info['module'], 'field_storage_load', $obj_type, $queried_objects, $age, $fields, $options); + } // Invoke field-type module's hook_field_load(). _field_invoke_multiple('load', $obj_type, $queried_objects, $age, $options); @@ -791,6 +819,8 @@ function field_attach_insert($obj_type, $object) { _field_invoke_default('insert', $obj_type, $object); _field_invoke('insert', $obj_type, $object); + list($id, $vid, $bundle, $cacheable) = field_extract_ids($obj_type, $object); + // Let other modules act on inserting the object, accumulating saved // fields along the way. $skip_fields = array(); @@ -799,10 +829,26 @@ function field_attach_insert($obj_type, $object) { $function($obj_type, $object, $skip_fields); } - // Field storage module saves any remaining unsaved fields. - module_invoke(variable_get('field_storage_module', 'field_sql_storage'), 'field_storage_write', $obj_type, $object, FIELD_STORAGE_INSERT, $skip_fields); + // Collect the storage backends used by the remaining fields in the objects. + $storages = array(); + foreach (field_info_instances($bundle) as $instance) { + $field = field_info_field_by_id($instance['field_id']); + $field_id = $field['id']; + $field_name = $field['field_name']; + if (!empty($object->$field_name)) { + // Collect the storage backend if the field has not been written yet. + if (!isset($skip_fields[$field_id])) { + $storages[$field['storage']['type']][$field_id] = $field_id; + } + } + } + + // Field storage backends save any remaining unsaved fields. + foreach ($storages as $storage => $fields) { + $storage_info = field_info_storage_types($storage); + module_invoke($storage_info['module'], 'field_storage_write', $obj_type, $object, FIELD_STORAGE_INSERT, $fields); + } - list($id, $vid, $bundle, $cacheable) = field_extract_ids($obj_type, $object); if ($cacheable) { cache_clear_all("field:$obj_type:$id", 'cache_field'); } @@ -819,6 +865,8 @@ function field_attach_insert($obj_type, $object) { function field_attach_update($obj_type, $object) { _field_invoke('update', $obj_type, $object); + list($id, $vid, $bundle, $cacheable) = field_extract_ids($obj_type, $object); + // Let other modules act on updating the object, accumulating saved // fields along the way. $skip_fields = array(); @@ -827,10 +875,30 @@ function field_attach_update($obj_type, $object) { $function($obj_type, $object, $skip_fields); } - // Field storage module saves any remaining unsaved fields. - module_invoke(variable_get('field_storage_module', 'field_sql_storage'), 'field_storage_write', $obj_type, $object, FIELD_STORAGE_UPDATE, $skip_fields); + // Collect the storage backends used by the remaining fields in the objects. + $storages = array(); + foreach (field_info_instances($bundle) as $instance) { + $field = field_info_field_by_id($instance['field_id']); + $field_id = $field['id']; + $field_name = $field['field_name']; + // Leave the field untouched if $object comes with no $field_name property, + // but empty the field if it comes as a NULL value or an empty array. + // Function property_exists() is slower, so we catch the more frequent + // cases where it's an empty array with the faster isset(). + if (isset($object->$field_name) || property_exists($object, $field_name)) { + // Collect the storage backend if the field has not been written yet. + if (!isset($skip_fields[$field_id])) { + $storages[$field['storage']['type']][$field_id] = $field_id; + } + } + } + + // Field storage backends save any remaining unsaved fields. + foreach ($storages as $storage => $fields) { + $storage_info = field_info_storage_types($storage); + module_invoke($storage_info['module'], 'field_storage_write', $obj_type, $object, FIELD_STORAGE_UPDATE, $fields); + } - list($id, $vid, $bundle, $cacheable) = field_extract_ids($obj_type, $object); if ($cacheable) { cache_clear_all("field:$obj_type:$id", 'cache_field'); } @@ -847,7 +915,22 @@ function field_attach_update($obj_type, $object) { */ function field_attach_delete($obj_type, $object) { _field_invoke('delete', $obj_type, $object); - module_invoke(variable_get('field_storage_module', 'field_sql_storage'), 'field_storage_delete', $obj_type, $object); + + list($id, $vid, $bundle, $cacheable) = field_extract_ids($obj_type, $object); + + // Collect the storage backends used by the fields in the objects. + $storages = array(); + foreach (field_info_instances($bundle) as $instance) { + $field = field_info_field_by_id($instance['field_id']); + $field_id = $field['id']; + $storages[$field['storage']['type']][$field_id] = $field_id; + } + + // Field storage backends delete their data. + foreach ($storages as $storage => $fields) { + $storage_info = field_info_storage_types($storage); + module_invoke($storage_info['module'], 'field_storage_delete', $obj_type, $object, $fields); + } // Let other modules act on deleting the object. foreach (module_implements('field_attach_delete') as $module) { @@ -855,7 +938,6 @@ function field_attach_delete($obj_type, $object) { $function($obj_type, $object); } - list($id, $vid, $bundle, $cacheable) = field_extract_ids($obj_type, $object); if ($cacheable) { cache_clear_all("field:$obj_type:$id", 'cache_field'); } @@ -872,7 +954,22 @@ function field_attach_delete($obj_type, $object) { */ function field_attach_delete_revision($obj_type, $object) { _field_invoke('delete_revision', $obj_type, $object); - module_invoke(variable_get('field_storage_module', 'field_sql_storage'), 'field_storage_delete_revision', $obj_type, $object); + + list($id, $vid, $bundle, $cacheable) = field_extract_ids($obj_type, $object); + + // Collect the storage backends used by the fields in the objects. + $storages = array(); + foreach (field_info_instances($bundle) as $instance) { + $field = field_info_field_by_id($instance['field_id']); + $field_id = $field['id']; + $storages[$field['storage']['type']][$field_id] = $field_id; + } + + // Field storage backends delete their data. + foreach ($storages as $storage => $fields) { + $storage_info = field_info_storage_types($storage); + module_invoke($storage_info['module'], 'field_storage_delete_revision', $obj_type, $object, $fields); + } // Let other modules act on deleting the revision. foreach (module_implements('field_attach_delete_revision') as $module) { @@ -977,7 +1074,8 @@ function field_attach_query($field_id, $conditions, $count, &$cursor = NULL, $ag } // If the request hasn't been handled, let the storage engine handle it. if (!$skip_field) { - $function = variable_get('field_storage_module', 'field_sql_storage') . '_field_storage_query'; + $field = field_info_field_by_id($field_id); + $function = $field['storage']['module'] . '_field_storage_query'; $results = $function($field_id, $conditions, $count, $cursor, $age); } @@ -1194,8 +1292,6 @@ function field_attach_prepare_translation($node) { * The name of the newly created bundle. */ function field_attach_create_bundle($bundle) { - module_invoke(variable_get('field_storage_module', 'field_sql_storage'), 'field_storage_create_bundle', $bundle); - // Clear the cache. field_cache_clear(); @@ -1214,7 +1310,6 @@ function field_attach_create_bundle($bundle) { * The new name of the bundle. */ function field_attach_rename_bundle($bundle_old, $bundle_new) { - module_invoke(variable_get('field_storage_module', 'field_sql_storage'), 'field_storage_rename_bundle', $bundle_old, $bundle_new); db_update('field_config_instance') ->fields(array('bundle' => $bundle_new)) ->condition('bundle', $bundle_old) @@ -1243,12 +1338,15 @@ function field_attach_rename_bundle($bundle_old, $bundle_new) { * The bundle to delete. */ function field_attach_delete_bundle($bundle) { - // Delete the instances themseves + // First, delete the instances themseves. $instances = field_info_instances($bundle); foreach ($instances as $instance) { field_delete_instance($instance['field_name'], $bundle); } + // Clear the cache. + field_cache_clear(); + // Let other modules act on deleting the bundle. foreach (module_implements('field_attach_delete_bundle') as $module) { $function = $module . '_field_attach_delete_bundle'; |