You are here

relation_endpoint.module in Relation 7

Relation endpoints field.

File

relation_endpoint.module
View source
<?php

/**
 * @file
 * Relation endpoints field.
 */

/**
 * Implements hook_field_info().
 */
function relation_endpoint_field_info() {
  return array(
    'relation_endpoint' => array(
      'label' => t('Relation endpoint'),
      'description' => t('This field contains the endpoints of the relation'),
      'default_widget' => 'relation_endpoint',
      'default_formatter' => 'relation_endpoint',
      'entity types' => array(
        'relation',
      ),
      'no_ui' => TRUE,
    ),
  );
}

/**
 * Implements hook_field_validate().
 */
function relation_endpoint_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
  if (empty($entity_type) && empty($entity)) {
    return;
  }
  $relation_type = relation_type_load($entity->relation_type);

  // Check that relation_type exists.
  if (!$relation_type) {
    $errors[$field['field_name']][$langcode][$delta][] = array(
      'error' => 'relation_nonexistent_type',
      'message' => t("The !relation_type relation type does not exist.", array(
        '!relation_type' => $entity->relation_type,
      )),
    );
  }

  // Check if the relation type is unique and if so, check if a relation between
  // those items exist already.
  if ($relation_type->r_unique) {
    $rids = relation_relation_exists($items, $entity->relation_type);
    if ($rids && (!isset($entity->rid) || !isset($rids[$entity->rid]))) {
      $errors[$field['field_name']][$langcode][0][] = array(
        'error' => 'relation_already_exists',
        'message' => t("The !relation_type is unique but the relation already exists.", array(
          '!relation_type' => $entity->relation_type,
        )),
      );
    }
  }

  // Check that arity is within acceptable bounds.
  if (count($items) < $relation_type->min_arity && empty($entity->in_progress)) {
    $errors[$field['field_name']][$langcode][0][] = array(
      'error' => 'relation_too_few_endpoints',
      'message' => t("Relation has too few end points (:relation_type min arity :min_arity)", array(
        ':relation_type' => $entity->relation_type,
        ':min_arity' => $relation_type->min_arity,
      )),
    );
  }
  if ($relation_type->max_arity && count($items) > $relation_type->max_arity) {
    $errors[$field['field_name']][$langcode][0][] = array(
      'error' => 'relation_too_many_endpoints',
      'message' => t("Relation has too many end points (:relation_type max arity :max_arity)", array(
        ':relation_type' => $entity->relation_type,
        ':max_arity' => $relation_type->max_arity,
      )),
    );
  }

  // Load all entities referenced in $items via multiple load.
  $items_to_load = array();
  $loaded_items = array();
  foreach ($items as $delta => $item) {
    if (!isset($item['entity_bundle'])) {
      $items_to_load[$item['entity_type']][] = $item['entity_id'];
    }
  }
  foreach ($items_to_load as $entity_type => $ids) {
    $loaded_items[$entity_type] = entity_load($entity_type, $ids);
  }

  // Check that each entity is has acceptable bundle type and index.
  foreach ($items as $delta => $item) {
    $acceptable = FALSE;
    $directional = $relation_type->directional;
    $endpoint = $directional && $delta > 0 ? 'target' : 'source';
    $end_bundles = $endpoint . '_bundles';
    foreach ($relation_type->{$end_bundles} as $relation_bundle) {
      if (!isset($item['entity_bundle'])) {
        $endpoint_entity = $loaded_items[$item['entity_type']][$item['entity_id']];
        list(, , $item['entity_bundle']) = entity_extract_ids($item['entity_type'], $endpoint_entity);
      }
      $relation_bundle_array = explode(':', $relation_bundle, 2);
      if ($relation_bundle == $item['entity_type'] . ':' . $item['entity_bundle'] || $item['entity_type'] == $relation_bundle_array[0] && $relation_bundle_array[1] == '*') {
        $acceptable = TRUE;
        break;
      }
    }
    if (!$acceptable) {
      $t_arguments = array(
        '%relation_type' => $entity->relation_type,
        '@bundle' => $item['entity_bundle'],
      );
      if ($relation_type->directional) {
        if ($endpoint == 'target') {
          $errors[$field['field_name']][$langcode][$delta][] = array(
            'error' => 'relation_unsupported_target',
            'message' => t("The %relation_type relation type does not allow @bundle entities as target.", $t_arguments),
          );
        }
        else {
          $errors[$field['field_name']][$langcode][$delta][] = array(
            'error' => 'relation_unsupported_source',
            'message' => t("The %relation_type relation type does not allow @bundle entities as source.", $t_arguments),
          );
        }
      }
      else {
        $errors[$field['field_name']][$langcode][$delta][] = array(
          'error' => 'relation_unsupported_endpoint',
          'message' => t("The %relation_type relation type does not allow @bundle entities as an endpoint.", $t_arguments),
        );
      }
    }
  }
}

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

  // We need r_index here because EntityFieldQuery can't query on deltas.
  foreach ($items as $delta => &$item) {
    $item['r_index'] = $delta;
  }
}

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

  // We do not update.
}

/**
 * Implements hook_field_is_empty().
 */
function relation_endpoint_field_is_empty($item, $field) {

  // We are never empty.
  return FALSE;
}

/**
 * Helper to create an HTML table representing a relation.
 */
function _relation_endpoint_field_create_html_table($endpoints) {
  $entity_info = entity_get_info();
  $list_items = array();
  foreach ($endpoints as $delta => $endpoint) {
    $entities = entity_load($endpoint['entity_type'], array(
      $endpoint['entity_id'],
    ));
    $entity = reset($entities);
    $label = entity_label($endpoint['entity_type'], $entity);
    $uri = entity_uri($endpoint['entity_type'], $entity);
    if ($uri) {
      $list_items[$delta] = array(
        l($label, $uri['path'], $uri['options']),
        $entity_info[$endpoint['entity_type']]['label'],
      );
    }
    else {
      $list_items[$delta] = array(
        $label,
        $entity_info[$endpoint['entity_type']]['label'],
      );
    }
  }
  $headers = array(
    t('Entity'),
    array(
      'width' => '22%',
      'data' => t('Entity type'),
    ),
  );
  return array(
    '#theme' => 'table',
    '#header' => $headers,
    '#rows' => $list_items,
  );
}

/**
 * Implements hook_field_widget_info().
 */
function relation_endpoint_field_widget_info() {
  return array(
    'relation_endpoint' => array(
      'label' => t('Endpoints table'),
      'field types' => array(
        'relation_endpoint',
      ),
      'behaviors' => array(
        'multiple values' => FIELD_BEHAVIOR_CUSTOM,
      ),
    ),
  );
}

/**
 * Implements hook_field_formatter_info().
 */
function relation_endpoint_field_formatter_info() {
  $info = array(
    'relation_endpoint' => array(
      'label' => t('Endpoints table'),
      'field types' => array(
        'relation_endpoint',
      ),
    ),
    'relation_endpoint_full' => array(
      'label' => t('Full entities list'),
      'field types' => array(
        'relation_endpoint',
      ),
    ),
  );
  foreach (entity_get_info() as $entity_type => $data) {
    $info['relation_endpoint_full']['settings']['view_modes'][$entity_type] = 'default';
    $info['relation_endpoint']['settings']['view_modes'][$entity_type] = 'default';
  }
  return $info;
}

/**
 * Implements hook_field_formatter_settings_form().
 */
function relation_endpoint_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
  $view_modes_settings = $instance['display'][$view_mode]['settings']['view_modes'];
  foreach (_relation_endpoint_get_endpoint_entity_types($instance) as $endpoint_entity_type => $v) {
    $entity_info = entity_get_info($endpoint_entity_type);
    $options = array();
    foreach ($entity_info['view modes'] as $entity_view_mode => $data) {
      $options[$entity_view_mode] = $data['label'];
    }
    $element['#tree'] = TRUE;
    $element['view_modes'][$endpoint_entity_type] = array(
      '#title' => t('@endpoint_entity_type view mode', array(
        '@endpoint_entity_type' => $endpoint_entity_type,
      )),
      '#type' => 'select',
      '#default_value' => $view_modes_settings[$endpoint_entity_type],
      '#options' => $options,
    );
  }
  return $element;
}

/**
 * Implements hook_field_formatter_settings_summary().
 */
function relation_endpoint_field_formatter_settings_summary($field, $instance, $view_mode) {
  $view_modes_settings = $instance['display'][$view_mode]['settings']['view_modes'];
  foreach (_relation_endpoint_get_endpoint_entity_types($instance) as $endpoint_entity_type => $v) {
    $items[] = "{$endpoint_entity_type}: " . $view_modes_settings[$endpoint_entity_type];
  }
  return theme('item_list', array(
    'items' => $items,
  ));
}

/**
 * Helper getting endpoint entity types for the bundle specified in $instance.
 */
function _relation_endpoint_get_endpoint_entity_types($instance) {
  $relation_type = relation_type_load($instance['bundle']);
  $bundles = $relation_type->source_bundles + $relation_type->target_bundles;
  foreach ($bundles as $bundle_key) {
    list($endpoint_entity_type) = explode(':', $bundle_key);
    $endpoint_entity_types[$endpoint_entity_type] = TRUE;
  }
  return $endpoint_entity_types;
}

/**
 * Implements hook_field_formatter_view().
 */
function relation_endpoint_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  switch ($display['type']) {
    case 'relation_endpoint':
      $build[] = _relation_endpoint_field_create_html_table($items);
      break;
    case 'relation_endpoint_full':
      $list_items = array();
      $endpoint_entity_type = '';
      $multiple = TRUE;
      foreach ($items as $delta => $endpoint) {
        if (!$endpoint_entity_type) {
          $endpoint_entity_type = $endpoint['entity_type'];
        }
        if ($endpoint_entity_type == $endpoint['entity_type']) {
          $entity_ids[] = $endpoint['entity_id'];
        }
        else {
          $multiple = FALSE;
          break;
        }
      }
      $view_mode = isset($display['settings']['view_modes'][$endpoint_entity_type]) ? $display['settings']['view_modes'][$endpoint_entity_type] : 'full';
      if ($multiple) {
        $entities = entity_load($endpoint_entity_type, $entity_ids);
        if (function_exists('entity_view')) {
          return array(
            entity_view($endpoint_entity_type, $entities, $view_mode),
          );
        }
        $function = $endpoint_entity_type . '_view_multiple';
        if (function_exists($function)) {
          return array(
            $function($entities, $view_mode),
          );
        }
      }
      $build = array();
      foreach ($items as $delta => $endpoint) {
        if ($multiple) {
          $entity = $entities[$endpoint['entity_id']];
        }
        else {
          $entities = entity_load($endpoint['entity_type'], array(
            $endpoint['entity_id'],
          ));
          $entity = reset($entities);
        }
        if (function_exists('entity_view')) {
          $build[$delta] = entity_view($endpoint['entity_type'], array(
            $entity,
          ), $view_mode);
        }
        else {
          $function = $endpoint['entity_type'] . '_view';
          $build[$delta] = $function($entity, $view_mode);
        }
      }
  }
  return $build;
}

/**
 * Implements hook_field_widget_form().
 */
function relation_endpoint_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
  foreach ($items as $delta => $item) {
    foreach (array(
      'entity_type',
      'entity_id',
    ) as $column) {
      $element[$delta][$column] = array(
        '#type' => 'value',
        '#value' => $item[$column],
      );
    }
  }
  $element['link_list'] = _relation_endpoint_field_create_html_table($items);
  return $element;
}

/**
 * Implements hook_form_field_ui_field_overview_form_alter().
 */
function relation_endpoint_form_field_ui_field_overview_form_alter(&$form, $form_state) {

  // Deleting endpoints would make the module useless.
  if ($form['#entity_type'] == 'relation') {
    $form['fields']['endpoints']['delete'] = array(
      '#type' => 'markup',
      '#markup' => '&nbsp;',
    );
  }
}