diff options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/comment/comment.module | 3 | ||||
-rw-r--r-- | modules/field/field.api.php | 70 | ||||
-rw-r--r-- | modules/field/field.attach.inc | 7 | ||||
-rw-r--r-- | modules/field/field.default.inc | 24 | ||||
-rw-r--r-- | modules/field/field.test | 39 | ||||
-rw-r--r-- | modules/node/node.module | 3 | ||||
-rw-r--r-- | modules/node/node.pages.inc | 2 | ||||
-rw-r--r-- | modules/simpletest/tests/field_test.module | 40 | ||||
-rw-r--r-- | modules/taxonomy/taxonomy.module | 2 | ||||
-rw-r--r-- | modules/taxonomy/taxonomy.pages.inc | 1 | ||||
-rw-r--r-- | modules/taxonomy/taxonomy.test | 2 | ||||
-rw-r--r-- | modules/user/user.module | 3 |
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); |