You are here

noderefcreate.module in Node Reference Create 7

Same filename and directory in other branches
  1. 6 noderefcreate.module

Defines a widget type for referencing one node from another and creating a new one if the provided doesn't exists.

File

noderefcreate.module
View source
<?php

/**
 * @file
 * Defines a widget type for referencing one node from another
 * and creating a new one if the provided doesn't exists.
 */

/**
 * Implements hook_field_widget_info().
 *
 */
function noderefcreate_field_widget_info() {
  return array(
    'noderefcreate_autocomplete' => array(
      'label' => t('Autocomplete text field with create'),
      'description' => t('Display the list of referenceable nodes as a textfield with autocomplete behaviour, if the node doesn´t exist, create it.'),
      'field types' => array(
        'node_reference',
      ),
      'settings' => array(
        'autocomplete_match' => 'contains',
        'size' => 60,
        'autocomplete_path' => 'node_reference/autocomplete',
      ),
    ),
  );
}

/**
 * Implements of hook_field_widget_settings_form
 */
function noderefcreate_field_widget_settings_form($field, $instance) {
  $widget = $instance['widget'];
  $defaults = field_info_widget_settings($widget['type']);
  $settings = array_merge($defaults, $widget['settings']);
  if ($widget['type'] == 'noderefcreate_autocomplete') {
    $form['autocomplete_match'] = array(
      '#type' => 'select',
      '#title' => t('Autocomplete matching'),
      '#default_value' => $settings['autocomplete_match'],
      '#options' => array(
        'starts_with' => t('Starts with'),
        'contains' => t('Contains'),
      ),
      '#description' => t('Select the method used to collect autocomplete suggestions. Note that <em>Contains</em> can cause performance issues on sites with thousands of nodes.'),
    );
    $form['size'] = array(
      '#type' => 'textfield',
      '#title' => t('Size of textfield'),
      '#default_value' => $settings['size'],
      '#element_validate' => array(
        '_element_validate_integer_positive',
      ),
      '#required' => TRUE,
    );
  }
  return $form;
}

/**
 * Implements hook_field_widget_form().
 */
function noderefcreate_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
  switch ($instance['widget']['type']) {
    case 'noderefcreate_autocomplete':
      $element += array(
        '#type' => 'textfield',
        '#default_value' => isset($items[$delta]['nid']) ? $items[$delta]['nid'] : NULL,
        '#autocomplete_path' => $instance['widget']['settings']['autocomplete_path'] . '/' . $instance['entity_type'] . '/' . $instance['bundle'] . '/' . $field['field_name'],
        '#size' => $instance['widget']['settings']['size'],
        '#element_validate' => array(
          'noderefcreate_autocomplete_validate',
        ),
        '#value_callback' => 'node_reference_autocomplete_value',
      );
      break;
  }
  return array(
    'nid' => $element,
  );
}

/**
 * Validation callback for a noderefcreate autocomplete element.
 *
 * This is mostly a copy of node_reference validate function,
 * and we just create new node in case no node with provided title exists.
 */
function noderefcreate_autocomplete_validate($element, &$form_state, $form) {
  $field = field_widget_field($element, $form_state);
  $instance = field_widget_instance($element, $form_state);
  $value = $element['#value'];
  $nid = NULL;
  if (strlen(trim($value)) > 0) {

    // Check whether we have an explicit "[nid:n]" input.
    preg_match('/^(?:\\s*|(.*) )?\\[\\s*nid\\s*:\\s*(\\d+)\\s*\\]$/', $value, $matches);
    if (!empty($matches)) {

      // Explicit nid. Check that the 'title' part matches the actual title for
      // the nid.
      list(, $title, $nid) = $matches;
      if (!empty($title)) {
        $real_title = db_select('node', 'n')
          ->fields('n', array(
          'title',
        ))
          ->condition('n.nid', $nid)
          ->execute()
          ->fetchField();
        if (trim($title) != trim($real_title)) {
          form_error($element, t('%name: title mismatch. Please check your selection.', array(
            '%name' => $instance['label'],
          )));
        }
      }
    }
    else {

      // No explicit nid (the submitted value was not populated by autocomplete
      // selection). Get the nid of a referencable node from the entered title.
      $options = array(
        'string' => $value,
        'match' => 'equals',
        'ids' => NULL,
        'limit' => 1,
      );
      $reference = node_reference_potential_references($field, $options);
      if ($reference) {

        // @todo The best thing would be to present the user with an
        // additional form, allowing the user to choose between valid
        // candidates with the same title. ATM, we pick the first
        // matching candidate...
        $nid = key($reference);
      }
      else {
        $newnode = NULL;
        if (is_array($field['settings']['referenceable_types'])) {
          foreach (array_filter($field['settings']['referenceable_types']) as $related_type) {
            $newnode->type = $related_type;
          }
        }
        global $user;
        $newnode->uid = $user->uid;
        $newnode->title = $value;
        $newnode->language = $element['#language'];
        if (module_exists('comment')) {
          $newnode->comment = variable_get("comment_{$newnode->type}", COMMENT_NODE_OPEN);
        }
        node_save($newnode);
        $nid = $newnode->nid;
      }
    }
  }
  else {
    if (strlen($value) > 0) {

      // if we got here then the user filled the name with spaces
      form_error($element, t('%name: title is empty. Please check your input.', array(
        '%name' => $instance['label'],
      )));
    }
  }

  // Set the element's value as the node id that was extracted from the entered
  // input.
  form_set_value($element, $nid, $form_state);
}

/**
 * Implements hook_field_widget_error().
 */
function noderefcreate_field_widget_error($element, $error, $form, &$form_state) {
  form_error($element['nid'], $error['message']);
}

Functions

Namesort descending Description
noderefcreate_autocomplete_validate Validation callback for a noderefcreate autocomplete element.
noderefcreate_field_widget_error Implements hook_field_widget_error().
noderefcreate_field_widget_form Implements hook_field_widget_form().
noderefcreate_field_widget_info Implements hook_field_widget_info().
noderefcreate_field_widget_settings_form Implements of hook_field_widget_settings_form