Discussing #571654: Revert node titles as fields brought up the fact that our 'display' API not in too good shape.

We currently have 3 functions : field_attach_view(), field_display_field(), field_format().

field_attach_view($obj_type, $object, $build_mode, $langcode)

Builds a render array for the fully themed fields (field.tpl.php, with label and multiple values) of a given object *in a given build mode, using the display options specified on the 'Display Fields' UI screens for the corresponding field instances*.
Use case: simple 'object view' in a given context (build mode)
Works fine, except rendering the array has been identified as rather slow, without obvious room for optimisation so far. See #438570: Field API conversion leads to lots of expensive function calls

Additionally, we have two API helper functions that are currently in an intermediate state, more or less direct ports from CCK D6, not up to date with latest D7 commits.

field_display_field($obj_type, $object, $field, $instance, $build_mode)

Builds a render array for a single, fully themed field (field.tpl.php, with label and multiple values) of a given object, *allowing you to specify the display settings to use* (by hacking the $instance and $build_mode params). Was introduced for Panels in CCK D6.
Sample use cases: single field in a block or a Panel component (display settings are specified within the panel settings).
TODO:
- the signature has poor DX, could probably use a simpler ($obj_type, $object, $field_name, $display_settings)
- needs to be adapted for TF (which language to display ?),
- needs to be updated with field_attach_prepare_view() (introduced in #493314: Add multiple hook for formatters)

field_format($obj_type, $object, $field, $item, $formatter_type, $formatter_settings)

Runs a single field value through a formatter (no label, no multiple values).
Sample use cases:
- custom node theming (although using granular render() should be much easier in D7, it doesn't fill all use cases)
- Views (multiple values are displayed separately, Views takes care of the label, display settings are specified within the View field settings)
TODO:
- unify signature with field_display_field : ($obj_type, $object, $field_name, $item, $display_settings) ?
- not impacted by TF (caller provides the actual $item to be displayed)
- needs to be updated with field_attach_prepare_view() (introduced in #493314: Add multiple hook for formatters)
- probably needs to return a render array instead of a HTML string

field_display_field() is possibly not an absolute requirement in core, but it's a bit touchy and tedious to leave for every contrib/custom module that needs it to reimplement. Having it in CCK allowed for better sync regarding code changes, but that's not so true now that we're in core.
field_format(), OTOH, is IMO a requirement, at least for templates compatibility.

It's also possible that code reuse could be enhanced, both functions currently need to duplicate some logic taken care of during the 'regular' field_attach_view() workflow (field access check, language logic, hook invocations...)

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

yched’s picture

Closed #491640: move field_view_field() to _field_invoke() single-field mode as 'won't fix' in the light of the above.

plach’s picture

I repeat a question I made in #571654: Revert node titles as fields as here is more in topic: wouldn't making field_attach_view() work in single-field mode make field_display_field() useless?

yched’s picture

see my OP: field_attach_view() will take display settings saved in the $instance definition in the db. The intent of field_display_field() is to provide display settings on-the-fly, independently of whatever existing build modes or what's stored in the $instance definition. When displaying a field in a Panel pane, you want to specify the display settings within the Pane config screen, not in field UI 'Manage Display'.

plach’s picture

Ok, now it's clear. IMO the code shared between f_a_view() and f_display_field() is going to be so much that unifying them could be a good thing. Would it be so bad to add in the $options passed to f_a_v() the possiblity to pass a display settings data structure and make it work in single-field mode? In this scenario f_d_f() might become a simple wrapper just setting a couple of options, like _field_invoke_default().

plach’s picture

Issue tags: +translatable fields

IMO to proceed with this one we need to start from #571654-23: Revert node titles as fields.

yched’s picture

Attached patch tackles field_view_field().

API changes:

- field_view_field() is gone (was broken anyway), renamed to field_build_field() since it returns a renderable array.

/**
 * Returns a renderable array for the value of a single field in an object.
 *
 * The resulting output is a fully themed field with label and multiple values.
 *
 * @param $obj_type
 * @param $object
 * @param $field_name
 * @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. @todo actual description and default values.
 * @param $langcode
 *   (Optional) The language the field values are to be shown in. If no language is
 *   provided the current language will be used.
 */
function field_build_field($obj_type, $object, $field_name, $display = array(), $langcode = NULL) {

(see patch for the full PHPdoc)

- hook_field_formatter_prepare_view() receives an array of display settings instead of previously a build mode for which they had to extract the display settings in $instance['display'][$build_mode] themselves.

-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) {

Should affect very little existing code (rare hook). Only core implementation (taxonomy) didn't even use that param.

Internal changes:

- field_default_* functions involved in the 'display' workflow can accept a build_mode or (new) an array of custom display settings. Impacts field_default_prepare_view(), field_default_view().

- code in _field_info_prepare_instance() that massages 'display' settings for the current execution context factored out to a new _field_info_prepare_instance_display() helper. For consistency, same logic applied for widgets: new _field_info_prepare_instance_widget().

- fixes _field_invoke_multiple(), the $options param is not supposed to be passed to the invoked hooks. _field_invoke() doesn't do this.

Status: Active » Needs work

The last submitted patch failed testing.

yched’s picture

Status: Needs work » Needs review
FileSize
19.73 KB

Typo in the new _field_info_prepare_instance_widget(). That one should pass.

yched’s picture

Assigned: Unassigned » yched

Easier tracking.

yched’s picture

Rerolled + added some tests.

moshe weitzman’s picture

Status: Needs review » Needs work

Looks great.

  1. I prefer "render" array over "renderable" array. Briefer, and makes sense since it often gets ouput by render()
  2. "Prepares widget specifications for the current run-time context." Can we be clearer than "run-time context"?
  3. "Determines the behavior of a widget with respect to an operation.". There is some funky indentation in the doxygen below.
yched’s picture

Status: Needs work » Needs review
FileSize
19.18 KB

Rerolled after the various formatter API refactorings.
The needed API changes to allow displaying a field using one-off custom display settings have been rolled in #652834: Field formatters as render arrays, so no additional API change here.
Also, reverted the renaming of field_view_field() to field_build_field(), as per the general direction in #658364: Does build/view/formatter terminology make sense?. Field API consistently uses 'view'.

Re moshe #11
1. I'd tend to agree, but core is currently much more consistent on 'renderable arrays'.
2. The explanation is given in the PHPdoc for _field_info_prepare_instance(): " Since the instance was last saved or updated, a number of things might have changed: widgets or formatters disabled, new settings expected, new build modes added...". I'm not sure it's worth repeating, those are internal helper functions.
3. Indeed. removed that hunk.

yched’s picture

Oops 80 lines wrap.

yched’s picture

Fixed duplicate call to field_info_field() in field_view_field().

sun’s picture

Sorry. I only found those minor issues. And I was quite surprised to find those even... yched, yched... XD

Aside from that, this patch looks RTBC.

+++ modules/field/field.default.inc	19 Dec 2009 23:47:29 -0000
@@ -97,13 +97,32 @@ function field_default_insert($obj_type,
+ *   - 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, $display) {

Wrong list indentation. (second line should align with start of first line)

+++ modules/field/field.module	20 Dec 2009 00:27:23 -0000
@@ -500,7 +500,7 @@ function _field_filter_xss_display_allow
   if (!is_array($field)) {
-    $field = field_info_field($field);
+  $field = field_info_field($field);
   }

Please revert. :)

+++ modules/field/field.module	20 Dec 2009 00:27:23 -0000
@@ -565,45 +565,99 @@ function field_format($obj_type, $object
+ * This function can be used by third-party modules that needs to output an

s/needs/need/

+++ modules/field/field.module	20 Dec 2009 00:27:23 -0000
@@ -565,45 +565,99 @@ function field_format($obj_type, $object
+ *     - type: (string) The formatter to use.
+ *       Defaults to the 'default_formatter' for the field type, specified in
...
+ *     - settings: (array) Settings specific to the formatter.
+ *       Defaults to the formatter's default settings, specified in

Strange wrapping here, just remove the wrapping.

+++ modules/field/tests/field.test	19 Dec 2009 23:54:36 -0000
@@ -1728,6 +1728,108 @@ class FieldFormTestCase extends FieldTes
+class FieldDisplayAPITestCase extends FieldTestCase {
...
+
+

Duplicate newline.

This review is powered by Dreditor.

yched’s picture

Ah, yes, I must be tired :-p.
Updated patch.

Note this patch only deals with field_view_field() (return render array for fully themed 'field' with all values).
field_format() (apply a formatter on a single field value) is still TODO (doesn't have to go in in the same commit, though).

sun’s picture

Status: Needs review » Reviewed & tested by the community
+++ modules/field/field.default.inc	20 Dec 2009 01:24:55 -0000
@@ -125,16 +144,41 @@ function field_default_prepare_view($obj
 /**
- * Default field 'view' operation.
+ * Builds a renderable array for field values..

I pretend to have not seen this.

+++ modules/field/field.module	20 Dec 2009 01:27:13 -0000
@@ -565,45 +565,99 @@ function field_format($obj_type, $object
+function field_view_field($obj_type, $object, $field_name, $display = array(), $langcode = NULL) {
...
+    drupal_alter('field_attach_view', $result, $context);

Hm... is this alter hook mismatch desired? Backwards compatibility?

+++ modules/field/field.module	20 Dec 2009 01:27:13 -0000
@@ -565,45 +565,99 @@ function field_format($obj_type, $object
+      // When using a build mode, make sure we have settings for it, or fall
+      // back to the 'full' build mode.
...
+      if (!isset($instance['display'][$display])) {
+        $display = 'full';
+      }

(off-topic) This triggers the question whether 'full' shouldn't be 'default' in reality... not to be discussed here.

+++ modules/field/field.module	20 Dec 2009 01:27:13 -0000
@@ -565,45 +565,99 @@ function field_format($obj_type, $object
+    list ($id) = entity_extract_ids($obj_type, $object);

tumtetumm... I also didn't see this.

I'm on crack. Are you, too?

yched’s picture

LOL.

1) and 4) fixed.

+    drupal_alter('field_attach_view', $result, $context);

Hm... is this alter hook mismatch desired? Backwards compatibility?

Desired, because we want 3rd party modules to do the same alterations on one-off field displays than when a full object is rendered through field_attach_view().

This triggers the question whether 'full' shouldn't be 'default' in reality... not to be discussed here

I've been wondering this for quite a while. Technically I agree - then again: I'm not sure it should be the same as 'full'.
Do we want users to see 'Default' instead of 'Full node' when they want to configure the fields display for the main node page ?
Different issue indeed. Right now this patch is consistent on that aspect with what currently happens when a displaying a build mode the user has not configured yet - see // Fallback to 'full' display settings for unspecified build modes in _field_info_prepare_instance() .

yched’s picture

Added a comment about hook_field_attach_view_alter()

Dries’s picture

Status: Reviewed & tested by the community » Fixed

This looks like an important clean-up, and inspecting the code didn't yield any red flags. Committed to CVS HEAD. Thanks.

yched’s picture

Status: Fixed » Active

Thks Dries. As per #16, reopening for the 2nd part - field_format().

re sun #17: "This triggers the question whether 'full' shouldn't be 'default' in reality". Opened #664544: Clean-up entity build/view modes

cburschka’s picture

Status: Active » Closed (fixed)

This patch has introduced a parsing error on line 362 of field.info.inc, caused by a missing slash in front of a phpdoc section; setting to NW.

cburschka’s picture

Status: Closed (fixed) » Needs work

Slipped.

David_Rothstein’s picture

Title: API functions for 'display field' » (HEAD broken) API functions for 'display field'
Status: Needs work » Reviewed & tested by the community
FileSize
526 bytes

Just came across the same problem.

carlos8f’s picture

@David_Rothstein: beat me to it by a few seconds :)

Dries’s picture

Status: Reviewed & tested by the community » Fixed

Committed to CVS HEAD. Thanks!

yched’s picture

Title: (HEAD broken) API functions for 'display field' » API functions for 'display field'
Status: Fixed » Active

Oops. Sorry 'bout that. We sure miss the bot :-p.

Back to active for the remaining task.

sun.core’s picture

Priority: Critical » Normal

What's the "remaining task", and, can that be critical? :) Separate issue, perhaps?

yched’s picture

Priority: Normal » Critical

Critical as in "the current field_format() function is just a pile of code that simply doesn't work".

catch’s picture

Title: API functions for 'display field' » field_format() is just a pile of code that doesn't work

Re-titling.

webchick’s picture

LOL :)

Could you re-title it again with some kind of an indication on how someone so-inclined could help?

catch’s picture

@webchick - it's described in the opening post, I don't think a one sentence description can describe that any better than the current one.

yched’s picture

I have some code, will try to polish and post a patch asap. Tough week ahead.

chx’s picture

Can someone remind me why do we need field_format if field_view_field works..?

yched’s picture

Status: Active » Needs review
FileSize
14.55 KB

Sorry for not chiming in earlier, RL struck hard the last couple weeks.

field_view_field() returns a render array for a fully themed field ('#theme' => 'field'), with wrapping HTML, label, multiple values and RDF data - just like you'd find in a displayed node. Views (at least in D6) only displays individual field values, and takes care of the wrapping HTML and label display using its own mechanisms.

Also, theme('field') adds a non-negligible overhead vs. simply displaying a formatted field value. This was battled for months in #438570: Field API conversion leads to lots of expensive function calls and #659788: [meta issue] theme('field') is too slow, which is inhibiting its more widespread use; effulgentsia mitigated this in a awesome way in #652246: Optimize theme('field') and use it for comment body, but the cost is not negligible still.

So saying 'render this field, just hide the label', when all you want is just to run a given field value through a given formatter, is very unefficient. Would make a noticeable difference on a View displaying 10 entities with possibly 10 "field values" each.

However, it is doable to rely on field_view_field() to generate the render array for the whole field, and just grab the subpart we need, containing the render array for the specific value we want, as returned by the formatter. We reuse (not-so-simple) code, and the time spent in generating the wrapping array is negligible.

Attached patch does that
+ renames the function from field_format() (D7 only, never worked) to field_view_value(), for consistency with field_view_field()
+ adds tests for the function.

This field_view_value() won't give you the RDF wrapping, BTW. I'm not sure how Views wants to behave regarding RDF output, but I don't think it can afford the overhead of a full field theme "just" to get RDF data. IMO Views will need to add RDF data on its own (it will probably need to find a generic, Field + non-Field way to do so, I guess)

yched’s picture

FileSize
14.55 KB

fix coding style

catch’s picture

Status: Needs review » Reviewed & tested by the community

This looks great. There's no API change, yched's explanation makes sense as to the distinction, tests pass, code looks good.

plach’s picture

@yched: is field_view_value() language-agnostic, isn't it? I suppose I don't need to update #657972: Make field fallback logic actually reusable to reflect the latest changes here, right?

plach’s picture

+++ modules/field/field.module	10 Mar 2010 23:22:22 -0000
@@ -471,98 +471,50 @@ function _field_filter_xss_display_allow
+    if (isset($elements['#access'])) {
+      $output['#access'] = '#access';
     }

Is this correct or was this meant to be $output['#access'] = $elements['#access']?

Powered by Dreditor.

catch’s picture

Status: Reviewed & tested by the community » Needs work

whoah missed that one, whatever it's supposed to be, it can't be that.

yched’s picture

#access : indeed :-). Fixed.

re @plach #39: $item param in field_view_value() is already a value in a given language (e.g taken from some $entity->field_foo[$some_lang][$some_delta]). The $langcode param is there as a hint, because some formatters need to know the language of the value being rendered, and this is not available in the $item itself. So, yes, in a sense it's language agnostic.

Yet the code internally sticks the $item in a fake $cloned object to call field_view_field(), and thus relies on field_multilingual_available_languages() to determine the $langcode that will be used down the line in _field_invoke(). Whatever #657972: Make field fallback logic actually reusable refactors around there will need to be reflected here.

yched’s picture

Status: Needs work » Needs review
FileSize
14.57 KB

forgot the fixed patch.

Status: Needs review » Needs work
Issue tags: -translatable fields, -API clean-up

The last submitted patch, field_view_value.patch, failed testing.

plach’s picture

Status: Needs work » Needs review
Issue tags: +translatable fields, +API clean-up

#42: field_view_value.patch queued for re-testing.

plach’s picture

Status: Needs review » Reviewed & tested by the community

Green. Setting back to RTBC.

yched’s picture

Status: Reviewed & tested by the community » Fixed

Looks like Dries committed this earlier tonight.

plach’s picture

Updated #657972-39: Make field fallback logic actually reusable to handle field_view_value().

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

Gábor Hojtsy’s picture

Priority: Critical » Normal
Status: Closed (fixed) » Needs work

Looks like this was not documented in the upgrade guide, although the previous comments mentioned D6 code was using this function.

catch’s picture

Issue tags: +Needs documentation
yched’s picture

Well, the upgrade guide doesn't mention any of the CCK D6 API funcs that have changed names while moving to fields.module D7...

Gábor Hojtsy’s picture

Ok, well, if that is something to discover personally for everyone, then this does not need documentation either.

catch’s picture

Probably this needs to go in http://drupal.org/node/443536, with a link from update/6/7

There may be a point where we want to document 7-7 API changes on the overview page, I'd think at least from beta would be good, but that needs its own issue IMO.

plach’s picture

Assigned: yched » Unassigned

Just a notice: I linked the translatable fields documentation from the D6/D7 upgrade guide as it's a completely new bunch of code that needs to be taken into account when upgrading modules. I'd say this applies to many other parts of the Field API code including this one.

Anyway, I ain't sure yched wants to document this himself so unassigning.

jhodgdon’s picture

updating tag to new scheme for the upgrade guides

mcfilms’s picture

_field_info_prepare_instance_widget() was throwing errors in RC1 and continues to do so in RC1. If I clear the cache I get:

Notice: Undefined index: module in _field_info_prepare_instance_widget() (line 385 of /home/everlast/public_html/take5/modules/field/field.info.inc).

This is not a D6 to D7 upgrade. It is a site built on drupal 7.0-beta2 and upgraded twice.

yched’s picture

Status: Needs work » Fixed
Issue tags: -translatable fields, -API clean-up, -Needs documentation updates

@mcfilms : This is not related to the current thread. Could you open a separate issue ?

+ marking as 'fixed'.
This does not belong to the 6/7 upgrade page, the field_view_field() function had no equivalent in core D6.

jhodgdon’s picture

It was marked as update guide because of #53 and #54. Are those wrong?

mcfilms’s picture

@yched

I have done as you suggested and opened a new issue at:
http://drupal.org/node/1001060

There aren't too may issues with _field_info_prepare_instance_widget() and I noted that a patch for this was presented here and thought this may be the culprit.

jhodgdon’s picture

Status: Fixed » Needs work
Issue tags: +Needs documentation

So... Somewhere up there, someone (#53, catch) said this might need to go into the Field API pages in the Handbook. Has that been done?
http://drupal.org/node/443536

Adding the generic Needs Doc tag until that question is resolved. Agreed this doesn't need to be in the 6/7 upgrade guide, as that guide does not cover how to upgrade from contrib (CCK) to core.

antiorario’s picture

It seems to me that, in its current state, field_views_value() doesn't work. Please check out http://drupal.org/node/1017850#comment-4528334 and following comment for a possible solution.

Never mind that.

  • Dries committed 8b752bc on 8.3.x
    - Patch #612894 by David_Rothstein: fixed parse error.
    
    
  • Dries committed e9f1814 on 8.3.x
    - Patch #612894 by yched: display field improvements.
    
    
  • Dries committed 8e39e9a on 8.3.x
    - Patch #612894 by yched, David_Rothstein: field_format() is just a pile...

  • Dries committed 8b752bc on 8.3.x
    - Patch #612894 by David_Rothstein: fixed parse error.
    
    
  • Dries committed e9f1814 on 8.3.x
    - Patch #612894 by yched: display field improvements.
    
    
  • Dries committed 8e39e9a on 8.3.x
    - Patch #612894 by yched, David_Rothstein: field_format() is just a pile...

  • Dries committed 8b752bc on 8.4.x
    - Patch #612894 by David_Rothstein: fixed parse error.
    
    
  • Dries committed e9f1814 on 8.4.x
    - Patch #612894 by yched: display field improvements.
    
    
  • Dries committed 8e39e9a on 8.4.x
    - Patch #612894 by yched, David_Rothstein: field_format() is just a pile...

  • Dries committed 8b752bc on 8.4.x
    - Patch #612894 by David_Rothstein: fixed parse error.
    
    
  • Dries committed e9f1814 on 8.4.x
    - Patch #612894 by yched: display field improvements.
    
    
  • Dries committed 8e39e9a on 8.4.x
    - Patch #612894 by yched, David_Rothstein: field_format() is just a pile...

  • Dries committed 8b752bc on 9.1.x
    - Patch #612894 by David_Rothstein: fixed parse error.
    
    
  • Dries committed e9f1814 on 9.1.x
    - Patch #612894 by yched: display field improvements.
    
    
  • Dries committed 8e39e9a on 9.1.x
    - Patch #612894 by yched, David_Rothstein: field_format() is just a pile...