summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAngie Byron <webchick@24967.no-reply.drupal.org>2009-10-16 03:21:23 +0000
committerAngie Byron <webchick@24967.no-reply.drupal.org>2009-10-16 03:21:23 +0000
commit087a47ba5c8cdf5b0f79d9a121b7b9dcbbe7e992 (patch)
treeb223ccb070c29008ef9098484bb44894c2f53410
parent13d3072f418835569f37f65b5055e5b3180fad2e (diff)
downloadbrdo-087a47ba5c8cdf5b0f79d9a121b7b9dcbbe7e992.tar.gz
brdo-087a47ba5c8cdf5b0f79d9a121b7b9dcbbe7e992.tar.bz2
#493314 by yched and catch: Add multiple hook for formatters.
-rw-r--r--modules/comment/comment.module3
-rw-r--r--modules/field/field.api.php70
-rw-r--r--modules/field/field.attach.inc7
-rw-r--r--modules/field/field.default.inc24
-rw-r--r--modules/field/field.test39
-rw-r--r--modules/node/node.module3
-rw-r--r--modules/node/node.pages.inc2
-rw-r--r--modules/simpletest/tests/field_test.module40
-rw-r--r--modules/taxonomy/taxonomy.module2
-rw-r--r--modules/taxonomy/taxonomy.pages.inc1
-rw-r--r--modules/taxonomy/taxonomy.test2
-rw-r--r--modules/user/user.module3
12 files changed, 188 insertions, 8 deletions
diff --git a/modules/comment/comment.module b/modules/comment/comment.module
index 87ef24c0a..db36e0a7a 100644
--- a/modules/comment/comment.module
+++ b/modules/comment/comment.module
@@ -844,6 +844,7 @@ function comment_build_content($comment, $node, $build_mode = 'full') {
'#markup' => check_markup($comment->comment, $comment->format, '', TRUE),
);
+ field_attach_prepare_view('comment', array($comment->cid => $comment), $build_mode);
$comment->content += field_attach_view('comment', $comment, $build_mode);
if (empty($comment->in_preview)) {
@@ -937,6 +938,8 @@ function comment_links($comment, $node) {
* An array in the format expected by drupal_render().
*/
function comment_build_multiple($comments, $node, $build_mode = 'full', $weight = 0) {
+ field_attach_prepare_view('comment', $comments, $build_mode);
+
$build = array(
'#sorted' => TRUE,
);
diff --git a/modules/field/field.api.php b/modules/field/field.api.php
index ee80409a8..3728ba226 100644
--- a/modules/field/field.api.php
+++ b/modules/field/field.api.php
@@ -248,8 +248,11 @@ function hook_field_schema($field) {
* For performance reasons, information for all available objects should be
* loaded in a single query where possible.
*
- * Note that the changes made to the field values get cached by the
- * field cache for subsequent loads.
+ * Note that the changes made to the field values get cached by the field cache
+ * for subsequent loads. You should never use this hook to load fieldable
+ * entities, since this is likely to cause infinite recursions when
+ * hook_field_load() is run on those as well. Use
+ * hook_field_formatter_prepare_view() instead.
*
* @param $obj_type
* The type of $object.
@@ -826,6 +829,34 @@ function theme_field_formatter_FORMATTER_MULTIPLE($variables) {
}
/**
+ * Allow formatters to load information for multiple objects.
+ *
+ * This should be used when a formatter needs to load additional information
+ * from the database in order to render a field, for example a reference field
+ * which displays properties of the referenced objects such as name or type.
+ *
+ * @param $obj_type
+ * The type of $object.
+ * @param $objects
+ * Array of objects being displayed, keyed by object id.
+ * @param $field
+ * The field structure for the operation.
+ * @param $instances
+ * Array of instance structures for $field for each object, keyed by object id.
+ * @param $langcode
+ * The language the field values are to be shown in. If no language is
+ * provided the current language is used.
+ * @param $items
+ * Array of field values for the objects, keyed by object id.
+ * @return
+ * Changes or additions to field values are done by altering the $items
+ * parameter by reference.
+ */
+function hook_field_formatter_prepare_view($obj_type, $objects, $field, $instances, $langcode, &$items, $build_mode) {
+
+}
+
+/**
* @} End of "ingroup field_type"
*/
@@ -842,6 +873,41 @@ function theme_field_formatter_FORMATTER_MULTIPLE($variables) {
* See field_attach_form() for details and arguments.
*/
function hook_field_attach_form($obj_type, $object, &$form, &$form_state, $langcode) {
+ $tids = array();
+
+ // Collect every possible term attached to any of the fieldable entities.
+ foreach ($objects as $id => $object) {
+ foreach ($items[$id] as $delta => $item) {
+ // Force the array key to prevent duplicates.
+ $tids[$item['value']] = $item['value'];
+ }
+ }
+ if ($tids) {
+ $terms = array();
+
+ // Avoid calling taxonomy_term_load_multiple because it could lead to
+ // circular references.
+ $query = db_select('taxonomy_term_data', 't');
+ $query->fields('t');
+ $query->condition('t.tid', $tids, 'IN');
+ $query->addTag('term_access');
+ $terms = $query->execute()->fetchAllAssoc('tid');
+
+ // Iterate through the fieldable entities again to attach the loaded term data.
+ foreach ($objects as $id => $object) {
+ foreach ($items[$id] as $delta => $item) {
+ // Check whether the taxonomy term field instance value could be loaded.
+ if (isset($terms[$item['value']])) {
+ // Replace the instance value with the term data.
+ $items[$id][$delta]['taxonomy_term'] = $terms[$item['value']];
+ }
+ // Otherwise, unset the instance value, since the term does not exist.
+ else {
+ unset($items[$id][$delta]);
+ }
+ }
+ }
+ }
}
/**
diff --git a/modules/field/field.attach.inc b/modules/field/field.attach.inc
index 2bf38e457..3630ea40d 100644
--- a/modules/field/field.attach.inc
+++ b/modules/field/field.attach.inc
@@ -1110,6 +1110,13 @@ function field_attach_query_revisions($field_id, $conditions, $count, &$cursor =
}
/**
+ * Allow formatters to act on fieldable objects prior to rendering.
+ */
+function field_attach_prepare_view($obj_type, $objects, $build_mode = 'full') {
+ _field_invoke_multiple_default('prepare_view', $obj_type, $objects, $build_mode);
+}
+
+/**
* Generate and return a structured content array tree suitable for
* drupal_render() for all of the fields on an object. The format of
* each field's rendered content depends on the display formatter and
diff --git a/modules/field/field.default.inc b/modules/field/field.default.inc
index 31d5732c4..fc7c40e40 100644
--- a/modules/field/field.default.inc
+++ b/modules/field/field.default.inc
@@ -54,6 +54,30 @@ function field_default_insert($obj_type, $object, $field, $instance, $langcode,
}
/**
+ * Invoke hook_field_formatter_prepare_view() on the relavant formatters.
+ */
+function field_default_prepare_view($obj_type, $objects, $field, $instances, $langcode, &$items, $options, $build_mode) {
+ // Group objects, instances and items by formatter module.
+ $modules = array();
+ foreach ($instances as $id => $instance) {
+ $module = $instance['display'][$build_mode]['module'];
+ $modules[$module] = $module;
+ $grouped_objects[$module][$id] = $objects[$id];
+ $grouped_instances[$module][$id] = $instance;
+ // hook_field_formatter_prepare_view() alters $items by reference.
+ $grouped_items[$module][$id] = &$items[$id];
+ }
+
+ foreach ($modules as $module) {
+ // Invoke hook_field_formatter_prepare_view().
+ $function = $module . '_field_formatter_prepare_view';
+ if (function_exists($function)) {
+ $function($obj_type, $grouped_objects[$module], $field, $grouped_instances[$module], $langcode, $grouped_items[$module], $build_mode);
+ }
+ }
+}
+
+/**
* Default field 'view' operation.
*
* @see field_attach_view()
diff --git a/modules/field/field.test b/modules/field/field.test
index 999c74ffa..86983e35b 100644
--- a/modules/field/field.test
+++ b/modules/field/field.test
@@ -786,18 +786,19 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
}
/**
- * Test field_attach_views() and field_attach_preprocess().
+ * Test field_attach_view() and field_atach_prepare_view().
*/
- function testFieldAttachViewAndPreprocess() {
+ function testFieldAttachView() {
$entity_type = 'test_entity';
- $entity = field_test_create_stub_entity(0, 0, $this->instance['bundle']);
+ $entity_init = field_test_create_stub_entity();
$langcode = FIELD_LANGUAGE_NONE;
// Populate values to be displayed.
$values = $this->_generateTestFieldValues($this->field['cardinality']);
- $entity->{$this->field_name}[$langcode] = $values;
+ $entity_init->{$this->field_name}[$langcode] = $values;
// Simple formatter, label displayed.
+ $entity = clone($entity_init);
$formatter_setting = $this->randomName();
$this->instance['display'] = array(
'full' => array(
@@ -809,6 +810,7 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
),
);
field_update_instance($this->instance);
+ field_attach_prepare_view($entity_type, array($entity->ftid => $entity));
$entity->content = field_attach_view($entity_type, $entity);
$output = drupal_render($entity->content);
$this->content = $output;
@@ -819,14 +821,17 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
}
// Label hidden.
+ $entity = clone($entity_init);
$this->instance['display']['full']['label'] = 'hidden';
field_update_instance($this->instance);
+ field_attach_prepare_view($entity_type, array($entity->ftid => $entity));
$entity->content = field_attach_view($entity_type, $entity);
$output = drupal_render($entity->content);
$this->content = $output;
$this->assertNoRaw($this->instance['label'], "Hidden label: label is not displayed.");
// Field hidden.
+ $entity = clone($entity_init);
$this->instance['display'] = array(
'full' => array(
'label' => 'above',
@@ -834,6 +839,7 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
),
);
field_update_instance($this->instance);
+ field_attach_prepare_view($entity_type, array($entity->ftid => $entity));
$entity->content = field_attach_view($entity_type, $entity);
$output = drupal_render($entity->content);
$this->content = $output;
@@ -843,6 +849,7 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
}
// Multiple formatter.
+ $entity = clone($entity_init);
$formatter_setting = $this->randomName();
$this->instance['display'] = array(
'full' => array(
@@ -854,6 +861,7 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
),
);
field_update_instance($this->instance);
+ field_attach_prepare_view($entity_type, array($entity->ftid => $entity));
$entity->content = field_attach_view($entity_type, $entity);
$output = drupal_render($entity->content);
$display = $formatter_setting;
@@ -863,6 +871,29 @@ class FieldAttachOtherTestCase extends FieldAttachTestCase {
$this->content = $output;
$this->assertRaw($display, "Multiple formatter: all values are displayed, formatter settings are applied.");
+ // Test a formatter that uses hook_field_formatter_prepare_view()..
+ $entity = clone($entity_init);
+ $formatter_setting = $this->randomName();
+ $this->instance['display'] = array(
+ 'full' => array(
+ 'label' => 'above',
+ 'type' => 'field_test_needs_additional_data',
+ 'settings' => array(
+ 'test_formatter_setting_additional' => $formatter_setting,
+ )
+ ),
+ );
+ field_update_instance($this->instance);
+ field_attach_prepare_view($entity_type, array($entity->ftid => $entity));
+ $entity->content = field_attach_view($entity_type, $entity);
+ $output = drupal_render($entity->content);
+ $this->content = $output;
+ foreach ($values as $delta => $value) {
+ $this->content = $output;
+ $expected = $formatter_setting . '|' . $value['value'] . '|' . ($value['value'] + 1);
+ $this->assertRaw($expected, "Value $delta is displayed, formatter settings are applied.");
+ }
+
// TODO:
// - check display order with several fields
diff --git a/modules/node/node.module b/modules/node/node.module
index 0d7940a5e..038a0a175 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -1241,7 +1241,7 @@ function node_show($node, $message = FALSE) {
node_tag_new($node->nid);
// For markup consistency with other pages, use node_build_multiple() rather than node_build().
- return node_build_multiple(array($node), 'full');
+ return node_build_multiple(array($node->nid => $node), 'full');
}
/**
@@ -2034,6 +2034,7 @@ function node_feed($nids = FALSE, $channel = array()) {
* An array in the format expected by drupal_render().
*/
function node_build_multiple($nodes, $build_mode = 'teaser', $weight = 0) {
+ field_attach_prepare_view('node', $nodes, $build_mode);
$build = array();
foreach ($nodes as $node) {
$build['nodes'][$node->nid] = node_build($node, $build_mode);
diff --git a/modules/node/node.pages.inc b/modules/node/node.pages.inc
index b9cedaeb1..3ecdaf2a5 100644
--- a/modules/node/node.pages.inc
+++ b/modules/node/node.pages.inc
@@ -355,6 +355,8 @@ function node_preview($node) {
}
$node->changed = REQUEST_TIME;
+ $nodes = array($node->nid => $node);
+ field_attach_prepare_view('node', $nodes, 'full');
// Display a preview of the node.
// Previewing alters $node so it needs to be cloned.
diff --git a/modules/simpletest/tests/field_test.module b/modules/simpletest/tests/field_test.module
index 8cc99b1e9..8bb504389 100644
--- a/modules/simpletest/tests/field_test.module
+++ b/modules/simpletest/tests/field_test.module
@@ -564,6 +564,13 @@ function field_test_field_formatter_info() {
'multiple values' => FIELD_BEHAVIOR_CUSTOM,
),
),
+ 'field_test_needs_additional_data' => array(
+ 'label' => t('Tests hook_field_formatter_prepare_view()'),
+ 'field types' => array('test_field'),
+ 'settings' => array(
+ 'test_formatter_setting_additional' => 'dummy test string',
+ ),
+ ),
);
}
@@ -578,10 +585,31 @@ function field_test_theme() {
'field_formatter_field_test_multiple' => array(
'arguments' => array('element' => NULL),
),
+ 'field_formatter_field_test_needs_additional_data' => array(
+ 'arguments' => array('element' => NULL),
+ ),
);
}
/**
+ * Implement hook_field_formatter_prepare_view().
+ */
+function field_test_field_formatter_prepare_view($obj_type, $objects, $field, $instances, $langcode, &$items, $build_mode) {
+ foreach ($items as $id => $item) {
+ // To keep the test non-intrusive, only act on the
+ // 'field_test_needs_additional_data' formatter.
+ if ($instances[$id]['display'][$build_mode]['type'] == 'field_test_needs_additional_data') {
+ foreach ($item as $delta => $value) {
+ // Don't add anything on empty values.
+ if ($value) {
+ $items[$id][$delta]['additional_formatter_value'] = $value['value'] + 1;
+ }
+ }
+ }
+ }
+}
+
+/**
* Theme function for 'field_test_default' formatter.
*/
function theme_field_formatter_field_test_default($variables) {
@@ -610,6 +638,18 @@ function theme_field_formatter_field_test_multiple($variables) {
}
/**
+ * Theme function for 'field_test_needs_additional_data' formatter.
+ */
+function theme_field_formatter_field_test_needs_additional_data($variables) {
+ $element = $variables['element'];
+ $value = $element['#item']['value'];
+ $additional = $element['#item']['additional_formatter_value'];
+ $settings = $element['#settings'];
+
+ return $settings['test_formatter_setting_additional'] . '|' . $value . '|' . $additional;
+}
+
+/**
* Sample function to test default value assignment.
*/
function field_test_default_value($obj_type, $object, $field, $instance) {
diff --git a/modules/taxonomy/taxonomy.module b/modules/taxonomy/taxonomy.module
index 6fe12b689..88d00f546 100644
--- a/modules/taxonomy/taxonomy.module
+++ b/modules/taxonomy/taxonomy.module
@@ -1131,7 +1131,7 @@ function taxonomy_allowed_values($field) {
* This preloads all taxonomy terms for multiple loaded objects at once and
* unsets values for invalid terms that do not exist.
*/
-function taxonomy_field_load($obj_type, $objects, $field, $instances, $langcode, &$items, $age) {
+function taxonomy_field_formatter_prepare_view($obj_type, $objects, $field, $instances, $langcode, &$items, $age) {
$tids = array();
// Collect every possible term attached to any of the fieldable entities.
diff --git a/modules/taxonomy/taxonomy.pages.inc b/modules/taxonomy/taxonomy.pages.inc
index b3a2c941a..c62f6e00c 100644
--- a/modules/taxonomy/taxonomy.pages.inc
+++ b/modules/taxonomy/taxonomy.pages.inc
@@ -30,6 +30,7 @@ function taxonomy_term_page($term) {
drupal_add_feed(url('taxonomy/term/' . $term->tid . '/feed'), 'RSS - ' . $term->name);
drupal_add_css(drupal_get_path('module', 'taxonomy') . '/taxonomy.css');
+ field_attach_prepare_view('taxonomy_term', array($term->tid => $term), 'full');
$build = array();
$build += field_attach_view('taxonomy_term', $term);
if (!empty($term->description)) {
diff --git a/modules/taxonomy/taxonomy.test b/modules/taxonomy/taxonomy.test
index f0ec295af..36fbcabec 100644
--- a/modules/taxonomy/taxonomy.test
+++ b/modules/taxonomy/taxonomy.test
@@ -758,6 +758,8 @@ class TaxonomyTermFieldTestCase extends TaxonomyWebTestCase {
// Display the object.
$entity = field_test_entity_load($id);
+ $entities = array($id => $entity);
+ field_attach_prepare_view($entity_type, $entities, 'full');
$entity->content = field_attach_view($entity_type, $entity);
$this->content = drupal_render($entity->content);
$this->assertText($term->name, t('Term name is displayed'));
diff --git a/modules/user/user.module b/modules/user/user.module
index 8e23ba165..ca787e054 100644
--- a/modules/user/user.module
+++ b/modules/user/user.module
@@ -2102,6 +2102,9 @@ function user_build($account) {
function user_build_content($account) {
$account->content = array();
+ $accounts = array($account->uid, $account);
+ field_attach_prepare_view('user', $accounts, 'full');
+
// Build fields content.
$account->content += field_attach_view('user', $account);