A couple of bugs got revealed during my work on #420816: On-demand loading of dynamic paths and local tasks #1

- If you have a field_foo anywhere, then you can edit field_foo anywhere, f.e. admin/config/people/accounts/fields/field_foo, regardless of whether an instance of that field exists for the entity type and bundle.

- Field UI menu items don't have any menu item titles at all.

Comments

Status: Needs review » Needs work

The last submitted patch, drupal.field-ui-menu.0.patch, failed testing.

yched’s picture

just subscribe for today :-(

yched’s picture

See #614030-24: Cannot edit fields for taxonomy terms for an explanation on why $bundle arg in menu loaders are not usable :-(.

yched’s picture

+++ modules/field_ui/field_ui.module	15 Mar 2010 00:34:01 -0000
@@ -86,33 +86,45 @@ function field_ui_menu() {
           $items["$path/fields/%field_ui_menu"] = array(
+            'load arguments' => array($entity_type, $bundle_name),

This is the crux of the issue :
You cannot use $bundle_name, because the same menu path will possibly be redefined for several bundles, thus only the $bundle_name for the last iteration of the 'foreach bundles' loop will be considered. You need to use $bundle_arg (the numeric position of the %bundle placeholder in the base $path).

Problem : in menu 'loader' callbacks, placeholders come as raw elements from the URL, not as 'elements as translated by the previous loader callbacks that have run for the path'. See #614030-3: Cannot edit fields for taxonomy terms
In short : field_ui_menu_load() won't receive a 'bundle name' it can understand, only the string that is in the path.

Powered by Dreditor.

sun’s picture

Hm. Not sure whether I'm able to follow you. :-/

In the meantime, #744258: admin/structure/taxonomy paths have to use machine_name, not vid contains an almost ready patch.

Does this mean we need to move back #617562: Remove underscore-to-dash conversion in path arguments for content types to D7? (I'd love to have a reason for that ;)

yched’s picture

Put a dsm($bundle_name) at the top of your field_ui_menu_load() func.
Then visit admin/structure/types/manage/article/fields/body (*article*)
You'll see that the func never receives 'article', but rather 'page'.

Node 'article' and 'page' bundles both set 'admin/structure/types/manage/%node_type' as their $entity_info['bundles'][$bundle_name]['admin']['path'].

Side note : Field API allows each bundle to specify its own admin path, even though in most cases it will be the same path (with a placeholder) for all bundles in a given entity type, because IIRC, when this code was written, node-type admin paths were precisely not using a placeholder for the node type, but separate menu items with hardcoded strings.

So the foreach ($info['bundles'] as $bundle_name => $bundle_info) { loop in field_ui_menu() in fact redefines the *same* $items["admin/structure/types/manage/%node_type/fields/%field_ui_menu/..."] menu items several times for node bundles. So 'load arguments' => array($entity_type, $bundle_name), in your patch just keeps the $bundle_name of the last loop iteration.

The 'load argument' needs to be the index of the placeholder ($bundle_arg), so that the menu loader receives the actual string in the requested path.

But :
field_ui_menu_load() will then receive $bundle_name as "the string present in the path", not as "the $node_type object loaded by the node_type_load() menu loader that has previously run for the %node_type placeholder" : menu loaders don't learn from each other - sad. Field API doesn't know how to turn this string into a 'bundle name' it understands. Meaning : field_ui_menu_loader() currently cannot deal with bundles and instances.
After replacing $bundle_arg with $bundle_arg in your patch, visiting the edit page of a field on a taxonomy term brings a 404, because field_ui_menu_load() returns FALSE.

Bottomline is : having a module handle menu items built by appending to paths handled by a different module is a *pain*.

It's all a question of what constraints we deem reasonable to put on fieldable entities :
- your admin paths need to be the same menu item for all of your bundles, using a placeholder
- the actual menu path needs to contain the exact bundle name understood by Field API - problem : we already know this won't be the case for comments.

sun’s picture

Status: Needs work » Needs review
StatusFileSize
new4.62 KB

If that's all needed to make you happy... only implemented for "$path/fields/%field_ui_menu" for now, because I have no idea how you thought of that object being used.

Status: Needs review » Needs work

The last submitted patch, drupal.field-ui-menu.7.patch, failed testing.

sun’s picture

No happy yched? :(

yched’s picture

Yes, sorry, my time in front of the keyboard is really limited currently :-/.

Hard to follow, but #7 should work indeed. But then :

$bundle_object = $map[$bundle_pos];

should be

$bundle_object = $map[$bundle_pos];
$bundle_name = field_extract_bundle($entity_type, $bundle_object);
yched’s picture

[edited the snippet in my previous comment]

sun’s picture

Status: Needs work » Needs review
StatusFileSize
new6.55 KB

Did I mention that I love you? :)

Fully working patch + extensive docs to provide some reasoning.

yched’s picture

W00t ! So much love :-)

Great comments. Will try to actually test later today (er, tonight).

+++ modules/field_ui/field_ui.module	18 Mar 2010 11:50:34 -0000
@@ -86,33 +100,45 @@ function field_ui_menu() {
+            'weight' => 10,

Why ? Is this for admin_menu ? Is this the only item that needs an explicit weight ?

147 critical left. Go review some!

sun’s picture

StatusFileSize
new8.57 KB

The weight is for the (usually last) "Delete" local task. Apparently, yes, those local tasks are not displayed currently - though I'm not really sure why that is. (separate issue)

Removed stale debug code, fixed comments and variable names ($bundle is not an "object"), and also: Moved comment_menu_alter() below comment_menu(), as I didn't recognize that it even exists... at the very bottom of the file...

yched’s picture

re #14: Those local tasks below $path/fields/%field_ui_menu (/edit, /field-settings, /widget-type, /delete) are in fact not displayed as 'local tabs'. They use MENU_LOCAL_TASK because it looks like the only way that those pages (e.g admin/structure/types/manage/article/fields/body/widget-type) keep the breadcrumb and primary tabs as 'context' - cf screenshots in #614030-12: Cannot edit fields for taxonomy terms to see what I mean.
I don't even understand how or why this use of MENU_LOCAL_TASK does the trick (I think it was quicksketch who wrote it that way when he worked on #516138: Move CCK HEAD in core), but I do know that any other way I tried fails...

So, as far as the current core Field UI is concerned, weights don't matter on those - could be different with admin_menu, though.

As for the patch :
- if $path/fields/%field_ui_menu uses a 'title callback', we can remove the manual drupal_set_title() in the page callback (field_ui_field_settings_form())
- why don't the other paths use a 'title callback' ? (the corresponding page callbacks also have a manual drupal_set_title() that can be removed if moving to a callback)

Other than that, RTBC for me.

yched’s picture

Additional thoughts :
- Since you proved that field_ui_menu_load() can in fact receive and understand $bundles, then IMO it makes more sense to have it return an $instance rather than a $field. Those menu paths identify an (entity type + bundle + field name) triple, meaning : an instance. Plus getting a $field if you have an $instance is easy, but not the other way around.
- Then we don't need the $entity_type and $bundle_arg in 'title arguments' and 'page arguments', only $field_position (renamed $instance_position, I guess). The corresponding callbacks just receive an $instance instead of ($entity_type, $bundle, $field)

sun’s picture

StatusFileSize
new9.39 KB

if $path/fields/%field_ui_menu uses a 'title callback', we can remove the manual drupal_set_title() in the page callback (field_ui_field_settings_form())

Done in attached patch.

Note, however: Is $instance['label'] already localized? I've slapped a t() on it + also took over the fallback to the (non-localized) field name if label is empty.

why don't the other paths use a 'title callback' ? (the corresponding page callbacks also have a manual drupal_set_title() that can be removed if moving to a callback)

Comlicated area. The title callback is both used for the - here invisible (but not in admin_menu) - local tasks ("tabs"), but also for the page title when requesting that particular page.

For the common parent item, the field instance, we want the actual field label to appear both in menu link trees, but also as page title.

The dependent local tasks (edit, settings, widget, delete) are static and should not change (compare to node/%/edit, node/%/delete tabs).

Since you proved that field_ui_menu_load() can in fact receive and understand $bundles, then IMO it makes more sense to have it return an $instance rather than a $field. Those menu paths identify an (entity type + bundle + field name) triple, meaning : an instance. Plus getting a $field if you have an $instance is easy, but not the other way around.

Ugh, I already feared that you'd say that ;) - that basically means to revert the changes of #614030: Cannot edit fields for taxonomy terms, no?

Then we don't need the $entity_type and $bundle_arg in 'title arguments' and 'page arguments', only $field_position (renamed $instance_position, I guess). The corresponding callbacks just receive an $instance instead of ($entity_type, $bundle, $field)

Not sure about that. One important detail to keep in mind is: while we can pass additional arguments to menu loader functions, we can't make menu loader functions generate additional arguments that are passed to subsequent access/page/title/etc callbacks.

In other words, $instance is... - oh, now I get you. :) When reverting the changes of #614030, then our menu loader no longer returns a $field, but an $instance. Hence, all callbacks that specify $bundle_arg as callback argument will receive $instance in that place.

yched’s picture

Yes, I changed from returning an $instance to returning a $field in #614030: Cannot edit fields for taxonomy terms just because I couldn't find a way to have the menu loader deal with bundles. You just made the loader smarter, so we can go back to the $instance.

Hence, all callbacks that specify $bundle_arg as callback argument will receive $instance in that place

Or rather : callback just need to specify $index_of_the_field_placeholder argument, and will receive an $instance, that contains all the other info (entitty type, bundle, field name). They don't need $bundle_arg and $entity_type as arguments.

Localisation : no, labels are not translated. Grey area, there's an issue about this somewhere :-(.

!empty($instance['label']) ? t($instance['label']) : $instance['field_name'];
Actually, I don't think I see a case where $instance['label'] would be empty. That's a remnant from a previous state of the code, possibly D6, dunno for sure. I'd say we can ditch that fallback and fix later if it breaks.

yched’s picture

StatusFileSize
new12.78 KB

As per #16-#18, updated patch builds on #14
- reverts the menu loader to return an $instance,
- adjusts 'page arguments' and 'title arguments', as well as the corresponding callbacks, accordingly.

yched’s picture

StatusFileSize
new12.78 KB

Rerolled after #707724: Call them entities instead of objects ('object_type' -> 'entity_type')

sun’s picture

Status: Needs review » Reviewed & tested by the community

Awesome! Sorry, I got sick the other day, which threw me off from the keyboard.

dries’s picture

Status: Reviewed & tested by the community » Fixed

Committed to CVS HEAD. Thanks.

Status: Fixed » Closed (fixed)

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