6 * Defines list field types that can be used with the Options module.
10 * Implements hook_help().
12 function list_help($path, $arg) {
14 case
'admin/help#list':
16 $output .
= '<h3>' .
t('About') .
'</h3>';
17 $output .
= '<p>' .
t('The List module defines various fields for storing a list of items, for use with the Field module. Usually these items are entered through a select list, checkboxes, or radio buttons. See the <a href="@field-help">Field module help page</a> for more information about fields.', array('@field-help' => url('admin/help/field'))) .
'</p>';
23 * Implements hook_field_info().
25 function list_field_info() {
29 '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.'),
30 'settings' => array('allowed_values' => '', 'allowed_values_function' => ''),
31 'default_widget' => 'options_select',
32 'default_formatter' => 'list_default',
34 'list_boolean' => array(
35 'label' => t('Boolean'),
36 'description' => t('This field stores simple on/off or yes/no options.'),
37 'settings' => array('allowed_values' => '', 'allowed_values_function' => ''),
38 'default_widget' => 'options_select',
39 'default_formatter' => 'list_default',
41 'list_number' => array(
42 'label' => t('List (numeric)'),
43 '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.'),
44 'settings' => array('allowed_values' => '', 'allowed_values_function' => ''),
45 'default_widget' => 'options_select',
46 'default_formatter' => 'list_default',
49 'label' => t('List (text)'),
50 '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'),
51 'settings' => array('allowed_values' => '', 'allowed_values_function' => ''),
52 'default_widget' => 'options_select',
53 'default_formatter' => 'list_default',
59 * Implements hook_field_schema().
61 function list_field_schema($field) {
62 switch ($field['type']) {
92 'columns' => $columns,
94 'value' => array('value'),
100 * Implements hook_field_settings_form().
102 * @todo: If $has_data, add a form validate function to verify that the
103 * new allowed values do not exclude any keys for which data already
104 * exists in the databae (use field_attach_query()) to find out.
105 * Implement the validate function via hook_field_update_forbid() so
106 * list.module does not depend on form submission.
108 function list_field_settings_form($field, $instance, $has_data) {
109 $settings = $field['settings'];
111 $form['allowed_values'] = array(
112 '#type' => 'textarea',
113 '#title' => t('Allowed values list'),
114 '#default_value' => $settings['allowed_values'],
115 '#required' => FALSE
,
117 '#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>',
118 '#element_validate' => array('list_allowed_values_validate'),
119 '#list_field_type' => $field['type'],
120 '#access' => empty($settings['allowed_values_function']),
123 // Alter the description for allowed values depending on the widget type.
124 if ($instance['widget']['type'] == 'options_onoff') {
125 $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>';
127 elseif ($instance['widget']['type'] == 'options_buttons') {
128 $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>';
130 $form['allowed_values']['#description'] .
= t('Allowed HTML tags in labels: @tags', array('@tags' => _field_filter_xss_display_allowed_tags()));
132 $form['allowed_values_function'] = array(
134 '#value' => $settings['allowed_values_function'],
136 $form['allowed_values_function_display'] = array(
138 '#title' => t('Allowed values list'),
139 '#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'])),
140 '#access' => !empty($settings['allowed_values_function']),
147 * Implements hook_field_create_field().
149 function list_field_create_field($field) {
150 if (array_key_exists($field['type'], list_field_info())) {
151 // Clear the static cache of allowed values for $field.
152 $allowed_values = &drupal_static('list_allowed_values', array());
153 unset($allowed_values[$field['field_name']]);
158 * Implements hook_field_update_field().
160 function list_field_update_field($field, $prior_field, $has_data) {
161 if (array_key_exists($field['type'], list_field_info())) {
162 // Clear the static cache of allowed values for $field.
163 $allowed_values = &drupal_static('list_allowed_values', array());
164 unset($allowed_values[$field['field_name']]);
169 * Create an array of allowed values for this field.
171 function list_allowed_values($field) {
172 // This static cache must be cleared whenever $field['field_name']
173 // changes. This includes when it is created because a different
174 // field with the same name may have previously existed, as well
175 // as when it is updated.
176 $allowed_values = &drupal_static(__FUNCTION__
, array());
178 if (isset($allowed_values[$field['field_name']])) {
179 return $allowed_values[$field['field_name']];
182 $allowed_values[$field['field_name']] = array();
184 $function = $field['settings']['allowed_values_function'];
185 if (!empty($function) && function_exists($function)) {
186 $allowed_values[$field['field_name']] = $function($field);
188 elseif (!empty($field['settings']['allowed_values'])) {
189 $allowed_values[$field['field_name']] = list_allowed_values_list($field['settings']['allowed_values'], $field['type'] == 'list');
192 return $allowed_values[$field['field_name']];
196 * Create an array of the allowed values for this field.
198 * Explode a string with keys and labels separated with '|' and with each new
199 * value on its own line.
201 * @param $string_values
202 * The list of choices as a string.
203 * @param $position_keys
204 * Boolean value indicating whether to generate keys based on the position of
205 * the value if a key is not manually specified, effectively generating
206 * integer-based keys. This should only be TRUE for fields that have a type of
207 * "list". Otherwise the value will be used as the key if not specified.
209 function list_allowed_values_list($string_values, $position_keys = FALSE
) {
210 $allowed_values = array();
212 $list = explode("\n", $string_values);
213 $list = array_map('trim', $list);
214 $list = array_filter($list, 'strlen');
215 foreach ($list as
$key => $value) {
216 // Sanitize the user input with a permissive filter.
217 $value = field_filter_xss($value);
219 // Check for a manually specified key.
220 if (strpos($value, '|') !== FALSE
) {
221 list($key, $value) = explode('|', $value);
223 // Otherwise see if we need to use the value as the key. The "list" type
224 // will automatically convert non-keyed lines to integers.
225 elseif (!$position_keys) {
228 $allowed_values[$key] = (isset($value) && $value !== '') ?
$value : $key;
231 return $allowed_values;
235 * Element validate callback; check that the entered values are valid.
237 function list_allowed_values_validate($element, &$form_state) {
238 $values = list_allowed_values_list($element['#value'], $element['#list_field_type'] == 'list');
239 $field_type = $element['#list_field_type'];
241 // Check that keys are valid for the field type.
242 foreach ($values as
$key => $value) {
243 if ($field_type == 'list_number' && !is_numeric($key)) {
244 form_error($element, t('Allowed values list: each key must be a valid integer or decimal.'));
247 elseif ($field_type == 'list_text' && strlen($key) > 255) {
248 form_error($element, t('Allowed values list: each key must be a string less than 255 characters.'));
251 elseif ($field_type == 'list' && !preg_match('/^-?\d+$/', $key)) {
252 form_error($element, t('Allowed values list: keys must be integers.'));
255 elseif ($field_type == 'list_boolean' && !in_array($key, array('0', '1'))) {
256 form_error($element, t('Allowed values list: keys must be either 0 or 1.'));
261 // Check that boolean fields get two values.
262 if ($field_type == 'list_boolean' && count($values) != 2) {
263 form_error($element, t('Allowed values list: two values are required.'));
268 * Implements hook_field_validate().
270 * Possible error codes:
271 * - 'list_illegal_value': The value is not part of the list of allowed values.
273 function list_field_validate($obj_type, $object, $field, $instance, $langcode, $items, &$errors) {
274 $allowed_values = list_allowed_values($field);
275 foreach ($items as
$delta => $item) {
276 if (!empty($item['value'])) {
277 if (count($allowed_values) && !array_key_exists($item['value'], $allowed_values)) {
278 $errors[$field['field_name']][$langcode][$delta][] = array(
279 'error' => 'list_illegal_value',
280 'message' => t('%name: illegal value.', array('%name' => t($instance['label']))),
288 * Implements hook_field_is_empty().
290 function list_field_is_empty($item, $field) {
291 if (empty($item['value']) && (string)$item['value'] !== '0') {
298 * Implements hook_field_formatter_info().
300 function list_field_formatter_info() {
302 'list_default' => array(
303 'label' => t('Default'),
304 'field types' => array('list', 'list_boolean', 'list_text', 'list_number'),
308 'field types' => array('list', 'list_boolean', 'list_text', 'list_number'),
314 * Implements hook_field_formatter().
316 function list_field_formatter($object_type, $object, $field, $instance, $langcode, $items, $display) {
319 switch ($display['type']) {
321 $allowed_values = list_allowed_values($field);
322 foreach ($items as
$delta => $item) {
323 if (isset($allowed_values[$item['value']])) {
324 $output = $allowed_values[$item['value']];
327 // If no match was found in allowed values, fall back to the key.
330 $element[$delta] = array('#markup' => $output);
335 foreach ($items as
$delta => $item) {
336 $element[$delta] = array('#markup' => $item['value']);