This is a follow-up to #652834: Field formatters as render arrays which recently landed, and so did a follow-up improvement: #657828: Make hook_field_formatter() act on all field values. So, now field formatters return render arrays, bringing the whole field/formatter rendering pipeline into accordance with the D7 rendering model: awesome!

But, on #652834-28: Field formatters as render arrays, sun brought up that he was confused by terminology, and so am I. So, I investigated different parts of HEAD that all seem to do the same conceptual thing (build and return a render array), but use different terms to describe the process:

node_build() // return render array for a single node
  $node->content = INITIAL_INFO + field_attach_view('node', $node, $build_mode) + EXTRA_INFO;
  module_invoke_all('node_view', $node, $build_mode);
  $build = $node->content + EXTRA_INFO;
  drupal_alter('node_build', $build);
  return $build;

comment_build() // same as node_build(), replace 'node' with 'comment'
user_build() // same as node_build(), replace 'node' with 'user'/'account'

field_attach_view() // return render array for all the field instances of an entity
  $output = merge the result of calling field_default_view() for each field instance
  $output += EXTRA_INFO;
  drupal_alter('field_attach_view', $output, $context);

field_default_view() // return render array for a single field instance
  $elements = hook_field_formatter($obj_type, $object, $field, $instance, $langcode, $items, $display);
  $elements += EXTRA_INFO;
  return array($field['field_name'] => $elements);

So, when building a render array for a node, comment, or user, we call it build, as in node_build() and hook_node_build_alter(). But, during that process, we want render sub-arrays from the field module and other modules, and we call that view, as in field_attach_view() and hook_node_view(). And then within field_default_view(), we want to have module-defined, but administrator-assigned thingies that build and return the specific render array for the field, and we call those thingies formatters, but we call that formatter's function without a verb, as in hook_field_formatter() rather than hook_field_formatter_view() or hook_field_formatter_build(), presumably because we're not sure whether the correct verb is view or build, and in any case, it's the only thing a formatter does, so maybe an explicit verb isn't needed.

I suspect it's too late in the D7 cycle to try to rename hooks so that we standardize on either 'build' or 'view', but not use both. On the other hand, if we think it would help, we can rename hook_field_formatter() to hook_field_formatter_view() or hook_field_formatter_build(), since that function has already underwent API breakage, and has only existed in HEAD in its current form for 2 days, so why not break it again if it will help DX? I guess the question is: will it help DX?

Thoughts?

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

yched’s picture

Agreed that consistency is far from ideal here.

- About 'build' / 'view': Note that node.module itself is not consistent: node_build() does

module_invoke_all('node_view', $node, $build_mode);
drupal_alter('node_build', $build);

Errr ;-)

- I don't think I remember the state of the 'build' trend when Field API was worked on and got initially committed, but f_a_view() clearly takes the D6 legacy of 'view'.

- Field API also has 'prepare_view':
Field Attach API has field_attach_prepare_view()
Formatters have hook_field_formatter_prepare_view()
#658302: repurpose hook_field_sanitize() into hook_field_prepare_view() introduces hook_field_prepare_view()
#636992: Entity loading needs protection from infinite recursion introduces entity_prepare_view()

- About hook_field_formatter() (no "verb"):
True that we could add a verb. That would require us to pick _view() or _build(). and going with _build() if the rest of field API uses _view() doesn't sound a good option :-/.
Also, hook_field_formatter() is consistent with hook_field_widget() - no verb either.

- About the terminology ('Formatter'), reposting what I wrote in #652834: Field formatters as render arrays:

Agreed that a new word might be more accurate given the approach in the patch where a 'formatter' just builds a field for viewing. Having a specific word however was just not for hype, it reflected the fact that it's a pluggable component, next to (and independant from) the notions of 'field types', 'widgets', (and in D7 'storage backends'). We need an unambiguous terminology (preferably single word). 'widget' has long been controversial too, BTW, but no better term emerged.

In Views terminology (and if Field API was OO), it would be a 'build handler' ? 'Formatter' has years of usage, has the advantage of being one single word, and makes more sense than other, more technically accurate terminologies.

More generally, I don't think it's the appropriate timing to change terminology now :-(. I vote for the status quo ('formatter'), and rethinking names in D8 when (hopefully) moving to a OO architecture.

sun’s picture

node_view/_build inconsistency in http://api.drupal.org/api/function/node_build/7 exists only for historical reasons.

In general, taking a - really large - step back... ;)

... "build" makes no sense to me.

If I wouldn't know drupal_render() inside out and wouldn't be familiar with Drupal yet, then I would rather associate "build" with the loading of something.

We, however, associate that with the "building data for rendering". Errr. ;)

yched’s picture

re @sun #2: I didn't dare say it myself ;-).

effulgentsia’s picture

I agree that _view() is better than _build() across the board if what's being built is a render array that represents the "view" of something. And I'd be in favor changing node_build() to node_view() and hook_node_build_alter() to hook_node_view_alter() in D8.

Also, _view() is the chosen term within FieldAPI, which at least makes field_attach_view() consistent with hook_node_view(). So I agree that hook_field_formatter_view() would be better than hook_field_formatter_build().

So my preference is to change hook_field_formatter() to hook_field_formatter_view(). I think it would also be ideal to change hook_field_widget() to hook_field_widget_form() (since it's called from field_default_form()).

What do you guys think? Would either/both of these be an improvement? Are either/both do-able for D7? Does it make sense to do one if we don't also do the other?

yched’s picture

hooks and verbs ; I guess I'd vote for hook_field_formatter_view(), and could live with hook_field_widget() staying as is.

Dries’s picture

I also much prefer "view" over "build" as "view" is more self-explanatory.

webchick’s picture

A summary of what I told sun on IRC when he asked me last night:

In the past, "view" has embodied both the "create an array/object of content" stuff, and the "display it to the screen" stuff. See for example node_view() in Drupal 6, which returns a string of themed node output.

In Drupal 7, we have split these two so you can still get the full renderable array and do other things with it. See node_build() in Drupal 7. The idea being that you may want to use this output for something else, although most often it will be passed to drupal_render(). This is basically the same conceptually as form definition functions being different than the wrapper page callback that calls drupal_get_form().

I don't have a good grasp of how big of a developer-facing change it is to change 'build' to 'view' wholesale throughout core, and would need to see a patch. At this point in the release cycle, I tend to lean towards "document the hell out of it" rather than break APIs. But from Dries's reply, he seems like he's open to it, so that's fine. If we are going to make such a change, though, now is definitely the time to do it.

moshe weitzman’s picture

To me, *build* the right word when the return value is a render array. High level, we are building up a $page array. It is only at the very end that we decide to *render* the $page to HTML because we have a real person *viewing* the request. The word 'build' emphasizes that we are keeping an array as long as possible and we might render it to HTML later - or not.

The 'build' term is not new in D7. Since D5 we have node_build_content. And since D6 we support $build_mode. The proposal #4 would require changing all those as well.

I do think we can make a few things more consistent by replacing some uses of 'view' in field api. I'd personally leave formatters alone as they only care about the build operation and thus don't need a verb.

effulgentsia’s picture

Status: Active » Needs review
FileSize
36.12 KB

Here's a patch that might be too much for D7, but what the heck, I'll throw it up here for comments and we can remove hunks if needed. Here's what the patch does:

  • Changes hook_field_formatter() to hook_field_formatter_view().
  • Changes hook_field_widget() to hook_field_widget_form().
  • Changes (comment|node|user|contextual_links|toolbar)_build() to *_view().
  • Changes (comment|node|user)_build_multiple() to *_view_multiple().
  • Changes hook_(comment|node|user)_build_alter() to hook_*_view_alter().

This patch does NOT:

  • Change variable names or parameter names (e.g., $build and $build_mode remain as variable names throughout these functions).
  • Change hook_page_build() or hook_page_alter().
  • Change (comment|node|user)_build_content().

Here's my reasoning. I understand that in D6 and before, "view" implied returning HTML or modifying an object property with HTML. And that as the D7 render model was being worked on, we needed to draw attention to the difference between returning a structured array and returning HTML. But now that the render model has very nicely progressed to where it is, we're pretty much dealing with render arrays everywhere. Within HEAD, hook_(node|comment|user)_view($obj) work on $obj->content as a render array. hook_block_view() returns $data that contains 'subject' and 'content', and 'content' should be set to a render array, and hook_block_view_alter() can modify $data['content'], but should also keep it as a render array while doing so. aggregator_block_view(), block_block_view(), and blog_block_view() still set the content to an HTML string, but that can potentially still be fixed prior to release; OTOH, book_block_view() sets $data['content'] to a render array as is proper. Page callbacks should return render arrays, and node_page_view() does; aggregator_view() returns HTML, but this can still be fixed prior to release. And, at this point, FieldAPI always returns render arrays from all of its display functions, and those functions end in _view().

So basically, we nearly succeeded (and may yet fully succeed) in making all core module functions use render arrays and not output HTML except in theme functions that are invoked after page rendering has started. And those functions, of course, all start with 'theme_', so we can reclaim the word 'view' to be less tied to the HTML format, but instead refer to the more abstract concept of "a representation of a display", and because PHP is the way it is, our representation of choice is a render array. And by using that representation, we allow for more altering further down the pipeline, and in contrib and maybe in D8 core, we'll start seeing code that renders that representation to non-HTML formats. But as cool as all of that is, it doesn't change the fact that a render array is still a representation of a display. In MVC terminology, it's not the model (the $node object as it comes from the database and after hook_load() is the model), and it's not the controller (the various drupal functions involved in getting it so that node_build()/node_view() is called is the controller). No, the output of node_build()/node_view() is the view, even if a somewhat abstract one.

Meanwhile, we use the term 'build' to refer to all sorts of things other than render arrays. We build menu router items, forms (which while render arrays, are MORE than render arrays), the theme registry, batch information, etc., and for all of these, the term 'build' refers to model/controller related code.

The reason I don't think we need to change *_build_content() is because the word 'content' clarifies the meaning. And I don't think we need to change hook_page_build() and hook_page_alter(), because the word 'page' makes it clear what's going on. But for the other objects ('node', 'comment', 'user', 'toolbar', 'field', etc.), I believe 'view' is the more accurate description of the process than is 'build'.

But, this patch will likely require many other patches in the queue to be re-rolled, and will likely break modules that have already been ported to D7, so we need to decide if the benefits of clearer and more consistent terminology is worth that.

@moshe: Is any of this convincing or do you still think we should leave things in their inconsistent state or change FieldAPI to use 'build' instead of 'view'?

moshe weitzman’s picture

I didn't think someone would actually write the patch. Kudos to Alex for your persistence. Yeah, your explanation holds at least as much water as mine did. Maybe more. I'm good with the patch if thats what folks want.

sun’s picture

IMHO, this patch is a massive improvement for Drupal newbies/newcomers. Next to the build/view renaming, I also especially like the renaming to hook_field_widget_form(), since it clarifies that a widget is not a widget in terms of some displayed/rendered web 2.0 gadget, but a section of a form instead.

+1 on this patch, and, yeah, people are used to re-roll their patches ;)

yched’s picture

Is it OK to have a hook / function ending in _form() that does not return / act on a full $form but only a sub part ?

catch’s picture

I think it's a good change, but not sure if it's a change which should go into 7 or 8. I feel a bit like these are already new APIs in the sense we're not changing anything which was previously in D6 (so won't affect modules not ported at all yet), but don't have a handle on how many contrib modules already ported are making use of them yet.

Dries’s picture

I'd support still making this change. It makes the code a lot easier.

effulgentsia’s picture

Component: field system » base system
Issue tags: +API change, +API clean-up, +D7 API clean-up

Is it OK to have a hook / function ending in _form() that does not return / act on a full $form but only a sub part ?

Well, in addition to FieldAPI functions that already do this (field_default_form(), field_multiple_value_form()), we also have filter_form() and image_resize_form() and its variants, so I think it's okay, but someone please speak up if it isn't.

Not sure who else needs to review it before it's RTBC, but changing the "component" attribute of the issue and adding tags to reflect the nature of the patch.

effulgentsia’s picture

What's needed for this to be RTBC? Is there a key person (or people) who should review it?

yched’s picture

Status: Needs review » Reviewed & tested by the community

Dries approved the API changes, the patch looks good and tests are green. RTBC.

yched’s picture

About $build_mode / hook_field_build_modes(): #664544: Clean-up entity build/view modes

Dries’s picture

Status: Reviewed & tested by the community » Fixed

Alright, let's do this still. Not ideal to do it at this stage, but I think it will help us in the long term. Committed to CVS HEAD.

yched’s picture

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

I tried to update http://drupal.org/update/modules/6/7 with the changes in this patch.

The http://drupal.org/update/modules/6/7#node_view entry is now completely moot, we reverted that change. Not sure what the policy is in those cases, like for deadwood automated module rewrite and such. For now I just added a bold node that the change was reverted.

Also, http://drupal.org/update/modules/6/7#node_build_rss seems quite stale...

effulgentsia’s picture

Status: Needs work » Fixed

I opened a separate issue to get doc team help with this: #675212: How should a reversion be documented in the D6->D7 module upgrade doc?.

effulgentsia’s picture

Status: Fixed » Needs work

Actually, I guess just because the other issue was opened to get some help doesn't make this one fixed, does it? Since webchick sent out the email to the dev list asking for people to work on the "Needs Documentation" queue, perhaps this should be "needs work" so it gets attention.

sun’s picture

effulgentsia’s picture

Status: Needs work » Fixed

Got an answer in #675212-1: How should a reversion be documented in the D6->D7 module upgrade doc?, but noticed that at least some trace of information exists on the module upgrade page for other things that have been reverted, so I made a compromise by removing the body of the information, but leaving the title in DEL tags: http://drupal.org/node/224333/revisions/view/893868/894800.

Status: Fixed » Closed (fixed)
Issue tags: -Needs documentation

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