summaryrefslogtreecommitdiff
path: root/modules/field/field.default.inc
blob: eebde1e14f56ea2c4ad34cb26c42310dc7595580 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
<?php
// $Id$

/**
 * @file
 * Default 'implementations' of hook_field_*(): common field housekeeping.
 *
 * 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.
 * They are called through the _field_invoke_default() iterator, generally in
 * the corresponding field_attach_[operation]() function.
 */

function field_default_extract_form_values($entity_type, $entity, $field, $instance, $langcode, &$items, $form, &$form_state) {
  $field_name = $field['field_name'];

  if (isset($form_state['values'][$field_name][$langcode])) {
    $items = $form_state['values'][$field_name][$langcode];
    // Remove the 'value' of the 'add more' button.
    unset($items['add_more']);
  }
}

/**
 * Generic field validation handler.
 *
 * Possible error codes:
 * - 'field_cardinality': The number of values exceeds the field cardinality.
 *
 * @see _hook_field_validate()
 *
 * @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
 *   $entity->{$field['field_name']}[$langcode], or an empty array if unset.
 * @param $errors
 *   The array of errors, keyed by field name and by value delta, that have
 *   already been reported for the entity. The function should add its errors
 *   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.
 */
function field_default_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
  // 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'])),
    );
  }
}

function field_default_submit($entity_type, $entity, $field, $instance, $langcode, &$items, $form, &$form_state) {
  $field_name = $field['field_name'];

  if (isset($form_state['values'][$field_name][$langcode])) {
    // Reorder items to account for drag-n-drop reordering.
    if (field_behaviors_widget('multiple values', $instance) == FIELD_BEHAVIOR_DEFAULT) {
      $items = _field_sort_items($field, $items);
    }
    // Filter out empty values.
    $items = _field_filter_items($field, $items);
  }
  elseif (!empty($entity->revision) && isset($form_state['entity']->{$field_name}[$langcode])) {
    // To ensure new revisions are created with all field values in all
    // languages, populate values not included in the form with the ones from
    // the original object. This covers:
    // - partial forms including only a subset of the fields,
    // - fields for which the user has no edit access,
    // - languages not involved in the form.
    $items = $form_state['entity']->{$field_name}[$langcode];
  }
}

/**
 * Default field 'insert' operation.
 *
 * Insert default value if no $entity->$field_name entry was provided.
 * This can happen with programmatic saves, or on form-based creation where
 * the current user doesn't have 'edit' permission for the field.
 */
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.
  // 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.
  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);
  }
}

/**
 * Invokes hook_field_formatter_prepare_view() on the relevant formatters.
 *
 * @param $entity_type
 *   The type of $entity; e.g. 'node' or 'user'.
 * @param $entities
 *   An array of entities being displayed, keyed by entity id.
 * @param $field
 *   The field structure for the operation.
 * @param $instances
 *   Array of instance structures for $field for each entity, keyed by entity
 *   id.
 * @param $langcode
 *   The language associated to $items.
 * @param $items
 *   Array of field values already loaded for the entities, keyed by entity id.
 * @param $display
 *   Can be either:
 *   - the name of a view mode
 *   - or an array of display settings to use for display, as found in the
 *     'display' entry of $instance definitions.
*/
function field_default_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $display) {
  // Group entities, instances and items by formatter module.
  $modules = array();
  foreach ($instances as $id => $instance) {
    if (is_string($display)) {
      $view_mode = $display;
      $display = field_get_display($instance, $view_mode);
    }
    if ($display['type'] !== 'hidden') {
      $module = $display['module'];
      $modules[$module] = $module;
      $grouped_entities[$module][$id] = $entities[$id];
      $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];
    }
  }

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

/**
 * Builds a renderable array for field values.
 *
 * @param $entity_type
 *   The type of $entity; e.g. 'node' or 'user'.
 * @param $entities
 *   An array of entities being displayed, keyed by entity id.
 * @param $field
 *   The field structure for the operation.
 * @param $instances
 *   Array of instance structures for $field for each entity, keyed by entity
 *   id.
 * @param $langcode
 *   The language associated to $items.
 * @param $items
 *   Array of field values already loaded for the entities, keyed by entity id.
 * @param $display
 *   Can be either:
 *   - the name of a view mode;
 *   - or an array of custom display settings, as found in the 'display' entry
 *     of $instance definitions.
 */
function field_default_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);

  $addition = array();

  // Prepare incoming display specifications.
  if (is_string($display)) {
    $view_mode = $display;
    $display = field_get_display($instance, $view_mode);
  }
  else {
    $view_mode = '_custom_display';
  }

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

      if ($elements) {
        $info = array(
          '#theme' => 'field',
          '#weight' => $display['weight'],
          '#title' => t($instance['label']),
          '#access' => field_access('view', $field, $entity_type, $entity),
          '#label_display' => $display['label'],
          '#view_mode' => $view_mode,
          '#language' => $langcode,
          '#field_name' => $field['field_name'],
          '#field_type' => $field['type'],
          '#field_translatable' => $field['translatable'],
          '#entity_type' => $entity_type,
          '#bundle' => $bundle,
          '#object' => $entity,
          '#items' => $items,
          '#formatter' => $display['type']
        );

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

  return $addition;
}

function field_default_prepare_translation($entity_type, $entity, $field, $instance, $langcode, &$items) {
  $addition = array();
  if (isset($entity->translation_source->$field['field_name'])) {
    $addition[$field['field_name']] = $entity->translation_source->$field['field_name'];
  }
  return $addition;
}