You are here

units_field.module in Units of Measurement 7.2

Provide field type for storing measured values.

File

units_field/units_field.module
View source
<?php

/**
 * @file
 * Provide field type for storing measured values.
 */

/**
 * Implements hook_field_info().
 */
function units_field_field_info() {
  return array(
    'units_value' => array(
      'label' => t('Measured value'),
      'description' => t('Store measured quantities in this field and them seamlessly execute units conversion.'),
      'settings' => array(
        'dimension' => array(
          'type' => 'measure',
          'mathematical_expression' => NULL,
          'measure' => NULL,
        ),
      ),
      'instance_settings' => array(),
      'default_widget' => 'units_value_expression',
      'default_formatter' => 'units_value_expression',
    ),
  );
}

/**
 * Implements hook_field_settings_form().
 */
function units_field_field_settings_form($field, $instance, $has_data) {
  $form = array();
  switch ($field['type']) {
    case 'units_value':
      $form['dimension'] = array(
        '#tree' => TRUE,
      );
      $form['dimension']['type'] = array(
        '#type' => 'radios',
        '#title' => t('Format to specify dimension of this field'),
        '#options' => array(
          'measure' => t('By selecting a measure'),
          'mathematical_expression' => t('By entering mathematical expression'),
        ),
        '#default_value' => $field['settings']['dimension']['type'],
        '#disabled' => $has_data,
      );
      $mathematical_expression = units_mathematical_expression_create_from_postfix($field['settings']['dimension']['mathematical_expression']);
      $form['dimension']['mathematical_expression'] = array(
        '#type' => 'units_mathematical_expression',
        '#title' => t('Mathematical expression'),
        '#description' => t('Specify here mathematical expression that defines dimension of this field.'),
        '#default_value' => $mathematical_expression,
        '#value_format' => 'postfix',
        '#states' => array(
          'visible' => array(
            ':radio[name$="[dimension][type]"]' => array(
              'value' => 'mathematical_expression',
            ),
          ),
        ),
        '#disabled' => $has_data,
      );
      $options = array();
      foreach (units_measure_load_multiple() as $measure) {
        $options[$measure
          ->identifier()] = entity_label($measure
          ->entityType(), $measure);
      }
      $form['dimension']['measure'] = array(
        '#type' => 'radios',
        '#title' => t('Select underlying measure for this field'),
        '#options' => $options,
        '#default_value' => isset($field['settings']['dimension']['measure']) ? $field['settings']['dimension']['measure'] : NULL,
        '#disabled' => $has_data,
        '#states' => array(
          'visible' => array(
            ':radio[name$="[dimension][type]"]' => array(
              'value' => 'measure',
            ),
          ),
        ),
      );
      break;
  }
  return $form;
}

/**
 * Implements hook_field_widget_info().
 */
function units_field_field_widget_info() {
  return array(
    'units_value_expression' => array(
      'label' => t('Mathematical expression'),
      'description' => t('Specify value through mathematical formula'),
      'field types' => array(
        'units_value',
      ),
      'settings' => array(
        'expression_postfix' => NULL,
      ),
    ),
  );
}

/**
 * Implements hook_field_formatter_info().
 */
function units_field_field_formatter_info() {
  return array(
    'units_value_expression' => array(
      'label' => t('Mathematical expression'),
      'description' => t('Format value as mathematical expression'),
      'field types' => array(
        'units_value',
      ),
      'settings' => array(
        'expression_postfix' => NULL,
      ),
    ),
  );
}

/**
 * Implements hook_field_is_empty().
 */
function units_field_field_is_empty($item, $field) {
  switch ($field['type']) {
    case 'units_value':
      return !isset($item['expression']);
      break;
  }
}

/**
 * Implements hook_field_presave().
 */
function units_field_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
  foreach ($items as &$item) {
    $item['expression']
      ->save();
    $item['mathematical_expression_id'] = $item['expression']
      ->getMathematicalExpressionId();
  }
}

/**
 * Implements hook_field_load().
 */
function units_field_field_load($entity_type, $entities, $field, $instances, $langcode, &$items, $age) {

  // TODO: this should be replaced with a batch load in a single SQL SELECT.
  foreach ($entities as $id => $entity) {
    foreach ($items[$id] as $delta => $item) {
      $items[$id][$delta]['expression'] = units_mathematical_expression_load($item['mathematical_expression_id']);
    }
  }
}

/**
 * Implements hook_field_delete().
 */
function units_field_field_delete($entity_type, $entity, $field, $instance, $langcode, &$items) {

  // TODO: this should be replaced with a batch delete in a single SQL DELETE.
  foreach ($items as $item) {
    units_mathematical_expression_delete($item['mathematical_expression_id']);
  }
}

/**
 * Implements hook_field_delete_revision().
 */
function units_field_field_delete_revision($entity_type, $entity, $field, $instance, $langcode, &$items) {

  // TODO: this should be replaced with a batch delete in a single SQL DELETE.
  foreach ($items as $item) {
    units_mathematical_expression_delete($item['mathematical_expression_id']);
  }
}

/**
 * Implements hook_field_validate().
 */
function units_field_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
  foreach ($items as $delta => $item) {
    try {
      if ($item['expression']) {
        $item['expression']
          ->getExpression()
          ->evaluate();
      }
    } catch (UnitsMathematicalExpressionDimensionException $e) {
      $errors[$field['field_name']][$langcode][$delta][] = array(
        'error' => 'units_mathematical_expression_dimension_inconsistency',
        'message' => t('%name: the mathematical expression contains dimension inconsistency. Details: @exception', array(
          '%name' => $instance['label'],
          '@exception' => $e
            ->getMessage(),
        )),
      );
    } catch (UnitsMathematicalExpressionMalformedException $e) {
      $errors[$field['field_name']][$langcode][$delta][] = array(
        'error' => 'units_mathematical_expression_malformed',
        'message' => t('%name: the mathematical expression is malformed. Details: @exception', array(
          '%name' => $instance['label'],
          '@exception' => $e
            ->getMessage(),
        )),
      );
    }
  }
}

/**
 * Implements hook_field_widget_form().
 */
function units_field_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
  switch ($instance['widget']['type']) {
    case 'units_value_expression':
      $element['expression'] = array(
        '#type' => 'units_mathematical_expression',
        '#title' => $instance['label'],
        '#required' => $element['#required'],
        '#value_format' => 'object',
        '#default_value' => isset($items[$delta]['expression']) ? $items[$delta]['expression'] : NULL,
        '#allowed_dimension' => units_field_dimension($field),
      );
      break;
  }
  return $element;
}

/**
 * Implements hook_field_formatter_settings_form().
 */
function units_field_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
  $display = $instance['display'][$view_mode];
  $settings = $display['settings'];
  $element = array();
  switch ($display['type']) {
    case 'units_value_expression':
      $mathematical_expression = NULL;
      if (isset($settings['expression_postfix'])) {
        $mathematical_expression = units_mathematical_expression_create_from_postfix($settings['expression_postfix']);
      }
      $element['expression_postfix'] = array(
        '#type' => 'units_mathematical_expression',
        '#title' => t('Output as the following'),
        '#value_format' => 'postfix',
        '#default_value' => $mathematical_expression,
        '#description' => t('Specify here mathematical expression. All constant members of this mathematical expression will be replaced by real values from the field data. Leave empty to output in original format.'),
        '#allowed_dimension' => units_field_dimension($field),
      );
      break;
  }
  return $element;
}

/**
 * Implements hook_field_formatter_settings_summary().
 */
function units_field_field_formatter_settings_summary($field, $instance, $view_mode) {
  $display = $instance['display'][$view_mode];
  $summary = '';
  switch ($display['type']) {
    case 'units_value_expression':
      $mathematical_expression = units_field_display_mathematical_expression($display);
      $summary = $mathematical_expression ? check_plain($mathematical_expression
        ->getExpression()
        ->toInfix()) : t('Original');
      break;
  }
  return $summary;
}

/**
 * Implements hook_field_formatter_view().
 */
function units_field_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $element = array();
  switch ($display['type']) {
    case 'units_value_expression':
      foreach ($items as $delta => $item) {
        $output_mathematical_expression = units_field_display_mathematical_expression($display);
        if (is_object($output_mathematical_expression)) {
          $output_mathematical_expression = $output_mathematical_expression
            ->getExpression();
          units_mathematical_expression_format_as($item['expression']
            ->getExpression(), $output_mathematical_expression);
        }
        else {

          // Since no output format was given, we output it in original
          // mathematical expression.
          $output_mathematical_expression = $item['expression']
            ->getExpression();
        }
        $element[$delta] = array(
          '#markup' => check_plain($output_mathematical_expression
            ->toInfix()),
        );
      }
      break;
  }
  return $element;
}

/**
 * Retrieve allowed dimension for a provided field.
 *
 * @param array $field
 *   Field definition array for which to determine allowed dimension
 *
 * @return array
 *   Dimension array that is allowed in the provided field
 */
function units_field_dimension($field) {
  $mathematical_expression = NULL;
  switch ($field['settings']['dimension']['type']) {
    case 'mathematical_expression':
      $mathematical_expression = units_mathematical_expression_create_from_postfix($field['settings']['dimension']['mathematical_expression'])
        ->getExpression();
      break;
    case 'measure':
      $efq = new EntityFieldQuery();
      $efq
        ->entityCondition('entity_type', 'units_unit');
      $efq
        ->entityCondition('bundle', $field['settings']['dimension']['measure']);
      $efq
        ->range(0, 1);
      $result = $efq
        ->execute();
      $result = array_keys($result['units_unit']);
      $mathematical_expression = units_unit_load(reset($result));
      break;
  }
  return $mathematical_expression
    ->dimension();
}

/**
 * Fetch expected output format from the provided display.
 *
 * @param array $display
 *   Display whose expected output format should be fetched
 *
 * @return UnitsMathematicalExpressionWrapper
 *   Expected output format from the provided display in the form of
 *   mathematical expression object. If none is defined in the provided display,
 *   NULL is returned
 */
function units_field_display_mathematical_expression($display) {

  // We replace all constants with 1, to make sure quantity can be distributed
  // properly.
  $expression_postfix = $display['settings']['expression_postfix'];
  $expression_postfix = preg_replace('#\\b\\d+\\b#', 1, $expression_postfix);
  return units_mathematical_expression_create_from_postfix($expression_postfix);
}