Allowed values

We encourage users to post events happening in the community to the community events group on https://www.drupal.org.
KarenS's picture

Several kinds of fields currently offer an 'allowed values' list where you can create either a hard-code list of possible value or some PHP code that will produce an allowed values list. The allowed values list is a field attribute that is shared between all instances of a field.

In our current D7 code, core will not allow changes to field attributes, only to instance attributes, mostly to prevent changes that would alter the data schema (like changing a SQL varchar field to a SQL text field), but 'allowed values' lists will need to be updated and changed, and those changes have no effect on the data schema.

Yves and I discussed this as we were bringing the code sprint work forward and decided to change 'allowed values' to an instance attribute instead and I made this change in the code. However I now see some problems this will create. The most important one is Views integration. In Views, we expose fields, not instances, and all the field settings and filter options are set at the field level. If instances have different allowed values lists, how would we create an exposed filter for that field to allow the end user to select a value to filter on? We would have to expose every instance of a field as a separate field. That would create a huge long list of Views fields, with fields like Node: Body (Page), Node: Body (Story), etc. And if you want to filter on the same value in different instances, you would have to create a separate exposed filter for each instance and set each of them to that value. That doesn't seem like a good idea.

So I think we have to go back to making it a field attribute, but one that can be altered, which means we need the core API to allow this.

During our discussion in the sprint we talked about this a bit and all agreed that the best solution would be to do something like pluggable allowed values list that could be shared not just among all the instances of a field but also between fields. I visualize a separate module for creating pluggable 'Allowed values' lists that exposes the available lists to our fields, then our core API would give fields a setting to identify which list to use.

This would be great for long and complicated allowed values lists that you don't want to re-create in every field. It could also reduce the need for using PHP code for those lists if the the 'Allowed values' stored only the name of a function that would return the list instead of raw PHP code.

Related to this has been the question of how to incorporate dependent or hierarchical allowed values lists where the value for one field is dependent on the selection in another. So some thought must be given to figuring out how that could be incorporated.

So the whole system of allowed values lists probably needs to be moved into a separate module that can provide some basic list functionality that could be extended by contrib modules, and a task would be to create a system to do something like this.

I'd like to get some discussion about this and hope that someone will want to step up and work on creating this.
'

Comments

Fields vs. Instances

bjaspan's picture

In a comment on a separate post I suggested that it might be nice to be able to set different Allowed Values lists on different instances. Your point about Views, however, it valid. If we expose Fields to fields and put Allowed Values on instances, filtering by allowed values is not possible. If we expose Instances, we lose the ability to create Views that operate on Fields across data types, which essentially guts the whole reason we are bothering with sharable fields in the first place.

I suppose it is conceivable to allow different Allowed Values on instances, and then expose a merged list of values to Views. Actually, I'm not sure this is so crazy. First, a scenario: A field called "Pattern" (as in cloth/textiles), stored as an int. For the bundle called Clothing, the instance of Pattern has allowed values 0/Solid, 1/Striped, 2/Plaid. For the bundle called Furniture, the instance of Pattern has allowed values 0/Solid and 3/Paisley. When the Pattern field is exposed to Views, the allowed values lists are merged. If you build a view that filters on Pattern == Paisley, obviously you will only get Furniture, but that is how Views is supposed to work.

Ah, but what about conflicts? If the Pattern instance on Furniture allows 0/Solid and 1/Paisley, then column value "1" can mean two things. Well, fine. When the Pattern Field is exposed to Views and it has to merge the multiple allowed values lists, it just includes the description for all conflicts. The views option list would be 0 => "Solid", 1 => "Striped or Paisley", 2 => "Plaid". If you build a view that filters on "Striped or Paisley", you might get Clothing or Furniture, exactly as you'd expect. Building this merged list would be a pretty simple bit of PHP, even if the Allowed Values came from a callback.

Another possible kind of conflict: One instance of a field has Allowed Values but the other doesn't. In this case, we could either export two fields to Views, one with an option list and one without, or we export one field to Views and its option widget is a "combo box" form element with a drop list and a text box. I'm sure jQuery combo boxes exist. :-)

This would lead to:

  • Value Lists are a stand-alone entity, perhaps managed by the Field Value List API, or maybe some other system. I still haven't fully thought through the relationship (if any) with taxonomy. As I said in the other post, we could just declare Value Lists to be vocabularies, but then we lose the ability to have a Value List with a text value (frankly, that's probably a good thing; I've seen many examples of text allowed-value fields and 100% of them should have been integer allowed-value fields with a text display value per key).

  • Value Lists are instance properties. An instance either contains a vlid or it does not.

  • The contrib Field Views module exports fields to views, but merges the Value Lists for all instances of the field.

Comments?

Value List != Taxonomy vocabulary

bjaspan's picture

On further reflection, Value Lists cannot be taxonomy vocabularies. Vocabularies contain terms with automatically generated, site-unique term ids as keys. Value Lists often want to specify an exact value. For example, a "Lifetime in Days" field might have an instance that wants a drop-down list, 1 day, 1 week, 1 month, 1 year, with the values 1, 7, 31, and 366 in the database. That's impossible if we use taxonomy terms.

Also, another reason that Allowed Values should be an Instance and not a Field property is that they (just like Default Values) are inherently tied to the input widget, not the database. The Allowed Values aren't even checked during field_attach_save, much less enforced by the schema. It is easy to imagine two instances for the same field using wildly different input widgets with complete different concepts of the format of an Allowed Value.

So, I'm liking the idea that Allowed Values are on instances, and for Views, we export a merged list for each Field.

$term->system_name

catch's picture

On the other thread, grugnog suggested a system name for taxonomy terms (which could default to drupal_strtolower($term->name) and save us some unindexed queries too so would be useful in and of itself) - so you'd have tid, $term->system_name $term->name which could handle those cases. It's not necessarily very nice - but we're seeing a lot of people using CCK text fields for purposes taxonomy is better suited to simply because CCK widgets are nicer than taxonomy's crusty old forms.

On further reflection, Value

yched's picture

On further reflection, Value Lists cannot be taxonomy vocabularies. Vocabularies contain terms with automatically generated, site-unique term ids as keys. Value Lists often want to specify an exact value. For example, a "Lifetime in Days" field might have an instance that wants a drop-down list, 1 day, 1 week, 1 month, 1 year, with the values 1, 7, 31, and 366 in the database. That's impossible if we use taxonomy terms.

I think integer fields with unaliased allowed values (meaning, you want the actual int values for themselves) are in fact a different beast than text or integer fields with aliased allowed values, for which the int that gets stored has no semantics in itself, apart from being a reference to a term in a list (be it a taxo term or just 'a term in a list').

I do like the idea that the 'list of (aliased) values' feature could be
- integer-keyed only
- deferred to a separate module, that stores 'list of values' that can be reused.
- possibly even deferred to a different field type than 'integer' ? Even if the data stored is similar db-wise, this new field type is not more semantically similar to an Integer field than a noderef field is to an integer field. Actually, the way formatters for int and text fields currently handle aliased values shows that its in fact a separate concept.
(Issue : D6 -> D7 upgrade for existing fields with allowed values, though...)

At this point, we're indeed not that far from a 'taxonomy field'. Except :
- it's easier to fill-in a list of n values separated by a carriage return in a textarea than to create n terms in a vocab (ok, there are contrib modules out there to import taxo terms, but
- having a list of allowed values be dynamically generated and returned by a PHP function has its use cases (list of zipcodes, cities, countries...)
So I'm not sure we should take that last step of saying 'allowed values = taxonomy terms' right now.

But, as you point, there is a use case for numeric fields (mainly "Integer", I guess) with 'list of (unaliased) allowed values'...

Allowed Values are inherently tied to the input widget

No, allowed values validation is done in hook_field_validate(). You can have allowed values with a regular textfield widget, and validation will fail if you enter an incorrect value. field_attach_save() doesn't perform any check, be it 'allowed values' or 'min / max value' or 'max length', because it happens outside form validation, which is currently the only validation drupal performs in the node workflow.

I'm not in favor of sticking the allowed values on instances.
- Having Views expose select lists with "A; B or C; D" will IMO confuse people (Views usually doesn't do OR) and bring frustration ("hey, and what if I want it grouped as 'A or D' ?")
- If allowed values are integer-based references to 'values' in a 'values list', then a value in the data table is a foreign key, whose target is not the same for every row in the table depending on the instance - not too nice
- if an instance has allowed values (and is thus stored as an int) and not another instance, that other instance is still restricted to store ints.
- There's no conceptual need (our model is not broken if allowed values stay per-field), and no strong requests either AFAIK...

Another thing to keep in

KarenS's picture

Another thing to keep in mind is that when you use the list of values created in a textarea is that if you don't explicitly define the key in your list your database will be screwed if you insert a new value in between two other ones after creating data (since that changes the implied keys). That's why the code currently asks you to define both the key and the label. We just have to be sure our new method of handling lists doesn't re-introduce that problem.

Field settings inheritance to instances optional?

markus_petrux's picture

When an field option is per instance, you have the alternative to not reuse the field, or reuse the field if that's what you need. But when an option is per field, there's no option to share it.

For example, now in CCK2, allowed values is a per instance settings, so you can reuse the list reusing the field on different content types, or create a different field for a particular content type with a different list of allowed values. It gives the site designer more options. On the other hand, default value is a per field setting, so if you need to use a different default value depending on the content type, you have to create a separate field definition, just for that, or well use PHP code to compute the default.

I mean that one important thing to consider, IMHO, when choosing when a setting is per instance or per field is the options that it gives to cover different use cases. I would say that the best solution would be to let the site designer choose if a setting is per field, or if it's best inherited to instances. It's kind of "Object Oriented Design" applied to fields.

You have this backwards

KarenS's picture

In the D6 version allowed values are per field settings, not per instance settings. You create a list of allowed values that is shared by all instances of the field. When you share the field, you create a new instance that shares the same list you already defined at the field level. Default values are per instance -- you can create a different default value for each content type you use the field in.

In D7 we tried making the allowed values separate for each instance and ran into the problems noted above. I think yched and I are leaning toward going back to making these into per-field settings, but ideally extracting all the logic out into a separate module that would handle lists in a more intelligent way that would allow you to define lists that can be re-used by many fields.

Looks like you're getting

yched's picture

Looks like you're getting 'per-instance' and 'per field' reversed :-)
In CCK D6, 'allowed values' is per field, and 'default value' is per instance.

one important thing to consider (...) is the options that it gives to cover different use cases
The most important thing to consider IMO when assigning a given property to 'per field' or 'per instance' is : does it make sense and is the model consistent.
Use cases and features come second : if a feature 'would be nice' but doesn't fit the current model or means convoluted code, then let's not. (Of course, if too many things don't fit with the model, it can mean that the model needs to be changed :-))
For the reasons I explained at the end of my comment above, I think going 'per instance' with allowed values creates problems.

let the site designer choose if a setting is per field, or if it's best inherited to instances. It's kind of "Object Oriented Design" applied to fields.
In our current D7 model, a field is not a class, an instance isn't an (object) instanciation of that class. $field and $instance are 2 different things, and an $instance points to a $field ("I'm an instance of that field").
I'd formulate this differently: Properties are inherently per field or per instance. What we need (though not urgently IMO) is the ability for an admin, when editing an instance setting, to say 'oh, BTW, propagate the value of this setting to all the other instances'. Just a UI helper, each instance continues to hold its own value for the setting, only you write all of them.
That's a different discussion, though.

markus_petrux's picture

Though, it was mostly an example about the idea to optionally have settings at a field level that could perhaps be altered per instance. For example, the 'required' attribute. Yes, I could have posted this here: No field update, which seems more general than this discussion. My bad, sorry.

New List module

KarenS's picture

I have pulled the allowed values handling out of Field, Text, and Number and moved it to a new field type called 'List'. Most of the other options for Text and Number make no sense when you're using allowed values -- like 'Min' or 'Max' or 'Format' -- we only need a place to store the key and a way to create the list of allowed values, so it's actually a fairly simple field type.

From this thread and my own experience, I ended up creating four kinds of list field types:

1) List - the usual kind of list where the key is just an alias for the value.

2) List (numeric) - where the key is numeric and has significance that must be preserved, like Barry's example above, or a list of years (2008, 2009, 2010).

3) List (text) - where the key is a varchar and has significance that must be preserved, like a list of US States (IL => Illinois, IA => Iowa, IN => Indiana).

4) List (boolean) - where the only setting needed is a label for 'On' and a label for 'Off'.

I got the beginning of optionwidgets working again and added that in and set optionwidgets to work for the new 'List' types instead of Text and Number.

I also got the beginning of getting nodereference and userreference working again.

I renamed optionwidgets to option_widgets, nodereference to node_reference, and userreference to user_reference per Dries earlier comment that we don't squeeze names together like that in core.

I also got rid of allowed_values_php and changed it to allowed_values_function to expect a function name as an alternative to a hard-coded list. I'm moving the PHP handling to the contrib module where we can store the PHP code and return it as an option for the custom allowed values function.

I went ahead and committed these changes so others can weigh in on them. Obviously if you think this is a mistake we can re-work it.

+1

bjaspan's picture

I haven't looked at the code yet, but in general I think this is a great idea. The fact that specifying "allowed values" magically turns a number/text field with a textfield widget into a select box never made much sense, and the config form certainly confused a lot of people. I think a List field will provide a substantially improved user experience. Good work!

The only comment I can make so far is that we want to try to clear about what "List (numeric)" and "List (text)" really mean. In particular, we want to make it clear that you have text display labels for numeric lists, and somehow want to try to explain when you should use one or the other. Actually, I think your state example is a perfect example of when you really want a text field, and "1 week, 30 days, 1 year" is probably a good example for numeric (years aren't a good example because the key and display value are the same).

List field type names

bjaspan's picture

I just tried to create a List field. It didn't work, but I could see the List field types in the select list. Questions:

  1. Do we really need a separate type, List, for when the key is just an alias for the value? Why not just have numeric and text lists automatically display the key if no label is provided?

  2. I think "List (numeric)" vs. "List (text)" does not really communicate to the user what the difference is. I think users will see that and think, "I want a select list showing strings 'one week', 'one month', and 'one year', so I better choose List (text)" when they really want numeric. I'm not sure how to communicate this difference in the space of a select box. Here's an idea: When the user selects a field type, can we have a description of the type show up in the New Field area? Then (e.g.) for "List (text)" we could display, "Use List (text) when you want to store a string value in the database. For example, you can create a list of USA states that displays the full name (Alabama, Alaska, Arkasas, ...) to the user and stores the two-letter abbreviation (AL, AK, AR, ...) in the database."

  3. For "List (booelan)", how about "Boolean (Yes/No, On/Off, ...)" instead?

I totally agree the

KarenS's picture

I totally agree the descriptions need work. We've tried before to figure out a way to communicate more info on that screen about the selected field or widget but couldn't find anything that would work to do it. If you think you see a way to present more information to the user, maybe you can create some code to see how it will work.

The reason for not using the same field for the alias list and the numeric list is that the alias list is storing an integer and the numeric list is going to have to store a float value since I think we have to allow a way to use non-integer values as keys. If we don't allow decimal values as keys we will break existing fields that already use them. Unless we want to store integer keys in float fields?

BTW, there are detailed

KarenS's picture

BTW, there are detailed descriptions in field_info() that will do what you want, we just need a way to retrieve them so people cam see them on the Manage fields screen as they go through the available fields. I don't know any way to do that though.

The easiest approach that

bjaspan's picture

The easiest approach that occurs to me is a collapsed fieldset at the bottom of the Add: New Field row containing a dd list of field type and description.

Tooltip over the field name?

markus_petrux's picture

In addition to a list of all field types and their descriptions. Maybe a tooltip could be displayed over the field names, so that the description is handy for fields that are already in use. ?

FWIW, the issue where this

yched's picture

FWIW, the issue where this was discussed is http://drupal.org/node/324647
Basically, I wanted to show the field type description when hovering the options in the 'field type' selector - but it seems FF is the only browser that would allow that.

A fieldset below the submit button could probably do the trick. Display field types, their description, and the advanced_help link to the right topic.

Replacing selects with... ¿?

markus_petrux's picture

http://v2.easy-designs.net/articles/replaceSelect/

Demo:
http://v2.easy-designs.net/articles/replaceSelect/files/final.html

Not sure if there's something similar written in jQuery, but it is doable. Once you have an unordered list you can attach hover events to them, and from there display field/widget descriptions wherever you wish, and that works on all browsers.