Options module invokes a hook_options_list() when a module wants to re-use its widget. For example taxonomy select lists, make use of the hook to provide an array of taxonomy terms.
However even if you only want a few terms in your select list - for example "terms that the user selected in a term reference field on their profiel" you're out of luck. If even core's default behaviour of the subtree, you always end up calling taxonomy_get_tree(), because taxonomy_options_list() calls taxonomy_allowed_values() - and even with a parent set, taxonomy_get_tree() will always get every single term in your vocabulary. So this is pretty much unusable apart from tiny vocabularies.
What I'd like to be able to do, is provide my own custom allowed values callback, but still be able to use the taxonomy_term_reference field type, and still use an options select widget. At the moment, I can define my own widget, then copy and paste a tonne of code from options.module but that's ugly as hell.
Attached patch allows field definitions to have an 'allowed_values_callback' key in $settings which is used by options module if set, and if not falls back to the field type module.
Note that user_reference and node_reference in D6 both let you use views for stuff like this, but without views in core, taxonomy module's running into the same problems - we should at least let developers mess with this stuff, even if it's not possible to expose in the UI.
| Comment | File | Size | Author |
|---|---|---|---|
| #18 | taxonomy_options.patch | 735 bytes | catch |
| #8 | taxonomy_options.patch | 989 bytes | catch |
| #6 | taxonomy_options.patch | 814 bytes | catch |
| #3 | taxonomy_options.patch | 813 bytes | catch |
| options_list_callback.patch | 992 bytes | catch |
Comments
Comment #1
catchComment #3
catchThinking about it, and following a discussion with bangpound, text and number fields don't really need this, because you set options in the field definition anyway. node and user reference can do what they like because they're in contrib, so can field modules, so it's actually just taxonomy module which needs to support this, because it builds its options list with taxonomy_get_tree(). We can't fix taxonomy_get_tree() completely, at least until D8, so this is the equivalent of variable_get('taxonomy_override_selector') for Field API.
Comment #4
moshe weitzman commentedthis is pretty much required when dealing with large vocabs.
Comment #5
yched commented+1
Comment #6
catchChanged the isset() to !empty(), just in case someone sets options_list_callback to FALSE. This is the only change, so leaving RTBC.
Comment #7
yched commentedHmm, actually a field setting should be declared with a default value (empty string ?) in hook_field_info().
Comment #8
catchLike this?
Comment #9
yched commentedYup :-)
Comment #10
moshe weitzman commentedActually, is this sufficient? We are seeing linear slowdown when creating thousands of terms. I think that taxonomy_field_validate() actually uses the full allowed values list and computing these allowed values gets more and more expensive as term count increases. We need to fix allowed values as in the OP or not use it in validation.
Upgrading priority as this is not just a UI fail anymore
Comment #11
yched commentedre #10 : whether the new setting should restrict the list of valid values depends on the feature catch is after, I guess ?
Regarding the performance cost of taxonomy_field_validate() calling taxonomy_allowed_values() calling taxonomy_get_tree() : we had similar problems in nodereference some time ago. We solved it by deferring the validate check to a helper function, accepting an optional array of candidate nids as param; the contract then becomes "filter invalid values out of the list I'm giving you, plz", which is more manageable performance-wise.
See _node_reference_potential_references_standard(), and how it's called in node_reference_options_list(), node_reference_field_validate(), node_reference_autocomplete()
I guess a similar approach could be used for taxo terms ? Might be a separate issue than the use case described in the OP, though.
Comment #12
catchtaxonomy_field_validate() does not call taxonomy_allowed_values() as of two months ago: #611752: taxonomy_field_validate calls taxonomy_allowed_values
http://api.drupal.org/api/function/taxonomy_field_validate/7
If that's causing scaling issues as it is now, please open a new issue.
Comment #13
moshe weitzman commentedHmm. My slowdown must be caused by something else. This one is back to RTBC.
Comment #14
dries commentedThis looks rather hacky to me. Why not always force the callback to be set explicitly?
Comment #15
yched commentedre catch #12 : oopsie, you're right, I was on crack.
Comment #16
catch@Dries. Fields via the UI are always going to use taxonomy_allowed_values(). I guess we could default to that rather than checking whether its set if Field API supports default settings (not sure if it actually does), but not sure that's any more or less hacky.
Comment #17
yched commentedFeld API does support default values for settings, whether field, instance, widget or formatter settings.
re #15-16 : that's a choice of semantics.
I think the current choice of '' as a default value, with a semantic of 'this will use the dafault : taxonomy_allowed_values()' is more future proof (allows later renaming or refactoring without needing to change the existing $field settings).
Maybe a slight code refactor of
?
Matter of taste, really.
Comment #18
catchTernary and returning straight from the function call lets us do it on two lines. Agreed with yched that the empty string is more robust for later changes than storing the default serialized every time.
Comment #19
moshe weitzman commentedRTBC again.
Related issue - #556842: taxonomy_get_tree() memory issues
Comment #20
webchickDries, does that last patch address your comments? I personally find a bunchofcodecrammedononelinewithaternaryoperatorincrediblyhardtoread.
Comment #21
dries commentedAlrighty then. Committed to CVS HEAD.
Comment #23
les limFollow-up bug in #1281732: Fatal error when taxonomy_options_list() tries to call an undefined callback function.