boolean.module in Boolean Field 7
Defines boolean field type.
The field has three states: on, off and not set. The corresponding storage values are 1, 0, and -1.
@author Jim Berry ("solotandem", http://drupal.org/user/240748)
File
boolean.moduleView source
<?php
/**
* @file
* Defines boolean field type.
*
* The field has three states: on, off and not set. The corresponding storage
* values are 1, 0, and -1.
*
* @author Jim Berry ("solotandem", http://drupal.org/user/240748)
*/
/**
* Implements hook_help().
*/
function boolean_help($path, $arg) {
switch ($path) {
case 'admin/help#boolean':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Boolean module defines a 3-state boolean field type for the Field module. See the <a href="@field-help">Field module help page</a> for more information about fields.', array(
'@field-help' => url('admin/help/field'),
)) . '</p>';
return $output;
}
}
/**
* Implements hook_field_info().
*
* @todo Adding settings causes 'undefined index' notice until settings are saved.
*/
function boolean_field_info() {
return array(
'number_boolean' => array(
'label' => t('Boolean (3-states)'),
'description' => t('This field stores simple on/off or yes/no options along with a not set state.'),
'instance_settings' => array(
'labels' => array(),
'suppress_warning' => FALSE,
'omit_strings' => FALSE,
'none' => array(
'prefix' => '',
'suffix' => '',
),
'false' => array(
'prefix' => '',
'suffix' => '',
),
'true' => array(
'prefix' => '',
'suffix' => '',
),
),
'default_widget' => 'boolean_checkbox',
'default_formatter' => 'number_boolean',
// For use with Entity API and Rules modules.
'property_type' => 'number_boolean',
),
);
}
/**
* Implements hook_field_settings_form().
*/
function boolean_field_settings_form($field, $instance, $has_data) {
// $settings = $field['settings'];
$form = array();
return $form;
}
/**
* Implements hook_field_instance_settings_form().
*
* Initially build the form without the vertical tabs so that the instance
* settings form items are parented like instance[settings][true][prefix]. If we
* try to build it all at once, then the parenting is nested two more levels
* like instance[settings][state][tabs][true][prefix] and does not line up with
* the instance settings as defined in the hook_field_info().
*
* Then use an #after_build handler to insert the fieldset and vertical tabs.
*/
function boolean_field_instance_settings_form($field, $instance) {
$settings = $instance['settings'];
$defaults = boolean_field_info();
$defaults = $defaults['number_boolean']['instance_settings'];
$settings += $defaults;
$form['labels'] = array(
'#type' => 'textarea',
'#title' => t('Labels'),
'#default_value' => $settings['labels'],
'#cols' => 20,
'#description' => t("The labels to use in place of 'delta' in the display strings and on edit form. Enter one value per line. Only applies if cardinality is not unlimited."),
);
$form['suppress_warning'] = array(
'#type' => 'checkbox',
'#title' => t('Omit warning'),
'#default_value' => $settings['suppress_warning'],
'#description' => t("Omit the 'value not set' warning for unset fields."),
);
$form['omit_strings'] = array(
'#type' => 'checkbox',
'#title' => t('Omit strings'),
'#default_value' => $settings['omit_strings'],
'#description' => t('Omit the prefix and suffix strings on edit form.'),
);
foreach (boolean_value_info() as $state) {
$form[$state] = array(
'#type' => 'fieldset',
'#title' => 'Strings to display when value is ' . $state,
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#tree' => TRUE,
'#weight' => 5,
);
$form[$state]['prefix'] = array(
'#type' => 'textfield',
'#title' => t('Prefix'),
'#default_value' => $settings[$state]['prefix'],
'#size' => 60,
'#description' => t("The string to be prefixed to the 'delta' value. Leave blank for none."),
);
$form[$state]['suffix'] = array(
'#type' => 'textfield',
'#title' => t('Suffix'),
'#default_value' => $settings[$state]['suffix'],
'#size' => 60,
'#description' => t("The string to be suffixed to the 'delta' value. Leave blank for none."),
);
}
$form['#after_build'][] = 'boolean_field_instance_settings_form_after_build';
return $form;
}
/**
* Form handler for after_build.
*
* Rebuild the element form items as vertical tabs. Retain form items added by
* other modules.
*
* @see boolean_field_instance_settings_form()
*/
function boolean_field_instance_settings_form_after_build($element, $form_state) {
$string = 'The display value of this field is equal to its "delta" value surrounded by the prefix and suffix strings defined below.' . ' The "delta" value is only displayed if the "number of values" for this field is greater than one.' . ' For example, if there are five values of this field, then the delta values are numbered zero through four.' . ' The corresponding display values are "prefix delta suffix."';
$element['state'] = array(
'#type' => 'fieldset',
'#title' => 'Display strings',
'#collapsible' => TRUE,
'#collapsed' => FALSE,
'#tree' => FALSE,
'#weight' => 5,
'#description' => t($string),
);
$element['state']['tabs'] = array(
'#type' => 'vertical_tabs',
'#default_tab' => 'edit-true',
);
foreach (boolean_value_info() as $state) {
$element['state']['tabs'][$state] = $element[$state];
unset($element[$state]);
}
return $element;
}
/**
* Implements hook_field_is_empty().
*/
function boolean_field_is_empty($item, $field) {
if (empty($item['value']) && (string) $item['value'] !== '0') {
return TRUE;
}
return FALSE;
}
/**
* Implements hook_field_formatter_info().
*/
function boolean_field_formatter_info() {
return array(
'number_boolean' => array(
'label' => t('Default'),
'field types' => array(
'number_boolean',
),
'settings' => array(
'labels' => FALSE,
'omit_unchecked' => FALSE,
'prefix_suffix' => TRUE,
),
),
);
}
/**
* Implements hook_field_formatter_settings_form().
*/
function boolean_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
// @todo This is not treated as a setting; presence of labels is used.
$element['labels'] = array(
'#type' => 'checkbox',
'#title' => t('Labels'),
'#default_value' => $settings['labels'],
'#description' => t('Display the labels in place of delta.'),
);
$element['omit_unchecked'] = array(
'#type' => 'checkbox',
'#title' => t('Omit unchecked'),
'#default_value' => $settings['omit_unchecked'],
'#description' => t('Omit the value if not checked.'),
);
$element['prefix_suffix'] = array(
'#type' => 'checkbox',
'#title' => t('Display prefix and suffix.'),
'#default_value' => $settings['prefix_suffix'],
);
return $element;
}
/**
* Implements hook_field_formatter_settings_summary().
*/
function boolean_field_formatter_settings_summary($field, $instance, $view_mode) {
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
$labels = $settings['labels'] ? 'labels' : 'delta';
$unchecked = $settings['omit_unchecked'] ? ' only if checked' : '';
$with = $settings['prefix_suffix'] ? 'with' : 'without';
$summary = t('Display !labels !with prefix and suffix!unchecked.', array(
'!labels' => $labels,
'!unchecked' => $unchecked,
'!with' => $with,
));
return $summary;
}
/**
* Returns boolean values and related strings.
*/
function boolean_value_info() {
return array(
-1 => 'none',
0 => 'false',
1 => 'true',
);
}
/**
* Implements hook_field_formatter_view().
*/
function boolean_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
$element = array();
$settings = $display['settings'];
// Allow for a site using the cardinality patch.
// @see https://www.drupal.org/files/issues/1029298-60-move-cardinality-setting.patch
$cardinality = isset($instance['cardinality']) ? $instance['cardinality'] : $field['cardinality'];
$labels = explode("\n", $instance['settings']['labels']);
switch ($display['type']) {
case 'number_boolean':
$display_delta = count($items) > 1;
foreach ($items as $delta => $item) {
if ($settings['omit_unchecked'] && $item['value'] != 1) {
continue;
}
$display_label = '';
if ($cardinality == FIELD_CARDINALITY_UNLIMITED) {
$display_label = $delta;
}
elseif ($settings['labels'] && !empty($labels[$delta])) {
$display_label = $labels[$delta];
}
elseif ($cardinality > 1) {
$display_label = $delta;
}
$prefix = $suffix = '';
$states = boolean_value_info();
$strings = $instance['settings'][$states[$item['value']]];
$class = 'state-' . $states[$item['value']];
// if (TRUE || $item['value']) { // @todo Do we need a check here?
if ($settings['prefix_suffix']) {
$prefix = isset($strings['prefix']) ? $strings['prefix'] . ' ' : 'Instance ';
$suffix = isset($strings['suffix']) ? ' ' . $strings['suffix'] : '';
}
elseif (!$settings['labels']) {
$prefix = 'Instance ';
$suffix = '';
}
$output = '<span class="' . $class . '">';
$output .= $prefix . $display_label . $suffix;
$output .= '</span>';
$element[$delta] = array(
'#markup' => $output,
'#attributes' => array(
'class' => 'state-' . $states[$item['value']],
),
);
// }
}
break;
}
return $element;
}
/**
* Implements hook_field_widget_info().
*/
function boolean_field_widget_info() {
return array(
'boolean_checkbox' => array(
'label' => t('Checkbox'),
'field types' => array(
'number_boolean',
),
'behaviors' => array(
// @todo Is FIELD_BEHAVIOR_CUSTOM what causes the list_boolean field not
// to have multiple values?
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
),
),
);
}
/**
* Implements hook_field_widget_form().
*/
function boolean_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
// Allow for a site using the cardinality patch.
// @see https://www.drupal.org/files/issues/1029298-60-move-cardinality-setting.patch
$cardinality = isset($instance['cardinality']) ? $instance['cardinality'] : $field['cardinality'];
$labels = explode("\n", $instance['settings']['labels']);
// If the boolean field is added to an entity after instances of that entity
// exist, then $delta == count($items) is TRUE when $delta == 0. Add condition
// on $delta > 0 to catch this use case and display the field.
if ($cardinality == FIELD_CARDINALITY_UNLIMITED && $delta && $delta == count($items)) {
// Suppress the automatic display of another item by the Field API to
// prevent the item being added to the database if the form is submitted.
// This should be resolved in HTML 5 when a checkbox will have a third state
// indicating whether it is set.
return array();
}
$is_set = isset($items[$delta]) && $items[$delta]['value'] != -1;
$suppress = empty($instance['settings']['suppress_warning']) ? FALSE : TRUE;
$value = $is_set ? $items[$delta]['value'] : 0;
$display_delta = count($items) > 1;
// @todo Is this ever true? This is passed one item.
$display_label = '';
if ($cardinality == FIELD_CARDINALITY_UNLIMITED) {
$display_label = $delta;
}
elseif (!empty($labels[$delta])) {
$display_label = $labels[$delta];
}
elseif ($cardinality > 1) {
$display_label = $delta;
}
$element += array(
'#type' => 'checkbox',
'#default_value' => $value,
'#on_value' => $on_value = 1,
'#off_value' => $off_value = 0,
'#no_value' => -1,
'#is_set' => $is_set,
);
$prefix = $suffix = '';
if (empty($instance['settings']['omit_strings'])) {
// Add prefix and suffix.
// When editing, always display the text applicable to a true state.
$states = boolean_value_info();
$strings = $instance['settings'][$states[1]];
// [$items[$delta]['value']]];
$prefix = isset($strings['prefix']) ? $strings['prefix'] . ' ' : '';
$suffix = isset($strings['suffix']) ? ' ' . $strings['suffix'] : '';
}
// Set the title.
$element['#title'] = $prefix . $display_label . $suffix;
if (!$is_set && !$suppress) {
// Highlight the field so the user knows it has not been set.
$element['#title'] .= ' (value not set)';
$element += array(
'#prefix' => '<div class="not-set" style="color: red;">',
'#suffix' => '</div>',
);
}
$element['#value_callback'] = 'boolean_field_widget_value';
$element['#element_validate'][] = 'boolean_field_widget_validate';
return array(
'value' => $element,
);
}
/**
* Form element validation handler for boolean field element.
*/
function boolean_field_widget_validate($element, &$form_state, $form) {
$value = $element['#value'];
// Transform '0 / 1' into the 'on / off / not set' values.
if (!$element['#is_set'] && $value === 0) {
$value = $element['#no_value'];
}
else {
$value = $value ? $element['#on_value'] : $element['#off_value'];
}
form_set_value($element, $value, $form_state);
}
/**
* Form element value callback for the boolean field element.
*/
function boolean_field_widget_value($element, $input = FALSE, $form_state = array()) {
if ($input === FALSE) {
return isset($element['#default_value']) ? $element['#default_value'] : 0;
}
else {
// With 3 states, a value of -1 is also considered TRUE. So check for 1.
return $input == 1 ? $input : 0;
}
}
/**
* Implements hook_field_widget_error().
*/
function boolean_field_widget_error($element, $error, $form, &$form_state) {
form_error($element['value'], $error['message']);
}