summaryrefslogtreecommitdiff
path: root/modules/field/field.attach.inc
diff options
context:
space:
mode:
authorAngie Byron <webchick@24967.no-reply.drupal.org>2009-03-30 03:44:55 +0000
committerAngie Byron <webchick@24967.no-reply.drupal.org>2009-03-30 03:44:55 +0000
commitfbabc0d98553d136f54073dc1624310bd07e11dc (patch)
treefdafeda88d090a9ad65d851b007688f8c4dd7d42 /modules/field/field.attach.inc
parent28aaa036e471a5d96be3938545c49e2dc71e342e (diff)
downloadbrdo-fbabc0d98553d136f54073dc1624310bd07e11dc.tar.gz
brdo-fbabc0d98553d136f54073dc1624310bd07e11dc.tar.bz2
#368674 by bjaspan, Eaton, chx, and yched: Provide hooks to allow hybrid field/bundle-level storage for fields in core.
Diffstat (limited to 'modules/field/field.attach.inc')
-rw-r--r--modules/field/field.attach.inc105
1 files changed, 80 insertions, 25 deletions
diff --git a/modules/field/field.attach.inc b/modules/field/field.attach.inc
index d52f9db2a..2b05937f4 100644
--- a/modules/field/field.attach.inc
+++ b/modules/field/field.attach.inc
@@ -94,16 +94,33 @@ define('FIELD_STORAGE_INSERT', 'insert');
*
* Fieldable types call Field Attach API functions during their own
* API calls; for example, node_load() calls field_attach_load(). A
- * fieldable type may is not required to use all of the Field Attach
+ * fieldable type is not required to use all of the Field Attach
* API functions.
*
* Most Field Attach API functions define a corresponding hook
* function that allows any module to act on Field Attach operations
- * for any object, and access or modify all the field, form, or
- * display data for that object and operation. These all-module hooks
- * are distinct from those of the Field Types API, such as
- * hook_field_load(), that are only invoked for the module that
- * defines a specific field type.
+ * for any object after the operation is complete, and access or
+ * modify all the field, form, or display data for that object and
+ * operation. For example, field_attach_view() invokes
+ * hook_field_attach_view(). These all-module hooks are distinct from
+ * those of the Field Types API, such as hook_field_load(), that are
+ * only invoked for the module that defines a specific field type.
+ *
+ * field_attach_load(), field_attach_insert(), and
+ * field_attach_update() also define pre-operation hooks,
+ * e.g. hook_field_attach_pre_load(). These hooks run before the
+ * corresponding Field Storage API and Field Type API operations.
+ * They allow modules to define additional storage locations
+ * (e.g. denormalizing, mirroring) for field data on a per-field
+ * basis. They also allow modules to take over field storage
+ * completely by instructing other implementations of the same hook
+ * and the Field Storage API itself not to operate on specified
+ * fields.
+ *
+ * The pre-operation hooks do not make the Field Storage API
+ * irrelevant. The Field Storage API is essentially the "fallback
+ * mechanism" for any fields that aren't being intercepted explicitly
+ * by pre-operation hooks.
*/
/**
@@ -241,7 +258,7 @@ function _field_attach_form($obj_type, $object, &$form, $form_state) {
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";
@@ -254,17 +271,45 @@ function _field_attach_load($obj_type, $objects, $age = FIELD_LOAD_CURRENT) {
$queried_objects[$id] = $objects[$id];
}
}
- // Fetch other nodes from the database.
+
+ // Fetch other objects from the database.
if ($queried_objects) {
- // 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);
+ // The loading order is:
+ // - hook_field_attach_pre_load()
+ // - storage engine's hook_field_storage_load()
+ // - field-type modules hook_field_load()
+ // - hook_field_attach_load()
+ // We need the raw additions to be able to cache them, so the hooks must
+ // not alter objects directly but return their additions. At each step,
+ // results are merged into the $queried_objects, and into the $additions
+ // array, that will eventually get cached.
+
+ // Invoke hook_field_attach_pre_load(): let any module load field
+ // data before the storage engine, accumulating along the way.
+ $additions_pre_load = array();
+ $skip_fields = array();
+ foreach (module_implements('field_attach_pre_load') as $module) {
+ $function = $module . '_field_attach_pre_load';
+ $function($obj_type, $queried_objects, $age, $additions_pre_load, $skip_fields);
+ }
+
+ // Invoke the storage engine's hook_field_storage_load(): 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, $skip_fields);
+
+ // First, merge the additions from the storage engine.
foreach ($additions as $id => $obj_additions) {
foreach ($obj_additions as $key => $value) {
$queried_objects[$id]->$key = $value;
}
}
+ // Then, merge the pre_load additions, so that they take precedence.
+ foreach ($additions_pre_load 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
@@ -281,13 +326,15 @@ function _field_attach_load($obj_type, $objects, $age = FIELD_LOAD_CURRENT) {
}
}
+ // Invoke field-type modules hook_field_load().
$custom_additions = _field_invoke('load', $obj_type, $object);
foreach ($custom_additions as $key => $value) {
$queried_objects[$id]->$key = $value;
$additions[$id][$key] = $value;
}
- // Let other modules act on loading the object.
+ // Invoke hook_field_attach_load(): 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.
@@ -464,14 +511,18 @@ function _field_attach_presave($obj_type, &$object) {
*/
function _field_attach_insert($obj_type, &$object) {
- // Let other modules act on inserting the object.
- foreach (module_implements('field_attach_insert') as $module) {
- $function = $module . '_field_attach_insert';
- $function($obj_type, $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_pre_insert') as $module) {
+ $function = $module . '_field_attach_pre_insert';
+ $function($obj_type, $object, $saved);
}
- _field_invoke('insert', $obj_type, $object);
- module_invoke(variable_get('field_storage_module', 'field_sql_storage'), 'field_storage_write', $obj_type, $object, FIELD_STORAGE_INSERT);
+ // 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, $saved);
list($id, $vid, $bundle, $cacheable) = field_attach_extract_ids($obj_type, $object);
if ($cacheable) {
@@ -489,14 +540,18 @@ function _field_attach_insert($obj_type, &$object) {
*/
function _field_attach_update($obj_type, &$object) {
- // Let other modules act on updating the object.
- foreach (module_implements('field_attach_update') as $module) {
- $function = $module . '_field_attach_update';
- $function($output, $obj_type, $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_pre_update') as $module) {
+ $function = $module . '_field_attach_pre_update';
+ $function($obj_type, $object, $saved);
}
- _field_invoke('update', $obj_type, $object);
- module_invoke(variable_get('field_storage_module', 'field_sql_storage'), 'field_storage_write', $obj_type, $object, FIELD_STORAGE_UPDATE);
+ // 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, $saved);
list($id, $vid, $bundle, $cacheable) = field_attach_extract_ids($obj_type, $object);
if ($cacheable) {