field_attach_*() calls

Taken from email discussion - Quick summary :

chx :

drupal_function_exists('field_attach_*');
field_attach_*(...);

is ugly, we should do :
module_invoke('field', 'attach_*', ...);

yched : This doesn't work because for this forbids reference-altering the arguments

chx: Then let's use the 1st form when by-ref args are needed and the 2nd one for the rest.

(end of summary)

I think mixing those two forms make poor DX. The beauty of this API is 'hey, look how simple it is to make your entity fieldable, just add these one-liners at the places that make sense for you'.
Plus the module_invoke() form gives the false impression that there is such a thing as hook_attach_*(), of which field.modules provides an implementation (current phpdoc for module_invoke reads 'Invoke a hook in a particular module'.

Should we move those functions into field.module so that they're always available (or maybe unconditionally load field.attach.inc in field_init() ?).
After all, field attach API is our main API, will be called much more often than field CRUD ?

Login to post comments

I was thinking about exactly

bjaspan's picture
bjaspan - Thu, 2009-01-08 22:16

I was thinking about exactly this issue just this morning. I agree that the drupal_function_exists() and module_invoke() approaches are both horrible. I guess I like module_invoke() more, at least it is only one line of code, but of course it can't always work. Grump.

Note that the Field module is going to be/should be required, just like node is, so we can assume it is always enabled.

This is a limitation/flaw in the code registry model, so "it isn't our fault." Not that that helps. Here are the options that occur to me:

  1. Always load field.attach.inc in field_init(). Unfortunate because we're loading unnecessary code for some pages.
  2. Hand-code our own auto-loaders (e.g. field_attach_load() loads field.attach.inc and calls field_attach_load) and put them in field.module. Ugly, because the code registry is supposed to make that unnecessary. It also requires an extra function call for all field_attach*() calls, but then so does drupal_function_exists() and module_invoke(), and both of those use call_user_func_array() which is even worse anyway.
  3. Have the code registry automatically generate auto-loaders for all functions defined in .inc files, since after all that is its job. Requires a non-Field API core patch.
  4. Admit that the code registry was a stupid idea because any site that cares about performance is using an opcode cache anyway, and just go with #1.

My first choice is #4, but that isn't going to fly. My second choice is #2, with our hand-coded auto-loaders to be removed when #3 actually gets implemented.

For #3, my idea is that the code registry can generate a single .inc file full of all necessary auto-loaders, store it in the files/ directory (since we know it can write there), and always load that one file during bootstrap. Then we get auto-loading for all functions in every module, automatically. chx?


uh huh

chx's picture
chx - Mon, 2009-01-12 19:16

the code registry helps with our memory footprint which is horrible. that is not helped by opcode caches.

generating autoloaders, maybe but how will you know which fucntions you want to call directly? A ton of functions are not called directly, hook implementations and form definition/validation/submit callbacks come to my mind.


Option 2 also makes code

yched - Thu, 2009-01-08 22:49

Option 2 also makes code navigation in IDEs by CTRL-clicking function names more painful, but, right, that's probably our best bet for now...


Added to plan.

bjaspan's picture
bjaspan - Thu, 2009-01-08 23:27

I added this task to the planning spreadsheet.


I created autoloaders for

bjaspan's picture
bjaspan - Tue, 2009-01-13 17:03

I created autoloaders for all field_attach_*() functions. Here's a sample:

<?php
/**
* Accounts for d-n-d reordering of field values.
* TODO D7 : rename to 'field_attach_submit' ?
*/
function field_attach_presave($obj_type, &$object) {
  if (
drupal_function_exists('_field_attach_presave')) {
    return
_field_attach_presave($obj_type, $object);
  }
  throw new
FieldException('cannot autoload function _field_attach_presave');
}
?>

The Perl script scripts/generate-autoload.pl creates them, including the PHPdoc, etc., so they are very easy to re-generate. All the Field Attach tests still pass.

NOTE: You will probably have to rebuild your site after importing this change as the code registry will be all screwed up and user_load() won't work until it is fixed so you cannot really get to the "Clear the cache" function.


So, what other functions

bjaspan's picture
bjaspan - Tue, 2009-01-13 17:06

So, what other functions should we have auto-loaders for? All of Field CRUD? Probably; we do not want module install files to have to use drupal_function_exists() explicitly.

I actually wonder if field_attach_*() should just always be loaded outright. Essentially every non-cached page load calls user_load(), and so will load field.attach.inc anyway, and we're just imposing an extra unnecessary function call. For Field CRUD, on the other hand, most page loads will not use those functions so autoloading makes sense.

thoughts?


Agreed that CRUD API could

yched - Tue, 2009-01-13 23:38

Agreed that CRUD API could use autoloaders : it will be rarely called but we want the functions available without callers having to explicitly include stuff themselves.

Unconditionnallty including field.attach.inc was my initial sugestion, but thinking about it more, I'm not sure it's a good idea right now. Until we move, say, node body or taxonomy to fields, we can imagine some simple Drupal sites that would not need no fields at all.
field.module being 'required' is one thing, but we should stick to making it as lightweight as possible


Every page load for a

bjaspan's picture
bjaspan - Wed, 2009-01-14 04:20

Every page load for a logged-in user (which is to say, every non-cache page load) calls user_load (right?). user_load() calls field_attach_load(), which loads field.attach.inc. So, I think field.attach.inc is always going to get loaded on any non-cache page load. If so, we should just always load it and save the indirect function call.


Nope

chx's picture
chx - Wed, 2009-01-14 06:53

user_load is not automatic.


Well, then my argument for

bjaspan's picture
bjaspan - Wed, 2009-01-14 12:42

Well, then my argument for always including field.attach.inc falls apart. :-)