entity_reference.module 9.7 KB
Newer Older
1 2 3 4 5 6 7 8 9
<?php

/**
 * @file
 * Provides a field that can reference other entities.
 */

use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Database\Query\AlterableInterface;
10
use Drupal\Core\Form\FormStateInterface;
11
use Drupal\Core\Render\Element;
12
use Drupal\Core\Routing\RouteMatchInterface;
13
use Drupal\field\Entity\FieldStorageConfig;
14
use Drupal\field\Entity\FieldConfig;
15
use Drupal\field\FieldStorageConfigInterface;
16
use Drupal\field\FieldConfigInterface;
17

18 19 20
/**
 * Implements hook_help().
 */
21
function entity_reference_help($route_name, RouteMatchInterface $route_match) {
22 23
  switch ($route_name) {
    case 'help.page.entity_reference':
24 25
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
26
      $output .= '<p>' . t('The Entity Reference module allows you to create fields that contain links to other entities (such as content items, taxonomy terms, etc.) within the site. This allows you, for example, to include a link to a user within a content item. For more information, see <a href="!er_do">the online documentation for the Entity Reference module</a> and the <a href="!field_help">Field module help page</a>.', array('!field_help' => \Drupal::url('help.page', array('name' => 'field')), '!er_do' => 'https://www.drupal.org/documentation/modules/entityreference')) . '</p>';
27 28 29
      $output .= '<h3>' . t('Uses') . '</h3>';
      $output .= '<dl>';
      $output .= '<dt>' . t('Managing and displaying entity reference fields') . '</dt>';
30
      $output .= '<dd>' . t('The <em>settings</em> and the <em>display</em> of the entity reference field can be configured separately. See the <a href="!field_ui">Field UI help</a> for more information on how to manage fields and their display.', array('!field_ui' => (\Drupal::moduleHandler()->moduleExists('field_ui')) ? \Drupal::url('help.page', array('name' => 'field_ui')) : '#')) . '</dd>';
31
      $output .= '<dt>' . t('Selecting reference type') . '</dt>';
32
      $output .= '<dd>' . t('In the field settings you can select which type of item you want to create a reference to.') . '</dd>';
33 34 35
      $output .= '<dt>' . t('Filtering and sorting reference fields') . '</dt>';
      $output .= '<dd>' . t('Depending on the chosen entity type, additional filtering and sorting options are available for the list of entities that can be referred to, in the field settings. For example, the list of users can be filtered by role and sorted by name or ID.') . '</dd>';
      $output .= '<dt>' . t('Displaying a reference') . '</dt>';
36 37 38 39 40 41 42 43 44
      $output .= '<dd>' . t('An entity reference can be displayed as a simple label with or without a link to the entity. Alternatively, the referenced entity can be displayed as a teaser (or any other available view mode) inside the referencing entity. Certain entity types may provide additional display options. You can configure how the entity reference is displayed on the <em>Manage display</em> page for the entity.') . '</dd>';
      $output .= '<dt>' . t('Configuring form displays') . '</dt>';
      $output .= '<dd>' . t('Reference fields have several widgets available on the <em>Manage form display</em> page:');
      $output .= '<ul>';
      $output .= '<li>' . t('The <em>Check boxes/radio buttons</em> widget displays the existing entities for the entity type as check boxes or radio buttons based on the <em>Allowed number of values</em> set for the field.') . '</li>';
      $output .= '<li>' . t('The <em>Select list</em> widget displays the existing entities in a drop-down list or scrolling list box based on the <em>Allowed number of values</em> setting for the field.') . '</li>';
      $output .= '<li>' . t('The <em>Autocomplete</em> widget displays text fields in which users can type entity labels based on the <em>Allowed number of values</em>. The widget can be configured to display all entities that contain the typed characters or restricted to those starting with those characters.') . '</li>';
      $output .= '<li>' . t('The <em>Autocomplete (Tags style)</em> widget displays a multi-text field in which users can type in a comma-separated list of entity labels.') . '</li>';
      $output .= '</ul>';
45 46 47 48 49
      $output .= '</dl>';
      return $output;
  }
}

50
/**
51
 * Implements hook_field_info_alter().
52
 */
53
function entity_reference_field_info_alter(&$info) {
54
  // Make the entity reference field configurable.
55
  $info['entity_reference']['no_ui'] = FALSE;
56
  $info['entity_reference']['class'] = '\Drupal\entity_reference\ConfigurableEntityReferenceItem';
57
  $info['entity_reference']['list_class'] = '\Drupal\Core\Field\EntityReferenceFieldItemList';
58 59
  $info['entity_reference']['default_widget'] = 'entity_reference_autocomplete';
  $info['entity_reference']['default_formatter'] = 'entity_reference_label';
60
  $info['entity_reference']['provider'] = 'entity_reference';
61 62
}

63 64 65 66 67 68 69 70 71 72 73 74
/**
 * Implements hook_field_widget_info_alter().
 */
function entity_reference_field_widget_info_alter(&$info) {
  if (isset($info['options_select'])) {
    $info['options_select']['field_types'][] = 'entity_reference';
  }
  if (isset($info['options_buttons'])) {
    $info['options_buttons']['field_types'][] = 'entity_reference';
  }
}

75
/**
76
 * Implements hook_ENTITY_TYPE_update() for 'field_storage_config'.
77 78 79
 *
 * Reset the instance handler settings, when the target type is changed.
 */
80
function entity_reference_field_storage_config_update(FieldStorageConfigInterface $field_storage) {
81
  if ($field_storage->getType() != 'entity_reference') {
82
    // Only act on entity reference fields.
83 84 85
    return;
  }

86
  if ($field_storage->isSyncing()) {
87 88 89 90
    // Don't change anything during a configuration sync.
    return;
  }

91
  if ($field_storage->getSetting('target_type') == $field_storage->original->getSetting('target_type')) {
92 93 94 95
    // Target type didn't change.
    return;
  }

96 97
  foreach ($field_storage->getBundles() as $bundle) {
    $field = FieldConfig::loadByName($field_storage->getTargetEntityTypeId(), $bundle, $field_storage->getName());
98
    $field->setSetting('handler_settings', []);
99
    $field->save();
100
  }
101
}
102

103 104 105 106 107 108 109 110 111 112
/**
 * Implements hook_ENTITY_TYPE_presave() for 'field_config'.
 *
 * Determine the selection handler plugin ID for an entity reference field.
 */
function entity_reference_field_config_presave(FieldConfigInterface $field) {
  if ($field->getType() != 'entity_reference') {
    // Only act on entity reference fields.
    return;
  }
113

114 115 116
  if ($field->isSyncing()) {
    // Don't change anything during a configuration sync.
    return;
117
  }
118 119 120 121

  $target_type = $field->getFieldStorageDefinition()->getSetting('target_type');
  $selection_manager = \Drupal::service('plugin.manager.entity_reference_selection');
  list($current_handler) = explode(':', $field->getSetting('handler'), 2);
122
  $field->setSetting('handler', $selection_manager->getPluginId($target_type, $current_handler));
123 124
}

125 126 127 128
/**
 * Implements hook_form_FORM_ID_alter() for 'field_ui_field_storage_add_form'.
 */
function entity_reference_form_field_ui_field_storage_add_form_alter(array &$form) {
129 130 131
  // We cast the optgroup label to string as array keys must not be objects
  // and t() may return a TranslationWrapper once issue #2557113 lands.
  $optgroup = (string) t('Reference');
132 133
  // Move the "Entity reference" option to the end of the list and rename it to
  // "Other".
134 135
  unset($form['add']['new_storage_type']['#options'][$optgroup]['entity_reference']);
  $form['add']['new_storage_type']['#options'][$optgroup]['entity_reference'] = t('Other…');
136 137
}

138
/**
139 140
 * Render API callback: Processes the field settings form and allows access to
 * the form state.
141
 *
142
 * @see entity_reference_field_field_settings_form()
143
 */
144 145
function _entity_reference_field_field_settings_ajax_process($form, FormStateInterface $form_state) {
  _entity_reference_field_field_settings_ajax_process_element($form, $form);
146 147 148 149 150
  return $form;
}

/**
 * Adds entity_reference specific properties to AJAX form elements from the
151
 * field settings form.
152
 *
153
 * @see _entity_reference_field_field_settings_ajax_process()
154
 */
155
function _entity_reference_field_field_settings_ajax_process_element(&$element, $main_form) {
156 157 158 159 160 161 162 163
  if (!empty($element['#ajax'])) {
    $element['#ajax'] = array(
      'callback' => 'entity_reference_settings_ajax',
      'wrapper' => $main_form['#id'],
      'element' => $main_form['#array_parents'],
    );
  }

164
  foreach (Element::children($element) as $key) {
165
    _entity_reference_field_field_settings_ajax_process_element($element[$key], $main_form);
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
  }
}

/**
 * Render API callback: Moves entity_reference specific Form API elements
 * (i.e. 'handler_settings') up a level for easier processing by the validation
 * and submission handlers.
 *
 * @see _entity_reference_field_settings_process()
 */
function _entity_reference_form_process_merge_parent($element) {
  $parents = $element['#parents'];
  array_pop($parents);
  $element['#parents'] = $parents;
  return $element;
}

/**
 * Form element validation handler; Filters the #value property of an element.
 */
186
function _entity_reference_element_validate_filter(&$element, FormStateInterface $form_state) {
187
  $element['#value'] = array_filter($element['#value']);
188
  $form_state->setValueForElement($element, $element['#value']);
189 190 191 192 193
}

/**
 * Ajax callback for the handler settings form.
 *
194
 * @see entity_reference_field_field_settings_form()
195
 */
196
function entity_reference_settings_ajax($form, FormStateInterface $form_state) {
197
  return NestedArray::getValue($form, $form_state->getTriggeringElement()['#ajax']['element']);
198 199 200 201 202
}

/**
 * Submit handler for the non-JS case.
 *
203
 * @see entity_reference_field_field_settings_form()
204
 */
205
function entity_reference_settings_ajax_submit($form, FormStateInterface $form_state) {
206
  $form_state->setRebuild();
207 208 209 210 211 212 213 214 215
}

/**
 * Implements hook_query_TAG_alter().
 */
function entity_reference_query_entity_reference_alter(AlterableInterface $query) {
  $handler = $query->getMetadata('entity_reference_selection_handler');
  $handler->entityQueryAlter($query);
}