field.default.inc 9.76 KB
Newer Older
1
<?php
2
// $Id$
3 4 5

/**
 * @file
6
 * Default 'implementations' of hook_field_*(): common field housekeeping.
7 8 9
 *
 * Those implementations are special, as field.module does not define any field
 * types. Those functions take care of default stuff common to all field types.
10 11
 * They are called through the _field_invoke_default() iterator, generally in
 * the corresponding field_attach_[operation]() function.
12 13
 */

14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
/**
 * Extracts field values from submitted form values.
 *
 * @param $entity_type
 *   The type of $entity.
 * @param $entity
 *   The entity for the operation.
 * @param $field
 *   The field structure for the operation.
 * @param $instance
 *   The instance structure for $field on $entity's bundle.
 * @param $langcode
 *   The language associated to $items.
 * @param $items
 *   The field values. This parameter is altered by reference to receive the
 *   incoming form values.
 * @param $form
 *   The form structure where field elements are attached to. This might be a
 *   full form structure, or a sub-element of a larger form.
 * @param $form_state
 *   The form state.
 */
36
function field_default_extract_form_values($entity_type, $entity, $field, $instance, $langcode, &$items, $form, &$form_state) {
37 38 39 40
  $path = array_merge($form['#parents'], array($field['field_name'], $langcode));
  $key_exists = NULL;
  $values = drupal_array_get_nested_value($form_state['values'], $path, $key_exists);
  if ($key_exists) {
41
    // Remove the 'value' of the 'add more' button.
42 43
    unset($values['add_more']);
    $items = $values;
44 45 46
  }
}

47 48 49 50 51 52 53 54
/**
 * Generic field validation handler.
 *
 * Possible error codes:
 * - 'field_cardinality': The number of values exceeds the field cardinality.
 *
 * @see _hook_field_validate()
 *
55 56 57
 * @param $entity_type
 *   The type of $entity.
 * @param $entity
58
 *   The entity for the operation.
59 60 61
 * @param $field
 *   The field structure for the operation.
 * @param $instance
62
 *   The instance structure for $field on $entity's bundle.
63 64 65
 * @param $langcode
 *   The language associated to $items.
 * @param $items
66
 *   $entity->{$field['field_name']}[$langcode], or an empty array if unset.
67 68
 * @param $errors
 *   The array of errors, keyed by field name and by value delta, that have
69
 *   already been reported for the entity. The function should add its errors
70 71 72 73 74
 *   to this array. Each error is an associative array, with the following
 *   keys and values:
 *   - 'error': an error code (should be a string, prefixed with the module name)
 *   - 'message': the human readable message to be displayed.
 */
75
function field_default_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
76 77 78 79 80 81 82 83 84 85 86 87 88 89
  // Filter out empty values.
  $items = _field_filter_items($field, $items);

  // Check that the number of values doesn't exceed the field cardinality.
  // For form submitted values, this can only happen with 'multiple value'
  // widgets.
  if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED && count($items) > $field['cardinality']) {
    $errors[$field['field_name']][$langcode][0][] = array(
      'error' => 'field_cardinality',
      'message' => t('%name: this field cannot hold more than @count values.', array('%name' => t($instance['label']), '@count' => $field['cardinality'])),
    );
  }
}

90
function field_default_submit($entity_type, $entity, $field, $instance, $langcode, &$items, $form, &$form_state) {
91 92
  // Filter out empty values.
  $items = _field_filter_items($field, $items);
93 94
  // Reorder items to account for drag-n-drop reordering.
  $items = _field_sort_items($field, $items);
95 96
}

97 98 99
/**
 * Default field 'insert' operation.
 *
100
 * Insert default value if no $entity->$field_name entry was provided.
101 102 103
 * This can happen with programmatic saves, or on form-based creation where
 * the current user doesn't have 'edit' permission for the field.
 */
104 105 106
function field_default_insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
  // _field_invoke() populates $items with an empty array if the $entity has no
  // entry for the field, so we check on the $entity itself.
107 108 109 110
  // We also check that the current field translation is actually defined before
  // assigning it a default value. This way we ensure that only the intended
  // languages get a default value. Otherwise we could have default values for
  // not yet open languages.
111 112 113
  if (empty($entity) || !property_exists($entity, $field['field_name']) ||
    (isset($entity->{$field['field_name']}[$langcode]) && count($entity->{$field['field_name']}[$langcode]) == 0)) {
    $items = field_get_default_value($entity_type, $entity, $field, $instance, $langcode);
114 115
  }
}
116

117
/**
118 119
 * Invokes hook_field_formatter_prepare_view() on the relevant formatters.
 *
120 121 122
 * @param $entity_type
 *   The type of $entity; e.g. 'node' or 'user'.
 * @param $entities
123
 *   An array of entities being displayed, keyed by entity id.
124 125 126
 * @param $field
 *   The field structure for the operation.
 * @param $instances
127
 *   Array of instance structures for $field for each entity, keyed by entity
128 129 130 131
 *   id.
 * @param $langcode
 *   The language associated to $items.
 * @param $items
132
 *   Array of field values already loaded for the entities, keyed by entity id.
133 134
 * @param $display
 *   Can be either:
135
 *   - the name of a view mode
136 137
 *   - or an array of display settings to use for display, as found in the
 *     'display' entry of $instance definitions.
138
 */
139
function field_default_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $display) {
140
  // Group entities, instances and items by formatter module.
141 142
  $modules = array();
  foreach ($instances as $id => $instance) {
143 144
    if (is_string($display)) {
      $view_mode = $display;
145
      $display = field_get_display($instance, $view_mode, $entities[$id]);
146
    }
147 148 149
    if ($display['type'] !== 'hidden') {
      $module = $display['module'];
      $modules[$module] = $module;
150
      $grouped_entities[$module][$id] = $entities[$id];
151 152 153 154 155
      $grouped_instances[$module][$id] = $instance;
      $grouped_displays[$module][$id] = $display;
      // hook_field_formatter_prepare_view() alters $items by reference.
      $grouped_items[$module][$id] = &$items[$id];
    }
156 157 158 159 160 161
  }

  foreach ($modules as $module) {
    // Invoke hook_field_formatter_prepare_view().
    $function = $module . '_field_formatter_prepare_view';
    if (function_exists($function)) {
162
      $function($entity_type, $grouped_entities[$module], $field, $grouped_instances[$module], $langcode, $grouped_items[$module], $grouped_displays[$module]);
163 164 165 166
    }
  }
}

167
/**
168
 * Builds a renderable array for field values.
169
 *
170 171 172
 * @param $entity_type
 *   The type of $entity; e.g. 'node' or 'user'.
 * @param $entities
173
 *   An array of entities being displayed, keyed by entity id.
174 175 176
 * @param $field
 *   The field structure for the operation.
 * @param $instances
177
 *   Array of instance structures for $field for each entity, keyed by entity
178 179 180 181
 *   id.
 * @param $langcode
 *   The language associated to $items.
 * @param $items
182
 *   Array of field values already loaded for the entities, keyed by entity id.
183 184
 * @param $display
 *   Can be either:
185
 *   - the name of a view mode;
186 187
 *   - or an array of custom display settings, as found in the 'display' entry
 *     of $instance definitions.
188
 */
189 190
function field_default_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
191 192 193

  $addition = array();

194 195
  // Prepare incoming display specifications.
  if (is_string($display)) {
196
    $view_mode = $display;
197
    $display = field_get_display($instance, $view_mode, $entity);
198 199
  }
  else {
200
    $view_mode = '_custom_display';
201 202
  }

203
  if ($display['type'] !== 'hidden') {
204 205
    // Calling the formatter function through module_invoke() can have a
    // performance impact on pages with many fields and values.
206
    $function = $display['module'] . '_field_formatter_view';
207
    if (function_exists($function)) {
208
      $elements = $function($entity_type, $entity, $field, $instance, $langcode, $items, $display);
209

210 211 212 213 214
      if ($elements) {
        $info = array(
          '#theme' => 'field',
          '#weight' => $display['weight'],
          '#title' => t($instance['label']),
215
          '#access' => field_access('view', $field, $entity_type, $entity),
216 217 218 219 220 221
          '#label_display' => $display['label'],
          '#view_mode' => $view_mode,
          '#language' => $langcode,
          '#field_name' => $field['field_name'],
          '#field_type' => $field['type'],
          '#field_translatable' => $field['translatable'],
222
          '#entity_type' => $entity_type,
223
          '#bundle' => $bundle,
224
          '#object' => $entity,
225 226 227 228 229 230
          '#items' => $items,
          '#formatter' => $display['type']
        );

        $addition[$field['field_name']] = array_merge($info, $elements);
      }
231
    }
232
  }
233

234 235 236
  return $addition;
}

237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
/**
 * Copies source field values into the entity to be prepared.
 *
 * @param $entity_type
 *   The type of $entity; e.g. 'node' or 'user'.
 * @param $entity
 *   The entity to be prepared for translation.
 * @param $field
 *   The field structure for the operation.
 * @param $instance
 *   The instance structure for $field on $entity's bundle.
 * @param $langcode
 *   The language the entity has to be translated in.
 * @param $items
 *   $entity->{$field['field_name']}[$langcode], or an empty array if unset.
 * @param $source_entity
 *   The source entity holding the field values to be translated.
 * @param $source_langcode
 *   The source language from which translate.
 */
function field_default_prepare_translation($entity_type, $entity, $field, $instance, $langcode, &$items, $source_entity, $source_langcode) {
  $field_name = $field['field_name'];
  // If the field is untranslatable keep using LANGUAGE_NONE.
  if ($langcode == LANGUAGE_NONE) {
    $source_langcode = LANGUAGE_NONE;
  }
  if (isset($source_entity->{$field_name}[$source_langcode])) {
    $items = $source_entity->{$field_name}[$source_langcode];
265
  }
266
}