hook_field_load(), hook_field_validate(), hook_field_attach_load() and hook_field_attach_validate() are all very confusing.

1. hook_field_load() isn't a hook, it's called only for the module that defines the field, so it's really a 'load callback'.

2. hook_field_load() isn't actually called for the module that defines the field, it's called for the module that defines the field type - in my custom module I can define a taxonomy field, but I don't get to implement hook_field_load() for it.

3. This is just look hook_load() for node module, except we should've learned that lesson before.

Two examples of the confusion this causes:

Today, I saw a hook_field_attach_validate() on a taxonomy field, and couldn't work out why it was using attach instead of hook_field_validate() when it was the module defining the field. Of course taxonomy_field_validate() gets that honour, but this took several minutes to click.

Yesterday chx swore that hook_field_attach_insert() only gets invoked for the field type module, not any module, which is the opposite of what happens.

Both of these are completely wrong, and we've both done a lot of work with field API in the past 18 months or so.

So, and I realise not all of this can be done for D7:

hook_field_load() needs to be redefined as a 'load callback' for a field type. Either by renaming hook_field_load() to FIELD_TYPE_PROVIDING_MODULE_field_load() (name needs some work), or adding a 'load callback' key in entity info, or something like that which makes it clear it's not a hook. I'd really favour the 'load callback' key, but don't think that will fly for D7.

It should also be SOMETHING_field_type_load() instead of SOMETHING_field_load() if we stick with the fake hook approach - because it's for the field type, not the specific field.

If we did that, hook_field_attach_load() could be renamed to hook_field_load() - which would bring it into line with hook_node_load(), hook_user_load(), hook_comment_load() all of which are similarly free for alls.

Anything we do for _load() needs to happen for _validate() and all the other hooks and fake hooks.

Comments

catch’s picture

Title: hook_field_load() and friends are not a real hooks » hook_field_load() and friends are not real hooks
Issue tags: +DrupalWTF
yched’s picture

This has been true of CCK from the very beginning. hook_field_$op() (hook_field($op) in CCK contrib) is indeed more a callback than a free-for-all hook. It implements the *field type* behavior.
In an OO model, it would be an ->$op() method of the field type class. In the FiC sprint it was decided not to go for an OO rewrite in the D7 cycle.

The pattern is, for all $op:

- hook_field_$op() is invoked only for the field type.
Same goes for hook_field_formatter_view(), hook_field_widget_form() - only called for the module defining the formatter or the widget.

- hook_field_attach_$op() is a free-for-all hook, operating at the object level. It is not an equivalent of hook_field_$op() - it is not called field by field, but once for the whole object. Hence '_attach_' : hook_field_attach_$op() is fired when field_attach_$op() runs.
hook_field_attach_$op() didn't exist in CCK, because back then they were actually hook_nodeapi($op). They are the node-agnostic equivalents (fire on anything that has fields), when entities didn't officially exist and had no associated hooks. It's very possible that they could now be discarded in favor of hook_entity_$op(), but I'm not sure we have all of those yet.

- There is no free-for-all $op hook at the field level. CCK never had those.

- The module defining a specific field (i.e calling field_create_field()) does not get any special treatment, only its field_attach_$op() will get called (unless it also defines the field type). Field API doesn't know which module defined which field, field_create_field() cannot track which module performed the call.

yched’s picture

On the proposed changes:

- Callbacks would solve a less-than-ideal consequence with hook_field_$op() : if your module defines several field types (or formatter types, or widget types), its hook_field_$op() (or formatter/widget hooks) will be called for all of of those types, and it possibly needs to be structured around a switch ($type) {. This is actually more often the case for widgets and formatters 'hooks' (see text_field_formatter_view()).

It's possible that there could be an API-freeze friendly way into callbacks: let field types define their callbacks in hook_field_info(), assuming defaults of '[module]_field_$op' if they don't, thus preserving current function names. But the same would need to be done for the other pluggable thingies: hook_field_formatter_info(), hook_field_widget_info(), hook_field_storage_info().

Callbacks raise a problem : we don't know how to document them. Only hooks go in xxx.api.php and on api.d.o. Menu callbacks and entity callbacks are only documented by a pack of full text in the PHPdocs of hook_menu() and hook_entity_info(). Not nearly enough for documenting the [field type|formatter|widget|storage engine] APIs.

- hook_field_load() -> hook_field_type_load() makes sense in a fake-hook approach. Also implies hook_field_info() -> hook_field_type_info(). Late API change, though :-/.
but hook_field_attach_load() -> hook_field_load() cannot be, because its object level vs field level. hook_field_attach_load() -> hook_entity_load() would be best.

webchick’s picture

I see that this is annoying and a WTF, but it's no worse than hook_access() and hook_load() and friends.

I think we can simply document the hell out of it and resolve this in Drupal 8.

catch’s picture

Version: 7.x-dev » 8.x-dev

Yeah fair enough, the documentation is probably a duplicate of the overall Field API docs one, so I'll move this to D8.

sun’s picture

catch’s picture

tstoeckler’s picture

If we did that, hook_field_attach_load() could be renamed to hook_field_load() - which would bring it into line with hook_node_load(), hook_user_load(), hook_comment_load() all of which are similarly free for alls.

One thing that is different for fields is that fields, in contrast to nodes and comments, are arrays and not objects, and hence are not passed by reference. There is no real way to attach 'properties' to a field upon load, for instance.

yched’s picture

For the record, consensus in #1032850: Get rid of Field API's pseudo-hooks was that field types "pseudo hooks" (hook_field_load() et al...) should rather be methods of a FieldType handler class, that each field type can subclass. Same principle for formatter and widget hooks. This, of course would heavily rely on the 'plugins' architecture that is supposed to come out of the Web services initiative...

The other hooks mentioned in the thread, hook_field_attach_load() and friends, are *real* hooks. As part of the Entity API D8 effort, they might be better off deprecated in favor of hook_entity_load(), though. Entity API didn't exist when those hooks were added.

yched’s picture

also, +1 for renaming hook_field_info() to hook_field_type_info(), for accuracy. But I guess that would be better off as part of the "move to plugin classes" task.

bfroehle’s picture

subscribe.

sylvain lecoy’s picture

Also, it is maybe the wrong place but is there any issues speaking about revamping the field API ?

I mean, even the doc is confusing:

Field API

Attach custom data fields to Drupal entities.

The Field API allows custom data fields to be attached to Drupal entities

Field Attach API

Operate on Field API data attached to Drupal entities.

Field Attach API functions load, store, display, generate Form API structures, and perform a variety of other functions for field data attached to individual entities.

While the first sentence explain that Field API actually attach field to entities (which should be the goal of Field Attach API isn't it?), the second claim that it is working on field already attached to entities. This is, to me a big WTF.

sun’s picture

Do we have an issue for converting field types into plugins already?

I searched the 'field system' component as well as the D8 Field API sandbox queue already, but couldn't find one?

With that conversion issue, plus #1250500: [policy adopted; patch done] Find a (standard) way to document callback signatures, this issue here should actually be a duplicate, I think.

yched’s picture

No, no issue yet. I'll open one when I start working on the topic.

sylvain lecoy’s picture

Issue tags: +Cleanup Initiative

Adding tag

swentel’s picture

Status: Active » Closed (won't fix)
Issue tags: -Cleanup Initiative

Field types are plugins now, so I guess we're good.