You are here

function _mvf_widget_process in Measured Value Field 7

Process function for form element type 'mvf_widget'.

Expand for element into an input for value and an input for unit measure in accordance with field settings for which form element is generated.

1 string reference to '_mvf_widget_process'
mvf_element_info in ./mvf.module
Implements hook_element_info().

File

./mvf.module, line 1159
Define a field type of measured value.

Code

function _mvf_widget_process($element, &$form_state, $form) {

  // Additionally values may be provided in #default_value property. So we
  // check it too.
  if (empty($element['#items']) && isset($element['#default_value'])) {
    $element['#delta'] = 0;
    $element['#items'] = array(
      $element['#default_value'],
    );
  }
  $form_fields = array();
  $field = $element['#field'];
  $instance = $element['#instance'];
  $items = $element['#items'];
  if (!isset($element['#field_name'])) {
    $element['#field_name'] = $element['#field']['field_name'];
  }
  if (!isset($element['#bundle'])) {
    $element['#bundle'] = $instance['bundle'];
  }
  uasort($instance['widget']['settings']['meta_info'], 'drupal_sort_weight');
  foreach ($instance['widget']['settings']['meta_info'] as $subfield => $meta_info) {
    $meta_info = $field['settings']['meta_info'][$subfield];
    $mocked_field = mvf_field_mockup($field, $subfield);
    $mocked_instance = mvf_instance_mockup($field, $instance, $subfield);

    // We have to extra process $mocked_field in order to make it work with
    // options module. It gets default value based on looking into the key
    // of first element in $field['columns'] array. Thus we have to make the
    // current subfield column first in columns array.
    $column_name = mvf_subfield_to_column($subfield);
    $column = array(
      $column_name => $mocked_field['columns'][$column_name],
    );
    $mocked_field['columns'] = $column + $mocked_field['columns'];
    $function = $mocked_instance['widget']['module'] . '_field_widget_form';
    $extra = FALSE;
    if (function_exists($function)) {

      // Since we mock sub fields as if the cardinality is 1 (we handle real
      // cardinality in our own field), we have to mock $items array to
      // represent "truth" for the subfield, i.e. $items array should only
      // include the current item and nothing else, this way we are able to mock
      // the cardinality 1 for our sub fields.
      $mocked_delta = 0;
      $mocked_items = isset($items[$element['#delta']]) ? array(
        $mocked_delta => $items[$element['#delta']],
      ) : array();
      switch ($subfield) {
        case 'value':
          break;
        case 'unit':
          if (empty($mocked_items)) {
            $mocked_items[] = array(
              mvf_subfield_to_column('unit') => mvf_unit_suggest($mocked_items, $field, $instance, $element['#entity'], NULL, array(
                MVF_UNIT_ORIGINAL,
              )),
            );
          }
          break;
      }
      $tmp = array(
        '#entity_type' => $element['#entity_type'],
        '#bundle' => $element['#bundle'],
        '#field_name' => $element['#field_name'],
        '#language' => $element['#language'],
        '#field_parents' => $element['#field_parents'],
        // @todo: #columns.
        '#description' => '',
        '#required' => $element['#required'],
        '#delta' => $mocked_delta,
        '#entity' => (object) array(),
      );
      if (isset($element['#title'])) {
        $tmp['#title'] = $element['#title'];
      }
      if (isset($element['#entity'])) {
        $tmp['#entity'] = $element['#entity'];
      }
      $extra = $function($form, $form_state, $mocked_field, $mocked_instance, $element['#language'], $mocked_items, $mocked_delta, $tmp);
    }
    if (is_array($extra) && !empty($extra)) {
      $extra = isset($extra[$subfield]) ? $extra[$subfield] : $extra;
      unset($extra['#description']);
      $extra['#title'] = isset($extra['#title']) ? $extra['#title'] . ' ' . $meta_info['label'] : $meta_info['label'];
      $extra['#title_display'] = 'invisible';

      // Doing any sub field specific customizations of subfield output.
      switch ($subfield) {
        case 'unit':
          if ($mocked_instance['widget']['module'] == 'options') {

            // Options module messes things up for us in its element validate
            // function. So we have to clean things up in our own element
            // validate function that will be run after the options' one.
            $extra['#element_validate'][] = 'mvf_field_widget_unit_options_validate';

            // Additionally we have to make sure the labeling is consistent with
            // what we have in widget settings. By default options module
            // generate options for EntityReference fields based on 'label'
            // property of each entity. MVF needs to support labeling by
            // 'symbol' property too. Thus if our widget is set up to generate
            // options based on 'symbol' property, we have to slightly adjust
            // the already generated #options array.
            switch ($instance['widget']['settings']['meta_info']['unit']['label_property']) {
              case 'symbol':

                // Let's substitute labels of entities by their symbols.
                if (!empty($extra['#options'])) {
                  $umids = $extra['#options'];
                  unset($umids['_none']);
                  $umids = array_keys($umids);
                  $units = units_unit_load_multiple($umids);
                  $options = array();
                  foreach ($units as $k => $unit) {
                    $label = $unit->{$instance['widget']['settings']['meta_info']['unit']['label_property']} ? $unit->{$instance['widget']['settings']['meta_info']['unit']['label_property']} : entity_label('units_unit', $unit);
                    $options[$k] = $label;
                  }

                  // Resort the new options array, because alphabetical order
                  // probably has changed.
                  asort($options);

                  // Putting on top of the new options array the 'None' option
                  // if it was originally present.
                  if (isset($extra['#options']['_none'])) {
                    $options = array(
                      '_none' => $extra['#options']['_none'],
                    ) + $options;
                  }
                  $extra['#options'] = $options;
                }
                break;
            }
          }
          break;
        case 'value':

          // Number module uses FAPI element validate function
          // number_field_widget_validate() for validating user input. That
          // function retrieves info about field and instance from $form_state.
          // Apparently in our case things go bad, because it retrieves info
          // about MVF field, instead of expected number sub field. We have to
          // to override $form_state before that validation function and then
          // return $form_state back to how it was after running Number's module
          // validation function.
          array_unshift($extra['#element_validate'], 'mvf_field_widget_validate_value_form_state_mockup_override');
          $extra['#element_validate'][] = 'mvf_field_widget_validate_value_form_state_mockup_revert';
          break;
      }
      if (isset($element['#dependency'])) {
        $extra['#dependency'] = $element['#dependency'];
      }
      if (isset($element['#states'])) {
        $extra['#states'] = $element['#states'];
      }
      $form_fields[$column_name] = $extra;
    }
  }
  $element += $form_fields;
  $element['label'] = array(
    '#type' => 'item',
    '#title' => isset($element['#title']) ? $element['#title'] : $instance['label'],
    '#title_display' => $element['#title_display'],
    '#required' => $element['#required'],
    '#weight' => -10,
  );
  $element['#title_display'] = 'invisible';
  if (isset($element['#dependency'])) {
    $element['label']['#dependency'] = $element['#dependency'];
  }
  if (isset($element['#states'])) {
    $element['label']['#states'] = $element['#states'];
  }
  return $element;
}