You are here

relation_add_block.module in Relation add 7

Relation Add Block module file.

File

modules/relation_add_block/relation_add_block.module
View source
<?php

/**
 * @file
 * Relation Add Block module file.
 */

/**
 * Implements hook_block_info().
 */
function relation_add_block_block_info() {
  $blocks['relation_add_block'] = array(
    // The name that will appear in the block list.
    'info' => t('Relation Add'),
  );
  return $blocks;
}

/**
 * Implements hook_block_view().
 */
function relation_add_block_block_view() {
  if (!(user_access('create relations') || user_access('create relations'))) {
    return NULL;
  }
  $block['subject'] = t('Relation Add');
  $block['content'] = drupal_get_form('relation_add_block_block_form');
  return $block;
}

/**
 * The relation add block form.
 */
function relation_add_block_block_form($form, &$form_state) {
  $form['#attached']['css'] = array(
    drupal_get_path('module', 'relation_add') . '/relation_add.css',
  );

  // This stuff is only relevant if we're NOT in an AJAX call.
  if (!isset($form_state['triggering_element']['#ajax'])) {

    // Get the entity for the current page. This fails for taxonomy entities.
    // Need a better way. Also, this will never really work for comments, or
    // files, or other entities that don't have their own page.
    $all_entities = array_keys(entity_get_info());
    $path = menu_get_item();
    if (count($path['map']) >= 2 && in_array($path['map'][0], $all_entities) && is_object($path['map'][1])) {
      $entity_type = $path['map'][0];
      $entity = $path['map'][1];
    }
    elseif (count($path['map']) >= 3 && $path['map'][0] == 'taxonomy' && is_object($path['map'][2])) {
      $entity_type = 'taxonomy_term';
      $entity = $path['map'][2];
    }
    elseif ($path['original_map'][0] == 'colorbox') {
      $entity_info = explode('/', $path['map'][1]);
      $entities = entity_load($entity_info[0], array(
        $entity_info[1],
      ));
      $entity = $entities[$entity_info[1]];
      $entity_type = $entity_info[0];
    }
    else {
      $entity_info = module_invoke_all('relation_add_load_entity');
      if (is_array($entity_info) && count($entity_info) > 1) {
        list($entity_type, $entity) = $entity_info;
      }
    }
    if (!isset($entity)) {
      $form['explanation']['#markup'] = t("No entity found, can't create a relation!");
      return $form;
    }
    else {

      // If we have an $entity, then we have an $entity_type.
      $entity_label = entity_label($entity_type, $entity);
      list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
      $label = $entity_label . ' [' . $entity_type . ':' . $id . ']';
      $relation_types = relation_get_available_types($entity_type, $bundle);
      $reverse_types = relation_get_available_types($entity_type, $bundle, 'target');
      $form_state['relation_add'] = $label;
    }
    if (empty($relation_types) && empty($reverse_types)) {

      // Act as helper block if no relation types are defined.
      $form['explanation']['#markup'] = t("Before you can create relations from entities of this bundle type (!bundle), you need to create one or more !link that include the bundle in the allowed bundles list.\n        Once you've done that, visit any page displays an entity, and use this block to add a new relation from that entity.", array(
        '!bundle' => $entity_type . ':' . $bundle,
        '!link' => l(t('relation types'), 'admin/structure/relation'),
      ));
      return $form;
    }
    $form['current_entity'] = array(
      '#type' => 'textfield',
      '#title' => t('Create a relation from'),
      '#value' => $label,
      '#disabled' => TRUE,
    );

    // Relation type selector. On change, rest of form is loaded via ajax.
    $types = array();
    foreach ($relation_types as $relation_type) {
      $types[$relation_type->relation_type] = $relation_type->label;
    }
    foreach ($reverse_types as $relation_type) {
      if ($relation_type->directional && $relation_type->max_arity == 2) {

        // Directional n-ary relations are f@*#ing stupid.
        // Machine name doesn't have colons, so we add a suffix for reverse
        // relations, which we explode off later.
        $types[$relation_type->relation_type . ':reverse'] = $relation_type->reverse_label ? $relation_type->reverse_label : 'reverse ' . $relation_type->reverse_label;
      }
    }
    ksort($types);
    $form_state['types'] = $types;

    // End non-AJAX part.
  }
  if (count($form_state['types']) > 1) {
    $form['relation_type'] = array(
      '#type' => 'select',
      '#title' => t('Relation type'),
      '#options' => $form_state['types'],
      '#empty_value' => '',
      '#empty_option' => t('Select a relation type'),
      '#ajax' => array(
        'callback' => 'relation_add_block_block_ajax',
        'wrapper' => 'block-relation-add-options',
        'method' => 'replace',
        'effect' => 'fade',
      ),
    );
  }
  else {
    $form['relation_type'] = array(
      '#type' => 'value',
      // Key of the first option.
      '#value' => key($form_state['types']),
    );
    $form['relation_type_item'] = array(
      '#type' => 'item',
      '#title' => t('Relation type'),
      '#markup' => current($form_state['types']),
    );

    // Pretend we've already returned from the AJAX callback.
    $form_state['values']['relation_type'] = $form['relation_type']['#value'];
  }
  $type = '';
  if (!empty($form_state['values']['relation_type'])) {

    // Remove ':reverse' suffix if it exists, and set reverse flag.
    $type_array = explode(':', $form_state['values']['relation_type']);
    $type = $type_array[0];
    $form_state['relation_reverse'] = isset($type_array[1]) && $type_array[1] == 'reverse';
  }
  $form['relation_options'] = array(
    '#prefix' => '<div id="block-relation-add-options">',
    '#suffix' => '</div>',
  );

  // AJAXification.
  if (!empty($form_state['values']['relation_type'])) {
    $relation_type = relation_type_load($type);
    $relation = (object) relation_create($type, array());

    // Create one autocomplete for each endpoint beyond the first.
    $direction = $form_state['relation_reverse'] ? '/source' : '/target';
    for ($i = 2; $i <= $relation_type->max_arity; $i++) {
      $form['relation_options']['targets']['target_' . $i] = array(
        '#type' => 'textfield',
        '#title' => t('Endpoint @num', array(
          '@num' => $i,
        )),
        '#autocomplete_path' => 'relation_add/autocomplete/' . $type . $direction . '/none' . '/all',
      );
    }
    field_attach_form('relation', $relation, $form['relation_options'], $form_state);
    unset($form['relation_options']['endpoints']);
    $form['relation_options']['save'] = array(
      '#type' => 'submit',
      '#weight' => 100,
      '#value' => t('Create relation'),
      '#submit' => array(
        'relation_add_save',
      ),
    );
  }
  else {
    $form['relation_options']['explanation'] = array(
      '#prefix' => '<div id=\'relation-add-explanation\'>',
      '#markup' => t('This block allows you to create a relation from the current entity (the one displayed on this page), to another one. Please select a relation type.'),
      '#suffix' => '</div>',
    );
  }
  return $form;
}

/**
 * AJAX callback for block form.
 */
function relation_add_block_block_ajax($form, $form_state) {
  return $form['relation_options'];
}

/**
 * Validate form submission for the relation add block form.
 */

/**
 * Note to do soon.
 *
 * @code
 * @codingStandardsIgnoreStart
 * function relation_add_validate($form, &$form_state) {
 * @TODO
 * $type =
 * $entity_keys =
 * relation_create($type, $entity_keys);
 * field_attach_form_validate('relation', $relation, $form['relation_options'], $form_state);
 * @codingStandardsIgnoreEnd
 * @endcode
 */

/**
 * Submit handler for the save button.
 */
function relation_add_save($form, &$form_state) {
  $type_array = explode(':', $form_state['values']['relation_type']);
  $type = $type_array[0];

  // Entity_form_submit_build_entity() uses this later,
  // so set it to the correct value.
  $form_state['values']['relation_type'] = $type;

  // Gather all the endpoint entities into one array.
  $entity_strings = array();
  for ($i = 2; $i; $i++) {
    if (isset($form_state['values']['target_' . $i])) {
      $entity_strings[] = $form_state['values']['target_' . $i];
    }
    else {

      // Break loop.
      $i = FALSE;
    }
  }

  // Add the current entity to the endpoints array.
  if ($form_state['relation_reverse']) {

    // For reverse relations, add the "current entity" to the end of the array,
    // else to the start.
    array_push($entity_strings, $form_state['relation_add']);
  }
  else {
    array_unshift($entity_strings, $form_state['relation_add']);
  }

  // Convert all entity_strings to proper entity_keys.
  $entity_keys = array();
  foreach ($entity_strings as $r_index => $entity_string) {
    $matches = array();
    preg_match('/(.*)\\[([\\w\\d]+):(\\d+)\\]/', $entity_string, $matches);
    if ($matches) {
      $entity_keys[] = array(
        'entity_label' => $matches[1],
        'entity_type' => $matches[2],
        'entity_id' => $matches[3],
        'r_index' => $r_index,
      );
    }
  }

  // @TODO: IF count(entity_keys) != count (entity_strings), FAIL.
  $relation = relation_create($type, $entity_keys);
  entity_form_submit_build_entity('relation', $relation, $form['relation_options'], $form_state);
  $rid = relation_save($relation);
  if ($rid) {
    $link = l($type, "relation/{$rid}");

    // See also _relation_stored_entity_keys_list()
    // in relation_entity_collector.module.
    $list = array(
      '#theme' => 'item_list',
      '#items' => array(),
    );
    foreach ($entity_keys as $entity_key) {
      $list['#items'][] = $entity_key['entity_label'];
    }
    $rendered_list = drupal_render($list);
    $message = t('Created new !link from !list', array(
      '!link' => $link,
      '!list' => $rendered_list,
    ));
    drupal_set_message($message);
  }
  else {
    drupal_set_message(t('Relation not created.'), 'error');
  }
}

Functions

Namesort descending Description
relation_add_block_block_ajax AJAX callback for block form.
relation_add_block_block_form The relation add block form.
relation_add_block_block_info Implements hook_block_info().
relation_add_block_block_view Implements hook_block_view().
relation_add_save Submit handler for the save button.