- Patch #546350 by dropcube: remove hardcoded numeric deltas from hook_filter_info().
[project/drupal.git] / modules / field / modules / list / list.module
CommitLineData
f3ed3283
AB
1<?php
2// $Id$
3
4/**
5 * @file
6 * Defines list field types that can be used with the Options module.
7 */
8
9/**
0f4060f3 10 * Implement hook_theme().
f3ed3283
AB
11 */
12function list_theme() {
13 return array(
14 'field_formatter_list_default' => array(
15 'arguments' => array('element' => NULL),
16 ),
17 'field_formatter_list_key' => array(
18 'arguments' => array('element' => NULL),
19 ),
20 );
21}
22
23/**
0f4060f3 24 * Implement hook_field_info().
f3ed3283
AB
25 */
26function list_field_info() {
27 return array(
28 'list' => array(
29 'label' => t('List'),
30 'description' => t('This field stores numeric keys from key/value lists of allowed values where the key is a simple alias for the position of the value, i.e. 0|First option, 1|Second option, 2|Third option.'),
e998857e 31 'settings' => array('allowed_values' => '', 'allowed_values_function' => ''),
f3ed3283
AB
32 'default_widget' => 'options_select',
33 'default_formatter' => 'list_default',
34 ),
35 'list_boolean' => array(
36 'label' => t('Boolean'),
37 'description' => t('This field stores simple on/off or yes/no options.'),
e998857e 38 'settings' => array('allowed_values' => '', 'allowed_values_function' => ''),
f3ed3283
AB
39 'default_widget' => 'options_select',
40 'default_formatter' => 'list_default',
41 ),
42 'list_number' => array(
43 'label' => t('List (numeric)'),
44 'description' => t('This field stores keys from key/value lists of allowed numbers where the stored numeric key has significance and must be preserved, i.e. \'Lifetime in days\': 1|1 day, 7|1 week, 31|1 month.'),
e998857e 45 'settings' => array('allowed_values' => '', 'allowed_values_function' => ''),
f3ed3283
AB
46 'default_widget' => 'options_select',
47 'default_formatter' => 'list_default',
48 ),
49 'list_text' => array(
50 'label' => t('List (text)'),
51 'description' => t('This field stores keys from key/value lists of allowed values where the stored key has significance and must be a varchar, i.e. \'US States\': IL|Illinois, IA|Iowa, IN|Indiana'),
e998857e 52 'settings' => array('allowed_values' => '', 'allowed_values_function' => ''),
f3ed3283
AB
53 'default_widget' => 'options_select',
54 'default_formatter' => 'list_default',
55 ),
56 );
57}
58
59/**
0f4060f3 60 * Implement hook_field_schema().
f3ed3283 61 */
ba29dbde 62function list_field_schema($field) {
f3ed3283
AB
63 switch ($field['type']) {
64 case 'list_text':
65 $columns = array(
66 'value' => array(
67 'type' => 'varchar',
68 'length' => 255,
69 'not null' => FALSE,
70 ),
71 );
72 break;
73 case 'list_number':
74 $columns = array(
75 'value' => array(
76 'type' => 'float',
77 'unsigned' => TRUE,
78 'not null' => FALSE,
79 ),
80 );
81 break;
82 default:
83 $columns = array(
84 'value' => array(
85 'type' => 'int',
86 'unsigned' => TRUE,
87 'not null' => FALSE,
88 ),
89 );
90 break;
91 }
ba29dbde
DB
92 return array(
93 'columns' => $columns,
94 'indexes' => array(
95 'value' => array('value'),
96 ),
97 );
f3ed3283
AB
98}
99
100/**
e998857e
AB
101 * Implement hook_field_settings_form().
102 */
103function list_field_settings_form($field, $instance) {
104 $settings = $field['settings'];
105
106 $form['allowed_values'] = array(
107 '#type' => 'textarea',
108 '#title' => t('Allowed values list'),
109 '#default_value' => $settings['allowed_values'],
110 '#required' => FALSE,
111 '#rows' => 10,
112 '#description' => '<p>' . t('The possible values this field can contain. Enter one value per line, in the format key|label. The key is the value that will be stored in the database, and must be a %type value. The label is optional, and the key will be used as the label if no label is specified.', array('%type' => $field['type'] == 'list_text' ? t('text') : t('numeric'))) . '</p>',
113 '#element_validate' => array('list_allowed_values_validate'),
114 '#list_field_type' => $field['type'],
115 '#access' => empty($settings['allowed_values_function']),
116 );
117
118 // Alter the description for allowed values depending on the widget type.
119 if ($instance['widget']['type'] == 'options_onoff') {
120 $form['allowed_values']['#description'] .= '<p>' . t("For a 'single on/off checkbox' widget, define the 'off' value first, then the 'on' value in the <strong>Allowed values</strong> section. Note that the checkbox will be labeled with the label of the 'on' value.") . '</p>';
121 }
122 elseif ($instance['widget']['type'] == 'options_buttons') {
123 $form['allowed_values']['#description'] .= '<p>' . t("The 'checkboxes/radio buttons' widget will display checkboxes if the <em>Number of values</em> option is greater than 1 for this field, otherwise radios will be displayed.") . '</p>';
124 }
125 $form['allowed_values']['#description'] .= t('Allowed HTML tags in labels: @tags', array('@tags' => _field_filter_xss_display_allowed_tags()));
126
127 $form['allowed_values_function'] = array(
128 '#type' => 'value',
129 '#value' => $settings['allowed_values_function'],
130 );
131 $form['allowed_values_function_display'] = array(
132 '#type' => 'item',
133 '#title' => t('Allowed values list'),
134 '#markup' => t('The value of this field is being determined by the %function function and may not be changed.', array('%function' => $settings['allowed_values_function'])),
135 '#access' => !empty($settings['allowed_values_function']),
136 );
137
138 return $form;
139}
140
141/**
142 * Create an array of allowed values for this field.
143 */
144function list_allowed_values($field) {
145 $allowed_values = drupal_static(__FUNCTION__, array());
146
147 if (isset($allowed_values[$field['field_name']])) {
148 return $allowed_values[$field['field_name']];
149 }
150
151 $allowed_values[$field['field_name']] = array();
152
153 $function = $field['settings']['allowed_values_function'];
154 if (!empty($function) && drupal_function_exists($function)) {
155 $allowed_values[$field['field_name']] = $function($field);
156 }
157 elseif (!empty($field['settings']['allowed_values'])) {
158 $allowed_values[$field['field_name']] = list_allowed_values_list($field['settings']['allowed_values'], $field['type'] == 'list');
159 }
160
161 return $allowed_values[$field['field_name']];
162}
163
164/**
165 * Create an array of the allowed values for this field.
166 *
167 * Explode a string with keys and labels separated with '|' and with each new
168 * value on its own line.
169 *
170 * @param $string_values
171 * The list of choices as a string.
172 * @param $position_keys
173 * Boolean value indicating whether to generate keys based on the position of
174 * the value if a key is not manually specified, effectively generating
175 * integer-based keys. This should only be TRUE for fields that have a type of
176 * "list". Otherwise the value will be used as the key if not specified.
177 */
178function list_allowed_values_list($string_values, $position_keys = FALSE) {
179 $allowed_values = array();
180
181 $list = explode("\n", $string_values);
182 $list = array_map('trim', $list);
183 $list = array_filter($list, 'strlen');
184 foreach ($list as $key => $value) {
185 // Sanitize the user input with a permissive filter.
186 $value = field_filter_xss($value);
187
188 // Check for a manually specified key.
189 if (strpos($value, '|') !== FALSE) {
190 list($key, $value) = explode('|', $value);
191 }
192 // Otherwise see if we need to use the value as the key. The "list" type
193 // will automatically convert non-keyed lines to integers.
194 elseif (!$position_keys) {
195 $key = $value;
196 }
197 $allowed_values[$key] = (isset($value) && $value !== '') ? $value : $key;
198 }
199
200 return $allowed_values;
201}
202
203/**
204 * Element validate callback; check that the entered values are valid.
205 */
206function list_allowed_values_validate($element, &$form_state) {
207 $values = list_allowed_values_list($element['#value'], $element['#list_field_type'] == 'list');
208 $field_type = $element['#list_field_type'];
209 foreach ($values as $key => $value) {
210 if ($field_type == 'list_number' && !is_numeric($key)) {
211 form_error($element, t('The entered available values are not valid. Each key must be a valid integer or decimal.'));
212 break;
213 }
214 elseif ($field_type == 'list_text' && strlen($key) > 255) {
215 form_error($element, t('The entered available values are not valid. Each key must be a string less than 255 characters.'));
216 break;
217 }
218 elseif ($field_type == 'list' && (!preg_match('/^-?\d+$/', $key))) {
219 form_error($element, t('The entered available values are not valid. All specified keys must be integers.'));
220 break;
221 }
222 }
223}
224
225/**
0f4060f3 226 * Implement hook_field_validate().
eecab108
AB
227 *
228 * Possible error codes:
229 * - 'list_illegal_value': The value is not part of the list of allowed values.
f3ed3283 230 */
eecab108 231function list_field_validate($obj_type, $object, $field, $instance, $items, &$errors) {
f3ed3283 232 $allowed_values = list_allowed_values($field);
eecab108
AB
233 foreach ($items as $delta => $item) {
234 if (!empty($item['value'])) {
235 if (count($allowed_values) && !array_key_exists($item['value'], $allowed_values)) {
236 $errors[$field['field_name']][$delta][] = array(
237 'error' => 'list_illegal_value',
238 'message' => t('%name: illegal value.', array('%name' => t($instance['label']))),
239 );
f3ed3283
AB
240 }
241 }
242 }
243}
244
245/**
0f4060f3 246 * Implement hook_field_is_empty().
f3ed3283
AB
247 */
248function list_field_is_empty($item, $field) {
249 if (empty($item['value']) && (string)$item['value'] !== '0') {
250 return TRUE;
251 }
252 return FALSE;
253}
254
255/**
0f4060f3 256 * Implement hook_field_formatter_info().
f3ed3283
AB
257 */
258function list_field_formatter_info() {
259 return array(
260 'list_default' => array(
261 'label' => t('Default'),
262 'field types' => array('list', 'list_boolean', 'list_text', 'list_number'),
f3ed3283
AB
263 ),
264 'list_key' => array(
265 'label' => t('Key'),
266 'field types' => array('list', 'list_boolean', 'list_text', 'list_number'),
f3ed3283
AB
267 ),
268 );
269}
270
271/**
272 * Theme function for 'default' list field formatter.
273 */
274function theme_field_formatter_list_default($element) {
275 $field = field_info_field($element['#field_name']);
276 if (($allowed_values = list_allowed_values($field)) && isset($allowed_values[$element['#item']['value']])) {
277 return $allowed_values[$element['#item']['value']];
278 }
279 // If no match was found in allowed values, fall back to the key.
280 return $element['#item']['safe'];
281}
282
283/**
284 * Theme function for 'key' list field formatter.
285 */
286function theme_field_formatter_list_key($element) {
287 return $element['#item']['safe'];
288}