Drupal PHP Cross Reference Content Management Systems

Source: /modules/field/modules/number/number.module - 419 lines - 15245 bytes - Summary - Text - Print

   1  <?php
   2  
   3  /**
   4   * @file
   5   * Defines numeric field types.
   6   */
   7  
   8  /**
   9   * Implements hook_help().
  10   */
  11  function number_help($path, $arg) {
  12    switch ($path) {
  13      case 'admin/help#number':
  14        $output = '';
  15        $output .= '<h3>' . t('About') . '</h3>';
  16        $output .= '<p>' . t('The Number module defines various numeric field types for the Field module. Numbers can be in integer, decimal, or floating-point form, and they can be formatted when displayed. Number fields can be limited to a specific set of input values or to a range of values. See the <a href="@field-help">Field module help page</a> for more information about fields.', array('@field-help' => url('admin/help/field'))) . '</p>';
  17        return $output;
  18    }
  19  }
  20  
  21  /**
  22   * Implements hook_field_info().
  23   */
  24  function number_field_info() {
  25    return array(
  26      'number_integer' => array(
  27        'label' => t('Integer'),
  28        'description' => t('This field stores a number in the database as an integer.'),
  29        'instance_settings' => array('min' => '', 'max' => '', 'prefix' => '', 'suffix' => ''),
  30        'default_widget' => 'number',
  31        'default_formatter' => 'number_integer',
  32      ),
  33      'number_decimal' => array(
  34        'label' => t('Decimal'),
  35        'description' => t('This field stores a number in the database in a fixed decimal format.'),
  36        'settings' => array('precision' => 10, 'scale' => 2, 'decimal_separator' => '.'),
  37        'instance_settings' => array('min' => '', 'max' => '', 'prefix' => '', 'suffix' => ''),
  38        'default_widget' => 'number',
  39        'default_formatter' => 'number_decimal',
  40      ),
  41      'number_float' => array(
  42        'label' => t('Float'),
  43        'description' => t('This field stores a number in the database in a floating point format.'),
  44        'settings' => array('decimal_separator' => '.'),
  45        'instance_settings' => array('min' => '', 'max' => '', 'prefix' => '', 'suffix' => ''),
  46        'default_widget' => 'number',
  47        'default_formatter' => 'number_decimal',
  48      ),
  49    );
  50  }
  51  
  52  /**
  53   * Implements hook_field_settings_form().
  54   */
  55  function number_field_settings_form($field, $instance, $has_data) {
  56    $settings = $field['settings'];
  57    $form = array();
  58  
  59    if ($field['type'] == 'number_decimal') {
  60      $form['precision'] = array(
  61        '#type' => 'select',
  62        '#title' => t('Precision'),
  63        '#options' => drupal_map_assoc(range(10, 32)),
  64        '#default_value' => $settings['precision'],
  65        '#description' => t('The total number of digits to store in the database, including those to the right of the decimal.'),
  66        '#disabled' => $has_data,
  67      );
  68      $form['scale'] = array(
  69        '#type' => 'select',
  70        '#title' => t('Scale'),
  71        '#options' => drupal_map_assoc(range(0, 10)),
  72        '#default_value' => $settings['scale'],
  73        '#description' => t('The number of digits to the right of the decimal.'),
  74        '#disabled' => $has_data,
  75      );
  76    }
  77    if ($field['type'] == 'number_decimal' || $field['type'] == 'number_float') {
  78      $form['decimal_separator'] = array(
  79        '#type' => 'select',
  80        '#title' => t('Decimal marker'),
  81        '#options' => array('.' => t('Decimal point'), ',' => t('Comma')),
  82        '#default_value' => $settings['decimal_separator'],
  83        '#description' => t('The character users will input to mark the decimal point in forms.'),
  84      );
  85    }
  86  
  87    return $form;
  88  }
  89  
  90  /**
  91   * Implements hook_field_instance_settings_form().
  92   */
  93  function number_field_instance_settings_form($field, $instance) {
  94    $settings = $instance['settings'];
  95  
  96    $form['min'] = array(
  97      '#type' => 'textfield',
  98      '#title' => t('Minimum'),
  99      '#default_value' => $settings['min'],
 100      '#description' => t('The minimum value that should be allowed in this field. Leave blank for no minimum.'),
 101      '#element_validate' => array('element_validate_number'),
 102    );
 103    $form['max'] = array(
 104      '#type' => 'textfield',
 105      '#title' => t('Maximum'),
 106      '#default_value' => $settings['max'],
 107      '#description' => t('The maximum value that should be allowed in this field. Leave blank for no maximum.'),
 108      '#element_validate' => array('element_validate_number'),
 109    );
 110    $form['prefix'] = array(
 111      '#type' => 'textfield',
 112      '#title' => t('Prefix'),
 113      '#default_value' => $settings['prefix'],
 114      '#size' => 60,
 115      '#description' => t("Define a string that should be prefixed to the value, like '$ ' or '&euro; '. Leave blank for none. Separate singular and plural values with a pipe ('pound|pounds')."),
 116    );
 117    $form['suffix'] = array(
 118      '#type' => 'textfield',
 119      '#title' => t('Suffix'),
 120      '#default_value' => $settings['suffix'],
 121      '#size' => 60,
 122      '#description' => t("Define a string that should be suffixed to the value, like ' m', ' kb/s'. Leave blank for none. Separate singular and plural values with a pipe ('pound|pounds')."),
 123    );
 124  
 125    return $form;
 126  }
 127  
 128  /**
 129   * Implements hook_field_validate().
 130   *
 131   * Possible error codes:
 132   * - 'number_min': The value is less than the allowed minimum value.
 133   * - 'number_max': The value is greater than the allowed maximum value.
 134   */
 135  function number_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
 136    foreach ($items as $delta => $item) {
 137      if ($item['value'] != '') {
 138        if (is_numeric($instance['settings']['min']) && $item['value'] < $instance['settings']['min']) {
 139          $errors[$field['field_name']][$langcode][$delta][] = array(
 140            'error' => 'number_min',
 141            'message' => t('%name: the value may be no less than %min.', array('%name' => $instance['label'], '%min' => $instance['settings']['min'])),
 142          );
 143        }
 144        if (is_numeric($instance['settings']['max']) && $item['value'] > $instance['settings']['max']) {
 145          $errors[$field['field_name']][$langcode][$delta][] = array(
 146            'error' => 'number_max',
 147            'message' => t('%name: the value may be no greater than %max.', array('%name' => $instance['label'], '%max' => $instance['settings']['max'])),
 148          );
 149        }
 150      }
 151    }
 152  }
 153  
 154  /**
 155   * Implements hook_field_presave().
 156   */
 157  function number_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
 158    if ($field['type'] == 'number_decimal') {
 159      // Let PHP round the value to ensure consistent behavior across storage
 160      // backends.
 161      foreach ($items as $delta => $item) {
 162        if (isset($item['value'])) {
 163          $items[$delta]['value'] = round($item['value'], $field['settings']['scale']);
 164        }
 165      }
 166    }
 167  }
 168  
 169  /**
 170   * Implements hook_field_is_empty().
 171   */
 172  function number_field_is_empty($item, $field) {
 173    if (empty($item['value']) && (string) $item['value'] !== '0') {
 174      return TRUE;
 175    }
 176    return FALSE;
 177  }
 178  
 179  /**
 180   * Implements hook_field_formatter_info().
 181   */
 182  function number_field_formatter_info() {
 183    return array(
 184      // The 'Default' formatter is different for integer fields on the one hand,
 185      // and for decimal and float fields on the other hand, in order to be able
 186      // to use different default values for the settings.
 187      'number_integer' => array(
 188        'label' => t('Default'),
 189        'field types' => array('number_integer'),
 190        'settings' =>  array(
 191          'thousand_separator' => ' ',
 192          // The 'decimal_separator' and 'scale' settings are not configurable
 193          // through the UI, and will therefore keep their default values. They
 194          // are only present so that the 'number_integer' and 'number_decimal'
 195          // formatters can use the same code.
 196          'decimal_separator' => '.',
 197          'scale' => 0,
 198          'prefix_suffix' => TRUE,
 199        ),
 200      ),
 201      'number_decimal' => array(
 202        'label' => t('Default'),
 203        'field types' => array('number_decimal', 'number_float'),
 204        'settings' =>  array(
 205          'thousand_separator' => ' ',
 206          'decimal_separator' => '.',
 207          'scale' => 2,
 208          'prefix_suffix' => TRUE,
 209        ),
 210      ),
 211      'number_unformatted' => array(
 212        'label' => t('Unformatted'),
 213        'field types' => array('number_integer', 'number_decimal', 'number_float'),
 214      ),
 215    );
 216  }
 217  
 218  /**
 219   * Implements hook_field_formatter_settings_form().
 220   */
 221  function number_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
 222    $display = $instance['display'][$view_mode];
 223    $settings = $display['settings'];
 224  
 225    if ($display['type'] == 'number_decimal' || $display['type'] == 'number_integer') {
 226      $options = array(
 227        ''  => t('<none>'),
 228        '.' => t('Decimal point'),
 229        ',' => t('Comma'),
 230        ' ' => t('Space'),
 231      );
 232      $element['thousand_separator'] = array(
 233        '#type' => 'select',
 234        '#title' => t('Thousand marker'),
 235        '#options' => $options,
 236        '#default_value' => $settings['thousand_separator'],
 237      );
 238  
 239      if ($display['type'] == 'number_decimal') {
 240        $element['decimal_separator'] = array(
 241          '#type' => 'select',
 242          '#title' => t('Decimal marker'),
 243          '#options' => array('.' => t('Decimal point'), ',' => t('Comma')),
 244          '#default_value' => $settings['decimal_separator'],
 245        );
 246        $element['scale'] = array(
 247          '#type' => 'select',
 248          '#title' => t('Scale'),
 249          '#options' => drupal_map_assoc(range(0, 10)),
 250          '#default_value' => $settings['scale'],
 251          '#description' => t('The number of digits to the right of the decimal.'),
 252        );
 253      }
 254  
 255      $element['prefix_suffix'] = array(
 256        '#type' => 'checkbox',
 257        '#title' => t('Display prefix and suffix.'),
 258        '#default_value' => $settings['prefix_suffix'],
 259      );
 260    }
 261  
 262    return $element;
 263  }
 264  
 265  /**
 266   * Implements hook_field_formatter_settings_summary().
 267   */
 268  function number_field_formatter_settings_summary($field, $instance, $view_mode) {
 269    $display = $instance['display'][$view_mode];
 270    $settings = $display['settings'];
 271  
 272    $summary = array();
 273    if ($display['type'] == 'number_decimal' || $display['type'] == 'number_integer') {
 274      $summary[] = number_format(1234.1234567890, $settings['scale'], $settings['decimal_separator'], $settings['thousand_separator']);
 275      if ($settings['prefix_suffix']) {
 276        $summary[] = t('Display with prefix and suffix.');
 277      }
 278    }
 279  
 280    return implode('<br />', $summary);
 281  }
 282  
 283  /**
 284   * Implements hook_field_formatter_view().
 285   */
 286  function number_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
 287    $element = array();
 288    $settings = $display['settings'];
 289  
 290    switch ($display['type']) {
 291      case 'number_integer':
 292      case 'number_decimal':
 293        foreach ($items as $delta => $item) {
 294          $output = number_format($item['value'], $settings['scale'], $settings['decimal_separator'], $settings['thousand_separator']);
 295          if ($settings['prefix_suffix']) {
 296            $prefixes = isset($instance['settings']['prefix']) ? array_map('field_filter_xss', explode('|', $instance['settings']['prefix'])) : array('');
 297            $suffixes = isset($instance['settings']['suffix']) ? array_map('field_filter_xss', explode('|', $instance['settings']['suffix'])) : array('');
 298            $prefix = (count($prefixes) > 1) ? format_plural($item['value'], $prefixes[0], $prefixes[1]) : $prefixes[0];
 299            $suffix = (count($suffixes) > 1) ? format_plural($item['value'], $suffixes[0], $suffixes[1]) : $suffixes[0];
 300            $output = $prefix . $output . $suffix;
 301          }
 302          $element[$delta] = array('#markup' => $output);
 303        }
 304        break;
 305  
 306      case 'number_unformatted':
 307        foreach ($items as $delta => $item) {
 308          $element[$delta] = array('#markup' => $item['value']);
 309        }
 310        break;
 311    }
 312  
 313    return $element;
 314  }
 315  
 316  /**
 317   * Implements hook_field_widget_info().
 318   */
 319  function number_field_widget_info() {
 320    return array(
 321      'number' => array(
 322        'label' => t('Text field'),
 323        'field types' => array('number_integer', 'number_decimal', 'number_float'),
 324      ),
 325    );
 326  }
 327  
 328  /**
 329   * Implements hook_field_widget_form().
 330   */
 331  function number_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
 332    $value = isset($items[$delta]['value']) ? $items[$delta]['value'] : '';
 333    // Substitute the decimal separator.
 334    if ($field['type'] == 'number_decimal' || $field['type'] == 'number_float') {
 335      $value = strtr($value, '.', $field['settings']['decimal_separator']);
 336    }
 337  
 338    $element += array(
 339      '#type' => 'textfield',
 340      '#default_value' => $value,
 341      // Allow a slightly larger size that the field length to allow for some
 342      // configurations where all characters won't fit in input field.
 343      '#size' => $field['type'] == 'number_decimal' ? $field['settings']['precision'] + 4 : 12,
 344      // Allow two extra characters for signed values and decimal separator.
 345      '#maxlength' => $field['type'] == 'number_decimal' ? $field['settings']['precision'] + 2 : 10,
 346      // Extract the number type from the field type name for easier validation.
 347      '#number_type' => str_replace('number_', '', $field['type']),
 348    );
 349  
 350    // Add prefix and suffix.
 351    if (!empty($instance['settings']['prefix'])) {
 352      $prefixes = explode('|', $instance['settings']['prefix']);
 353      $element['#field_prefix'] = field_filter_xss(array_pop($prefixes));
 354    }
 355    if (!empty($instance['settings']['suffix'])) {
 356      $suffixes = explode('|', $instance['settings']['suffix']);
 357      $element['#field_suffix'] = field_filter_xss(array_pop($suffixes));
 358    }
 359  
 360    $element['#element_validate'][] = 'number_field_widget_validate';
 361  
 362    return array('value' => $element);
 363  }
 364  
 365  /**
 366   * FAPI validation of an individual number element.
 367   */
 368  function number_field_widget_validate($element, &$form_state) {
 369    $field = field_widget_field($element, $form_state);
 370    $instance = field_widget_instance($element, $form_state);
 371  
 372    $type = $element['#number_type'];
 373    $value = $element['#value'];
 374  
 375    // Reject invalid characters.
 376    if (!empty($value)) {
 377      switch ($type) {
 378        case 'float':
 379        case 'decimal':
 380          $regexp = '@([^-0-9\\' . $field['settings']['decimal_separator'] . '])|(.-)@';
 381          $message = t('Only numbers and the decimal separator (@separator) allowed in %field.', array('%field' => $instance['label'], '@separator' => $field['settings']['decimal_separator']));
 382          break;
 383  
 384        case 'integer':
 385          $regexp = '@([^-0-9])|(.-)@';
 386          $message = t('Only numbers are allowed in %field.', array('%field' => $instance['label']));
 387          break;
 388      }
 389      if ($value != preg_replace($regexp, '', $value)) {
 390        form_error($element, $message);
 391      }
 392      else {
 393        if ($type == 'decimal' || $type == 'float') {
 394          // Verify that only one decimal separator exists in the field.
 395          if (substr_count($value, $field['settings']['decimal_separator']) > 1) {
 396            $message = t('%field: There should only be one decimal separator (@separator).',
 397              array(
 398                '%field' => t($instance['label']),
 399                '@separator' => $field['settings']['decimal_separator'],
 400              )
 401            );
 402            form_error($element, $message);
 403          }
 404          else {
 405            // Substitute the decimal separator; things should be fine.
 406            $value = strtr($value, $field['settings']['decimal_separator'], '.');
 407          }
 408        }
 409        form_set_value($element, $value, $form_state);
 410      }
 411    }
 412  }
 413  
 414  /**
 415   * Implements hook_field_widget_error().
 416   */
 417  function number_field_widget_error($element, $error, $form, &$form_state) {
 418    form_error($element['value'], $error['message']);
 419  }

title

Description

title

Description

title

Description

title

title

Body