? .cache ? .settings Index: modules/field/field.api.php =================================================================== RCS file: /cvs/drupal/drupal/modules/field/field.api.php,v retrieving revision 1.50 diff -u -p -r1.50 field.api.php --- modules/field/field.api.php 12 Nov 2009 21:03:36 -0000 1.50 +++ modules/field/field.api.php 29 Nov 2009 17:35:48 -0000 @@ -866,18 +866,48 @@ function theme_field_formatter_FORMATTER * @param $field * The field structure for the operation. * @param $instances - * Array of instance structures for $field for each object, keyed by object id. + * 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. + * @param $displays + * Array of display settings to use for each object display, 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) { +function hook_field_formatter_prepare_view($obj_type, $objects, $field, $instances, $langcode, &$items, $displays) { + $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['tid']] = $item['tid']; + } + } + if ($tids) { + $terms = taxonomy_term_load_multiple($tids); + + // 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['tid']])) { + // Replace the instance value with the term data. + $items[$id][$delta]['taxonomy_term'] = $terms[$item['tid']]; + } + // Otherwise, unset the instance value, since the term does not exist. + else { + unset($items[$id][$delta]); + } + } + } + } } /** Index: modules/field/field.attach.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/field/field.attach.inc,v retrieving revision 1.59 diff -u -p -r1.59 field.attach.inc --- modules/field/field.attach.inc 8 Nov 2009 19:11:56 -0000 1.59 +++ modules/field/field.attach.inc 29 Nov 2009 17:35:48 -0000 @@ -338,7 +338,7 @@ function _field_invoke_multiple($op, $ob if (function_exists($function)) { // Iterate over all the field translations. foreach ($grouped_items[$field_id] as $langcode => $items) { - $results = $function($obj_type, $grouped_objects[$field_id], $field, $grouped_instances[$field_id], $langcode, $grouped_items[$field_id][$langcode], $options, $a, $b); + $results = $function($obj_type, $grouped_objects[$field_id], $field, $grouped_instances[$field_id], $langcode, $grouped_items[$field_id][$langcode], $a, $b); if (isset($results)) { // Collect results by object. // For hooks with array results, we merge results together. @@ -1195,7 +1195,7 @@ function field_attach_view($obj_type, $o $output['#pre_render'][] = '_field_extra_weights_pre_render'; $output['#extra_fields'] = field_extra_fields($bundle); - // Let other modules make changes after rendering the view. + // Let other modules alter the renderable array. $context = array( 'obj_type' => $obj_type, 'object' => $object, Index: modules/field/field.default.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/field/field.default.inc,v retrieving revision 1.23 diff -u -p -r1.23 field.default.inc --- modules/field/field.default.inc 9 Nov 2009 18:23:41 -0000 1.23 +++ modules/field/field.default.inc 29 Nov 2009 18:02:30 -0000 @@ -55,38 +55,85 @@ function field_default_insert($obj_type, /** * Invoke hook_field_formatter_prepare_view() on the relavant formatters. + * + * @param $obj_type + * The type of $object; e.g. 'node' or 'user'. + * @param $objects + * An 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 associated to $items. + * @param $items + * Array of field values already loaded for the objects, keyed by object id. + * @param $display + * Can be either: + * - the name of a build mode + * - or an array of display settings to use for display, as found in the + * 'display' entry of $instance definitions. */ -function field_default_prepare_view($obj_type, $objects, $field, $instances, $langcode, &$items, $options, $build_mode) { +function field_default_prepare_view($obj_type, $objects, $field, $instances, $langcode, &$items, $display) { // 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]; + $display = is_string($display) ? $instance['display'][$display] : $display; + if ($display['type'] !== 'hidden') { + $module = $display['module']; + $modules[$module] = $module; + $grouped_objects[$module][$id] = $objects[$id]; + $grouped_instances[$module][$id] = $instance; + $grouped_displays[$module][$id] = $display; + // 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); + $function($obj_type, $grouped_objects[$module], $field, $grouped_instances[$module], $langcode, $grouped_items[$module], $grouped_displays[$module]); } } } /** - * Default field 'view' operation. + * Build a renderable array for field values. * - * @see field_attach_view() + * @param $obj_type + * The type of $object; e.g. 'node' or 'user'. + * @param $objects + * An 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 associated to $items. + * @param $items + * Array of field values already loaded for the objects, keyed by object id. + * @param $display + * Can be either: + * - the name of a build mode; + * - or an array of custom display settings, as found in the 'display' entry + * of $instance definitions. */ -function field_default_view($obj_type, $object, $field, $instance, $langcode, $items, $build_mode) { +function field_default_view($obj_type, $object, $field, $instance, $langcode, $items, $display) { list($id, $vid, $bundle) = entity_extract_ids($obj_type, $object); $addition = array(); - $display = $instance['display'][$build_mode]; + + // Prepare incoming display specifications. + if (is_string($display)) { + $build_mode = $display; + $display = $instance['display'][$build_mode]; + } + else { + $build_mode = '_custom'; + } if ($display['type'] !== 'hidden') { $theme = 'field_formatter_' . $display['type']; Index: modules/field/field.info.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/field/field.info.inc,v retrieving revision 1.30 diff -u -p -r1.30 field.info.inc --- modules/field/field.info.inc 29 Nov 2009 06:35:47 -0000 1.30 +++ modules/field/field.info.inc 29 Nov 2009 19:39:31 -0000 @@ -265,22 +265,10 @@ function _field_info_prepare_instance($i $instance['default_value'] = NULL; } - // Fallback to default widget if widget type is not available. - if (!field_info_widget_types($instance['widget']['type'])) { - $instance['widget']['type'] = $field_type['default_widget']; - } - // Make sure all expected widget settings are present. - $instance['widget']['settings'] += field_info_widget_settings($instance['widget']['type']); + $instance['widget'] = _field_info_prepare_instance_widget($field, $instance['widget']); foreach ($instance['display'] as $build_mode => $display) { - if ($display['type'] != 'hidden') { - // Fallback to default formatter if formatter type is not available. - if (!field_info_formatter_types($instance['display'][$build_mode]['type'])) { - $instance['display'][$build_mode]['type'] = $field_type['default_formatter']; - } - // Make sure all expected formatter settings are present. - $instance['display'][$build_mode]['settings'] += field_info_formatter_settings($instance['display'][$build_mode]['type']); - } + $instance['display'][$build_mode] = _field_info_prepare_instance_display($field, $display); } // Fallback to 'full' display settings for unspecified build modes. @@ -294,6 +282,71 @@ function _field_info_prepare_instance($i } /** + * Prepare display specifications for the current run-time context. + * + * @param $field + * The field structure for the instance. + * @param $display + * Display specifications as found in + * $instance['display']['some_build_mode']. + */ +function _field_info_prepare_instance_display($field, $display) { + $field_type = field_info_field_types($field['type']); + + // Fill in default values. + $display += array( + 'label' => 'above', + 'type' => $field_type['default_formatter'], + 'settings' => array(), + 'weight' => 0, + ); + if ($display['type'] != 'hidden') { + $formatter_type = field_info_formatter_types($display['type']); + // Fallback to default formatter if formatter type is not available. + if (!$formatter_type) { + $display['type'] = $field_type['default_formatter']; + $formatter_type = field_info_formatter_types($display['type']); + } + $display['module'] = $formatter_type['module']; + // Fill in default settings for the formatter. + $display['settings'] += field_info_formatter_settings($display['type']); + } + + return $display; +} + +/** + * Prepare widget specifications for the current run-time context. + * + * @param $field + * The field structure for the instance. + * @param $widget + * Widget specifications as found in $instance['widget']. + */ +function _field_info_prepare_instance_widget($field, $widget) { + $field_type = field_info_field_types($field['type']); + + // Fill in default values. + $widget += array( + 'type' => $field_type['default_widget'], + 'settings' => array(), + 'weight' => 0, + ); + + $widget_type = field_info_widget_types($widget['type']); + // Fallback to default formatter if formatter type is not available. + if (!$widget_type) { + $widget['type'] = $field_type['default_widget']; + $widget_type = field_info_widget_types($widget['type']); + } + $widget['module'] = $widget_type['module']; + // Fill in default settings for the widget. + $widget['settings'] += field_info_widget_settings($widget['type']); + + return $widget; +} + +/** * Helper function for determining the behavior of a widget * with respect to a given operation. * Index: modules/field/field.module =================================================================== RCS file: /cvs/drupal/drupal/modules/field/field.module,v retrieving revision 1.48 diff -u -p -r1.48 field.module --- modules/field/field.module 26 Nov 2009 19:09:32 -0000 1.48 +++ modules/field/field.module 29 Nov 2009 18:37:31 -0000 @@ -554,45 +554,94 @@ function field_format($obj_type, $object } /** - * Return a single field, fully themed with label and multiple values. + * Returns a renderable array for the value of a single field in an object. * - * To be used by third-party code (Views, Panels...) that needs to output - * an isolated field. Do *not* use inside node templates, use - * render($content[FIELD_NAME]) instead. + * The resulting output is a fully themed field with label and multiple values. * - * The field will be displayed using the display options (label display, - * formatter settings...) specified in the $instance structure for the given - * build mode: $instance['display'][$build_mode]. + * This function can be used by third-party modules that needs to output an + * isolated field. Do *not* use inside node templates, use + * render($content[FIELD_NAME]) instead. * + * @param $obj_type + * The type of $object; e.g. 'node' or 'user'. * @param $object - * The object containing the field to display. Must at least contain the id key, - * revision key (if applicable), bundle key, and the field data. - * @param $field - * The field structure. - * @param $instance - * The instance structure for $field on $object's bundle. - * @param $build_mode - * Build mode, e.g. 'full', 'teaser'... + * The object containing the field to display. Must at least contain the id + * key and the field data to display. + * @param $field_name + * The name of the field to display. + * @param $display + * Can be either: + * - The name of a build mode. The field will be displayed according to the + * display settings specified for this build mode in the $instance + * definition for the field in the object's bundle. + * If no display settings are found for the build mode, the settings for + * the 'full' build mode will be used. + * - An array of display settings, as found in the 'display' entry of + * $instance definitions. The following kay/value pairs are allowed: + * - label: (string) Position of the label. The default 'field' theme + * implementation supports the values 'inline', 'above' and 'hidden'. + * Defaults to 'above'. + * - type: (string) The formatter to use. + * Defaults to the 'default_formatter' for the field type, specified in + * hook_field_info(). The default formatter will also be used if the + * requested formatter is not available. + * - settings: (array) Settings specific to the formatter. + * Defaults to the formatter's default settings, specified in + * hook_field_formatter_info(). + * - weight: (float) The weight to assign to the renderable element. + * Defaults to 0. + * @param $langcode + * (Optional) The language the field values are to be shown in. The site's + * current language fallback logic will be applied no values are available + * for the language. If no language is provided the current language will be + * used. * @return - * The themed output for the field. + * A renderable array for the field value. */ -function field_view_field($obj_type, $object, $field, $instance, $build_mode = 'full') { - $output = ''; - if (isset($object->$field['field_name'])) { - $items = $object->$field['field_name']; - - // One-field equivalent to _field_invoke('sanitize'). - $function = $field['module'] . '_field_sanitize'; - if (function_exists($function)) { - $function($obj_type, $object, $field, $instance, $items); - $object->$field['field_name'] = $items; - } +function field_build_field($obj_type, $object, $field_name, $display = array(), $langcode = NULL) { + $output = array(); - $view = field_default_view($obj_type, $object, $field, $instance, $items, $build_mode); - // TODO : what about hook_field_attach_view ? + list(, , $bundle) = entity_extract_ids($obj_type, $object); + $field = field_info_field($field_name); + $instance = field_info_instance($obj_type, $field_name, $bundle); + if (is_string($display) && !isset($instance['display'][$display])) { + $display = 'full'; + } + + if ($field = field_info_field($field_name)) { + // Fill in default values for the display settings. + if (is_array($display)) { + $display = _field_info_prepare_instance_display($field, $display); + } - $output = $view[$field['field_name']]; + // Hook invocations are done through the _field_invoke() functions in + // 'single field' mode, to reuse the language fallback logic. + $options = array('field_name' => $field_name, 'language' => field_multilingual_valid_language($langcode, FALSE)); + $null = NULL; + + // Prepare view: let the formatter load additional data. + list ($id) = entity_extract_ids($obj_type, $object); + _field_invoke_multiple_default('prepare_view', $obj_type, array($id => $object), $display, $null, $options); + // Sanitize the data. + _field_invoke('sanitize', $obj_type, $object, $null, $null, $options); + // Build the renderable array. + $result = _field_invoke_default('view', $obj_type, $object, $display, $null, $options); + + // Let other modules alter the renderable array. + $context = array( + 'obj_type' => $obj_type, + 'object' => $object, + 'build_mode' => '_custom', + 'langcode' => $langcode, + ); + drupal_alter('field_attach_view', $result, $context); + + if (isset($result[$field_name])) { + $output = $result[$field_name]; + $output['#attached']['css'][] = drupal_get_path('module', 'field') . '/theme/field.css'; + } } + return $output; } Index: modules/field/tests/field_test.field.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/field/tests/field_test.field.inc,v retrieving revision 1.1 diff -u -p -r1.1 field_test.field.inc --- modules/field/tests/field_test.field.inc 20 Nov 2009 23:29:28 -0000 1.1 +++ modules/field/tests/field_test.field.inc 29 Nov 2009 17:35:48 -0000 @@ -238,11 +238,11 @@ function field_test_field_formatter_info /** * Implement hook_field_formatter_prepare_view(). */ -function field_test_field_formatter_prepare_view($obj_type, $objects, $field, $instances, $langcode, &$items, $build_mode) { +function field_test_field_formatter_prepare_view($obj_type, $objects, $field, $instances, $langcode, &$items, $displays) { 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') { + if ($displays[$id]['type'] == 'field_test_needs_additional_data') { foreach ($item as $delta => $value) { // Don't add anything on empty values. if ($value) { Index: modules/taxonomy/taxonomy.module =================================================================== RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.module,v retrieving revision 1.541 diff -u -p -r1.541 taxonomy.module --- modules/taxonomy/taxonomy.module 27 Nov 2009 07:10:51 -0000 1.541 +++ modules/taxonomy/taxonomy.module 29 Nov 2009 17:35:48 -0000 @@ -1115,12 +1115,12 @@ function taxonomy_allowed_values($field) } /** - * Implement hook_field_load(). + * Implement hook_field_formatter_prepare_view(). * * This preloads all taxonomy terms for multiple loaded objects at once and * unsets values for invalid terms that do not exist. */ -function taxonomy_field_formatter_prepare_view($obj_type, $objects, $field, $instances, $langcode, &$items, $age) { +function taxonomy_field_formatter_prepare_view($obj_type, $objects, $field, $instances, $langcode, &$items, $displays) { $tids = array(); // Collect every possible term attached to any of the fieldable entities.