summaryrefslogtreecommitdiff
path: root/modules/field/field.attach.inc
diff options
context:
space:
mode:
Diffstat (limited to 'modules/field/field.attach.inc')
-rw-r--r--modules/field/field.attach.inc160
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';