You are here

field_collection_table.module in Field Collection Table 7

Module implementing a field-collection table formatter.

File

field_collection_table.module
View source
<?php

/**
 * @file
 * Module implementing a field-collection table formatter.
 */

/**
 * Implements hook_field_formatter_info().
 */
function field_collection_table_field_formatter_info() {
  return array(
    'field_collection_table_view' => array(
      'label' => t('Table of field collection items'),
      'field types' => array(
        'field_collection',
      ),
      'settings' => array(
        'edit' => t('Edit'),
        'delete' => t('Delete'),
        'add' => t('Add'),
        'description' => TRUE,
        'view_mode' => 'full',
        'hide_empty' => FALSE,
        'empty' => TRUE,
        'caption' => NULL,
        'orientation' => 'columns',
        'header_column' => 'none',
      ),
    ),
  );
}

/**
 * Implements hook_field_formatter_view().
 */
function field_collection_table_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $element = array();
  $settings = $display['settings'];
  if (empty($items) && !empty($settings['hide_empty'])) {
    return $element;
  }
  if ($settings['orientation'] === 'columns') {
    _field_collection_table_column_mode($element, $settings, $entity_type, $entity, $field, $instance, $langcode, $items, $display);
  }
  if ($settings['orientation'] === 'rows') {
    _field_collection_table_row_mode($element, $settings, $entity_type, $entity, $field, $instance, $langcode, $items, $display);
  }
  field_collection_field_formatter_links($element, $entity_type, $entity, $field, $instance, $langcode, $items, $display);
  return $element;
}

/**
 * Helper function to build the table in column mode.
 */
function _field_collection_table_column_mode(&$element, $settings, $entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $view_mode = !empty($display['settings']['view_mode']) ? $display['settings']['view_mode'] : 'default';
  $header = array();
  $field_names = array();
  foreach (field_info_instances('field_collection_item', $field['field_name']) as $field_collection_item) {
    $item_view_mode = !empty($field_collection_item['display'][$view_mode]) ? $view_mode : 'default';
    if ($field_collection_item['display'][$item_view_mode]['type'] !== 'hidden') {
      $weight = $field_collection_item['display'][$item_view_mode]['weight'];
      $field_names[$weight] = $field_collection_item['field_name'];
      if ($field_collection_item['display'][$item_view_mode]['label'] !== 'hidden') {
        $header[$weight] = array(
          'data' => module_exists('i18n_field') ? i18n_field_translate_property($field_collection_item, 'label') : $field_collection_item['label'],
          'class' => drupal_html_class($field_names[$weight]),
        );
      }
      else {
        $header[$weight] = '';
      }
    }
  }
  if (module_exists('ds')) {
    $fields_ds = ds_get_fields('field_collection_item');
    $fields_ds_settings = ds_get_field_settings('field_collection_item', $field['field_name'], $view_mode);
    foreach ($fields_ds_settings as $name => $ds_settings) {
      if (isset($fields_ds[$name])) {
        $weight = $ds_settings['weight'];
        $field_names[$weight] = $name;
        $header[$weight] = array(
          'data' => $ds_settings['label'] !== 'hidden' ? $fields_ds[$name]['title'] : NULL,
          'class' => drupal_html_class($name),
        );
      }
      elseif (in_array($name, $field_names)) {
        $weight = array_search($name, $field_names);
      }

      // Allow to override field label using DS field format settings.
      if (isset($weight, $ds_settings['formatter_settings']['ft']['lb'])) {
        $header[$weight]['data'] = t(check_plain($ds_settings['formatter_settings']['ft']['lb']));
      }
    }
  }
  ksort($header);
  ksort($field_names);
  $rows = array();
  foreach ($items as $delta => $item) {
    $field_collection = field_collection_field_get_entity($item);
    if (empty($field_collection)) {
      continue;
    }
    $view = $field_collection
      ->view($view_mode);
    $content = $view['field_collection_item'][$field_collection
      ->identifier()];
    $column = array();
    foreach ($field_names as $field_name) {
      $cell = array(
        'class' => drupal_html_class($field_name),
        'data' => array(),
      );
      if (empty($contents[$field_name])) {
        $cell['data'] = array(
          '#markup' => '<span class="empty-field"></span>',
          '#empty' => TRUE,
        );
      }
      else {
        $cell['data'] = $content[$field_name];
        $cell['data-title'] = $content[$field_name]['#title'];
      }
      $column[] = $cell;
    }
    $links = array(
      '#theme' => 'links',
      '#theme_wrapper' => 'item_list',
      '#attributes' => array(
        'class' => array(
          'field-collection-view-links',
        ),
      ),
    );
    foreach (array(
      'edit',
      'delete',
    ) as $op) {
      if (!empty($settings[$op]) && !(module_exists('field_permissions') && !user_access($op . ' ' . $field['field_name'])) && entity_access($op === 'edit' ? 'update' : $op, 'field_collection_item', $field_collection)) {
        $links['#links'][$op] = array(
          'title' => t($settings[$op]),
          'href' => $field_collection
            ->path() . '/' . $op,
          'query' => drupal_get_destination(),
        );
        $header['operations'] = t('Operations');
      }
    }
    if (!empty($links['#links'])) {
      $column[] = array(
        'data' => $links,
        'class' => 'field-operations',
      );
    }
    $rows[] = array(
      'data' => $column,
      'class' => array(
        'field-collection-item',
      ),
    );
  }

  // Remove header if all labels are hidden.
  if (!array_filter($header)) {
    $header = array();
  }
  $element[0] = array(
    '#theme' => 'table',
    '#header' => $header,
    '#rows' => $rows,
    '#caption' => !empty($settings['caption']) ? t($settings['caption']) : NULL,
    '#attributes' => array(
      'class' => array(
        'field-collection-table-view',
        drupal_clean_css_identifier('view-mode-' . $view_mode),
      ),
    ),
  );
  if (!empty($settings['empty'])) {
    $element[0]['#theme'] = 'table__field_collection_table';
    $element[0]['#settings']['empty'] = TRUE;
  }
  return $element;
}

/**
 * Helper function to build the table in row mode.
 */
function _field_collection_table_row_mode(&$element, $settings, $entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $view_mode = !empty($display['settings']['view_mode']) ? $display['settings']['view_mode'] : 'default';
  $labels = array();
  $field_names = array();
  foreach (field_info_instances('field_collection_item', $field['field_name']) as $field_collection_item) {
    $item_view_mode = !empty($field_collection_item['display'][$view_mode]) ? $view_mode : 'default';
    if ($field_collection_item['display'][$item_view_mode]['type'] !== 'hidden') {
      $weight = $field_collection_item['display'][$item_view_mode]['weight'];
      $field_names[$weight] = $field_collection_item['field_name'];
      $labels[$field_collection_item['field_name']] = module_exists('i18n_field') ? i18n_field_translate_property($field_collection_item, 'label') : $field_collection_item['label'];
    }
  }
  if (module_exists('ds')) {
    $fields_ds = ds_get_fields('field_collection_item');
    $fields_ds_settings = ds_get_field_settings('field_collection_item', $field['field_name'], $view_mode);
    foreach ($fields_ds_settings as $name => $ds_settings) {
      if (isset($fields_ds[$name])) {
        $weight = $ds_settings['weight'];
        $labels[$name] = $ds_settings['label'] !== 'hidden' ? $fields_ds[$name]['title'] : NULL;
        $field_names[$weight] = $name;
      }

      // Allow to override field label using DS field format settings.
      if (isset($weight, $ds_settings['formatter_settings']['ft']['lb'])) {
        $labels[$name] = t(check_plain($ds_settings['formatter_settings']['ft']['lb']));
      }
    }
  }
  ksort($field_names);
  $header = array();
  if ($settings['header_column'] !== 'none') {
    $header = array(
      array(
        'class' => array(
          'field-label',
        ),
        'data' => $labels[$settings['header_column']],
      ),
    );
  }
  $rows = array();
  foreach ($items as $delta => $item) {
    $field_collection = field_collection_field_get_entity($item);
    if (empty($field_collection)) {
      continue;
    }
    $view = $field_collection
      ->view();
    $content = $view['field_collection_item'][$field_collection
      ->identifier()];
    foreach ($field_names as $field_name) {
      if (isset($content[$field_name])) {
        $content[$field_name]['#label_display'] = 'hidden';
      }
      else {
        $content[$field_name] = array(
          '#markup' => '<span class="empty-field"></span>',
          '#empty' => TRUE,
        );
      }
      if ($settings['header_column'] === $field_name) {
        unset($labels[$field_name]);
        $header[] = array(
          'data' => $content[$field_name],
        );
        continue;
      }
      $rows[$field_name]['data'][$delta] = array(
        'data' => $content[$field_name],
      );
      $rows[$field_name]['class'] = array(
        drupal_html_class($field_name),
      );
      $links = array(
        '#theme' => 'links',
        '#theme_wrapper' => 'item_list',
        '#attributes' => array(
          'class' => array(
            'field-collection-view-links',
          ),
        ),
      );
      foreach (array(
        'edit',
        'delete',
      ) as $op) {
        if (!empty($settings[$op]) && field_collection_item_access($op === 'edit' ? 'update' : $op, $field_collection)) {
          $links['#links'][$op] = array(
            'title' => $settings[$op],
            'href' => $field_collection
              ->path() . '/' . $op,
            'query' => drupal_get_destination(),
          );
        }
      }
      if (!empty($links['#links'])) {
        $operations[$delta] = array(
          'data' => $links,
          'class' => 'field-operations',
        );
      }
    }
  }
  foreach ($labels as $field_name => $data) {
    array_unshift($rows[$field_name]['data'], array(
      'class' => 'field-label',
      'data' => $data,
    ));
  }
  if (!empty($operations)) {
    array_unshift($operations, array(
      'class' => array(
        'field-label',
      ),
      'data' => t('Operations'),
    ));
    $rows['operations'] = array(
      'class' => array(
        'operations',
      ),
      'data' => $operations,
    );
  }
  $element[0] = array(
    '#theme' => 'table',
    '#header' => $header,
    '#rows' => $rows,
    '#caption' => !empty($settings['caption']) ? t($settings['caption']) : NULL,
    '#attributes' => array(
      'class' => array(
        'field-collection-table-view',
        drupal_clean_css_identifier('view-mode-' . $view_mode),
      ),
    ),
  );
  if (!empty($settings['empty'])) {
    $element[0]['#theme'] = 'table__field_collection_table';
    $element[0]['#settings']['empty'] = TRUE;
  }
}

/**
 * Implements hook_field_formatter_settings_form().
 */
function field_collection_table_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
  $display = $instance['display'][$view_mode];
  $settings = $display['settings'];
  $element = field_collection_field_formatter_settings_form($field, $instance, $view_mode, $form, $form_state);
  $field_collections = field_info_instances('field_collection_item', $instance['field_name']);
  $field_options = array(
    'none' => t('None'),
  );
  foreach ($field_collections as $key => $value) {
    $field_options[$key] = $value['label'];
  }
  if (!empty($element['view_mode'])) {
    $element['view_mode']['#description'] = t('Used to determine which fields should be displayed.');
  }
  $element['hide_empty'] = array(
    '#type' => 'checkbox',
    '#title' => t('Hide empty collection'),
    '#default_value' => $settings['hide_empty'],
    '#description' => t('If enabled, nothing will be displayed for an empty collection (not even the add link).'),
  );
  $element['empty'] = array(
    '#type' => 'checkbox',
    '#title' => t('Hide empty columns'),
    '#description' => t('If checked, hides empty table columns.'),
    '#default_value' => $settings['empty'],
  );
  $element['caption'] = array(
    '#type' => 'textfield',
    '#title' => t('Table caption'),
    '#description' => t('Displayed in the caption element above the table'),
    '#default_value' => $settings['caption'],
  );
  $element['orientation'] = array(
    '#type' => 'select',
    '#title' => t('Orientation'),
    '#description' => t('Set the orientation of the table'),
    '#options' => array(
      'columns' => t('Columns'),
      'rows' => t('Rows'),
    ),
    '#default_value' => $settings['orientation'],
  );
  $element['header_column'] = array(
    '#type' => 'select',
    '#title' => t('Header field'),
    '#description' => t('The selected field value will be used as the horizontal table header'),
    '#options' => $field_options,
    '#states' => array(
      'visible' => array(
        ':input[name="fields[field_fc][settings_edit_form][settings][orientation]"]' => array(
          'value' => 'rows',
        ),
      ),
    ),
  );
  return $element;
}

/**
 * Implements hook_field_formatter_settings_summary().
 */
function field_collection_table_field_formatter_settings_summary($field, $instance, $view_mode) {
  $display = $instance['display'][$view_mode];
  $settings = $display['settings'];
  $output = field_collection_field_formatter_settings_summary($field, $instance, $view_mode);
  if ($display['type'] === 'field_collection_table_view') {
    $output .= '<br>';
    $output .= !empty($settings['hide_empty']) ? t('Empty collections: Hidden') : t('Empty collections: Shown');
    $output .= '<br>';
    $output .= !empty($settings['empty']) ? t('Empty columns: Hidden') : t('Empty columns: Shown');
    $output .= !empty($settings['caption']) ? '<br>' . t('Caption: %caption', array(
      '%caption' => t($settings['caption']),
    )) : '';
    $orientations = array(
      'columns' => t('Column'),
      'rows' => t('Row'),
    );
    $output .= '<br />';
    $output .= !empty($settings['empty']) ? t('Empty columns: Hidden') : t('Empty columns: Shown');
    if (isset($settings['orientation'])) {
      $output .= '<br />';
      $output .= t('Format fields as <strong>!orientation</strong>.', array(
        '!orientation' => $orientations[$settings['orientation']],
      ));
    }
    if (isset($settings['orientation']) && $settings['orientation'] === 'rows') {
      $output .= '<br />';
      if (isset($settings['header_column']) && $settings['header_column'] !== 'none') {
        $output .= '<br />';
        $output .= t('Field @field value is used as the header', array(
          '@field' => $settings['header_column'],
        ));
      }
    }
  }
  return $output;
}

/**
 * Implements hook_theme().
 */
function field_collection_table_theme($existing, $type, $theme, $path) {
  $base = array(
    'file' => 'theme.inc',
    'path' => $path . '/theme',
  );
  return array(
    'field_collection_table_multiple_value_field' => $base + array(
      'render element' => 'element',
    ),
    'field_collection_table_multiple_value_fields' => $base + array(
      'render element' => 'element',
    ),
    'table__field_collection_table' => $base + array(
      'variables' => array(
        'header' => NULL,
        'rows' => NULL,
        'attributes' => array(),
        'caption' => NULL,
        'colgroups' => array(),
        'sticky' => TRUE,
        'empty' => '',
        'settings' => array(),
      ),
    ),
  );
}

/**
 * Implements hook_field_attach_form().
 */
function field_collection_table_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {
  list(, , $bundle) = entity_extract_ids($entity_type, $entity);

  // Host entity edit.
  foreach (field_info_instances($entity_type, $bundle) as $field_name => $instance) {
    if (isset($form[$field_name]) && $instance['widget']['type'] === 'field_collection_table') {
      $language = $form[$field_name]['#language'];
      $form[$field_name][$language]['#theme'] = 'field_collection_table_multiple_value_fields';
      $form[$field_name][$language]['#custom_settings'] = $instance['widget']['settings'];
      $form[$field_name][$language]['#pre_render'][] = 'field_collection_table_pre_render_multiple_fields';
    }
    $field = field_info_field($field_name);
    if ($field['type'] === 'field_collection' && isset($form[$field_name]) && $field['cardinality'] == FIELD_CARDINALITY_UNLIMITED && empty($form_state['programmed']) && $instance['widget']['type'] === 'field_collection_table' && field_access('edit', $field, $entity_type)) {
      $element_langcode = $form[$field_name]['#language'];
      $element_wrapper = $form[$field_name][$element_langcode]['add_more']['#ajax']['wrapper'];
      for ($i = 0; $i <= $form[$field_name][$element_langcode]['#max_delta']; $i++) {
        if (isset($form[$field_name][$element_langcode][$i]['remove_button'])) {
          $form[$field_name][$element_langcode][$i]['remove_button']['#ajax']['wrapper'] = $element_wrapper;
        }
      }
    }
  }

  // Individual field collection item edit.
  if ($entity_type === 'field_collection_item') {
    $instance = $entity
      ->instanceInfo();
    if ($instance['widget']['type'] === 'field_collection_table') {
      $form['#theme'] = 'field_collection_table_multiple_value_field';
      $form['#pre_render'][] = 'field_collection_table_pre_render_field';
    }
  }
}

/**
 * Callback for #pre_render for a single row, hide the titles for each field.
 */
function field_collection_table_pre_render_field($element) {
  if (isset($element['#entity_type'], $element['#bundle'])) {
    foreach (field_info_instances($element['#entity_type'], $element['#bundle']) as $field_name => $instance) {
      if (empty($element[$field_name])) {
        continue;
      }
      $field =& $element[$field_name];
      $language = $field['#language'];
      if (isset($field[$language])) {

        // Set the most common places for a title to display invisible.
        $field['#title_display'] = 'invisible';
        $field[$language]['#title_display'] = 'invisible';
        $children = element_children($field[$language]);
        if ($children) {
          foreach ($children as $child) {
            if (array_key_exists('#type', $field[$language][$child]) && !in_array($field[$language][$child]['#type'], [
              'radio',
              'checkbox',
            ])) {
              $field[$language][$child]['#title_display'] = 'invisible';
            }
            $field[$language][$child]['value']['#title_display'] = 'invisible';
          }
        }
      }
      else {
        $field['#label_display'] = 'hidden';
      }
    }
  }
  return $element;
}

/**
 * Callback for #pre_render for multiple rows, hide the titles for each field.
 */
function field_collection_table_pre_render_multiple_fields($element) {
  foreach (element_children($element) as $key) {

    // Skip the 'add_more' element.
    if (is_numeric($key)) {
      $element[$key] = field_collection_table_pre_render_field($element[$key]);
    }
  }
  return $element;
}

/**
 * Implements hook_field_widget_info().
 */
function field_collection_table_field_widget_info() {
  return array(
    'field_collection_table' => array(
      'label' => t('Table'),
      'field types' => array(
        'field_collection',
      ),
      'settings' => array(
        'nodragging' => FALSE,
        'hide_title' => FALSE,
      ),
      'behaviors' => array(
        'multiple values' => FIELD_BEHAVIOR_DEFAULT,
        'default value' => FIELD_BEHAVIOR_NONE,
      ),
    ),
  );
}

/**
 * Implements hook_field_widget_form().
 */
function field_collection_table_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {

  // Changing this variable so we build the form from field_collection_embed.
  $instance['widget']['type'] = 'field_collection_embed';
  $element = field_collection_field_widget_form($form, $form_state, $field, $instance, $langcode, $items, $delta, $element);
  return $element;
}

/**
 * Implements hook_field_widget_settings_form().
 */
function field_collection_table_field_widget_settings_form($field, $instance) {
  $widget = $instance['widget'];
  $settings = $widget['settings'];
  $form['nodragging'] = array(
    '#type' => 'checkbox',
    '#title' => t('Disable drag and drop'),
    '#description' => t('If checked, users cannot rearrange the rows.'),
    '#default_value' => $settings['nodragging'],
    '#weight' => 2,
  );
  $form['hide_title'] = array(
    '#type' => 'checkbox',
    '#title' => t('Hide title'),
    '#description' => t('If checked, the field title will be hidden.'),
    '#default_value' => $settings['hide_title'],
    '#weight' => 3,
  );
  return $form;
}