|
1 <?php |
|
2 |
|
3 /** |
|
4 * @file |
|
5 * Default 'implementations' of hook_field_*(): common field housekeeping. |
|
6 * |
|
7 * Those implementations are special, as field.module does not define any field |
|
8 * types. Those functions take care of default stuff common to all field types. |
|
9 * They are called through the _field_invoke_default() iterator, generally in |
|
10 * the corresponding field_attach_[operation]() function. |
|
11 */ |
|
12 |
|
13 /** |
|
14 * Extracts field values from submitted form values. |
|
15 * |
|
16 * @param $entity_type |
|
17 * The type of $entity. |
|
18 * @param $entity |
|
19 * The entity for the operation. |
|
20 * @param $field |
|
21 * The field structure for the operation. |
|
22 * @param $instance |
|
23 * The instance structure for $field on $entity's bundle. |
|
24 * @param $langcode |
|
25 * The language associated to $items. |
|
26 * @param $items |
|
27 * The field values. This parameter is altered by reference to receive the |
|
28 * incoming form values. |
|
29 * @param $form |
|
30 * The form structure where field elements are attached to. This might be a |
|
31 * full form structure, or a sub-element of a larger form. |
|
32 * @param $form_state |
|
33 * The form state. |
|
34 */ |
|
35 function field_default_extract_form_values($entity_type, $entity, $field, $instance, $langcode, &$items, $form, &$form_state) { |
|
36 $path = array_merge($form['#parents'], array($field['field_name'], $langcode)); |
|
37 $key_exists = NULL; |
|
38 $values = drupal_array_get_nested_value($form_state['values'], $path, $key_exists); |
|
39 if ($key_exists) { |
|
40 // Remove the 'value' of the 'add more' button. |
|
41 unset($values['add_more']); |
|
42 $items = $values; |
|
43 } |
|
44 } |
|
45 |
|
46 /** |
|
47 * Generic field validation handler. |
|
48 * |
|
49 * Possible error codes: |
|
50 * - 'field_cardinality': The number of values exceeds the field cardinality. |
|
51 * |
|
52 * @see _hook_field_validate() |
|
53 * |
|
54 * @param $entity_type |
|
55 * The type of $entity. |
|
56 * @param $entity |
|
57 * The entity for the operation. |
|
58 * @param $field |
|
59 * The field structure for the operation. |
|
60 * @param $instance |
|
61 * The instance structure for $field on $entity's bundle. |
|
62 * @param $langcode |
|
63 * The language associated to $items. |
|
64 * @param $items |
|
65 * $entity->{$field['field_name']}[$langcode], or an empty array if unset. |
|
66 * @param $errors |
|
67 * The array of errors, keyed by field name and by value delta, that have |
|
68 * already been reported for the entity. The function should add its errors |
|
69 * to this array. Each error is an associative array, with the following |
|
70 * keys and values: |
|
71 * - 'error': an error code (should be a string, prefixed with the module name) |
|
72 * - 'message': the human readable message to be displayed. |
|
73 */ |
|
74 function field_default_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) { |
|
75 // Filter out empty values. |
|
76 $items = _field_filter_items($field, $items); |
|
77 |
|
78 // Check that the number of values doesn't exceed the field cardinality. |
|
79 // For form submitted values, this can only happen with 'multiple value' |
|
80 // widgets. |
|
81 if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED && count($items) > $field['cardinality']) { |
|
82 $errors[$field['field_name']][$langcode][0][] = array( |
|
83 'error' => 'field_cardinality', |
|
84 'message' => t('%name: this field cannot hold more than @count values.', array('%name' => $instance['label'], '@count' => $field['cardinality'])), |
|
85 ); |
|
86 } |
|
87 } |
|
88 |
|
89 function field_default_submit($entity_type, $entity, $field, $instance, $langcode, &$items, $form, &$form_state) { |
|
90 // Filter out empty values. |
|
91 $items = _field_filter_items($field, $items); |
|
92 // Reorder items to account for drag-n-drop reordering. |
|
93 $items = _field_sort_items($field, $items); |
|
94 } |
|
95 |
|
96 /** |
|
97 * Default field 'insert' operation. |
|
98 * |
|
99 * Insert default value if no $entity->$field_name entry was provided. |
|
100 * This can happen with programmatic saves, or on form-based creation where |
|
101 * the current user doesn't have 'edit' permission for the field. |
|
102 */ |
|
103 function field_default_insert($entity_type, $entity, $field, $instance, $langcode, &$items) { |
|
104 // _field_invoke() populates $items with an empty array if the $entity has no |
|
105 // entry for the field, so we check on the $entity itself. |
|
106 // We also check that the current field translation is actually defined before |
|
107 // assigning it a default value. This way we ensure that only the intended |
|
108 // languages get a default value. Otherwise we could have default values for |
|
109 // not yet open languages. |
|
110 if (empty($entity) || !property_exists($entity, $field['field_name']) || |
|
111 (isset($entity->{$field['field_name']}[$langcode]) && count($entity->{$field['field_name']}[$langcode]) == 0)) { |
|
112 $items = field_get_default_value($entity_type, $entity, $field, $instance, $langcode); |
|
113 } |
|
114 } |
|
115 |
|
116 /** |
|
117 * Invokes hook_field_formatter_prepare_view() on the relevant formatters. |
|
118 * |
|
119 * @param $entity_type |
|
120 * The type of $entity; e.g. 'node' or 'user'. |
|
121 * @param $entities |
|
122 * An array of entities being displayed, keyed by entity id. |
|
123 * @param $field |
|
124 * The field structure for the operation. |
|
125 * @param $instances |
|
126 * Array of instance structures for $field for each entity, keyed by entity |
|
127 * id. |
|
128 * @param $langcode |
|
129 * The language associated to $items. |
|
130 * @param $items |
|
131 * Array of field values already loaded for the entities, keyed by entity id. |
|
132 * @param $display |
|
133 * Can be either: |
|
134 * - the name of a view mode |
|
135 * - or an array of display settings to use for display, as found in the |
|
136 * 'display' entry of $instance definitions. |
|
137 */ |
|
138 function field_default_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $display) { |
|
139 // Group entities, instances and items by formatter module. |
|
140 $modules = array(); |
|
141 foreach ($instances as $id => $instance) { |
|
142 if (is_string($display)) { |
|
143 $view_mode = $display; |
|
144 $instance_display = field_get_display($instance, $view_mode, $entities[$id]); |
|
145 } |
|
146 else { |
|
147 $instance_display = $display; |
|
148 } |
|
149 |
|
150 if ($instance_display['type'] !== 'hidden') { |
|
151 $module = $instance_display['module']; |
|
152 $modules[$module] = $module; |
|
153 $grouped_entities[$module][$id] = $entities[$id]; |
|
154 $grouped_instances[$module][$id] = $instance; |
|
155 $grouped_displays[$module][$id] = $instance_display; |
|
156 // hook_field_formatter_prepare_view() alters $items by reference. |
|
157 $grouped_items[$module][$id] = &$items[$id]; |
|
158 } |
|
159 } |
|
160 |
|
161 foreach ($modules as $module) { |
|
162 // Invoke hook_field_formatter_prepare_view(). |
|
163 $function = $module . '_field_formatter_prepare_view'; |
|
164 if (function_exists($function)) { |
|
165 $function($entity_type, $grouped_entities[$module], $field, $grouped_instances[$module], $langcode, $grouped_items[$module], $grouped_displays[$module]); |
|
166 } |
|
167 } |
|
168 } |
|
169 |
|
170 /** |
|
171 * Builds a renderable array for one field on one entity instance. |
|
172 * |
|
173 * @param $entity_type |
|
174 * The type of $entity; e.g. 'node' or 'user'. |
|
175 * @param $entity |
|
176 * A single object of type $entity_type. |
|
177 * @param $field |
|
178 * The field structure for the operation. |
|
179 * @param $instance |
|
180 * An array containing each field on $entity's bundle. |
|
181 * @param $langcode |
|
182 * The language associated to $items. |
|
183 * @param $items |
|
184 * Array of field values already loaded for the entities, keyed by entity id. |
|
185 * @param $display |
|
186 * Can be either: |
|
187 * - the name of a view mode; |
|
188 * - or an array of custom display settings, as found in the 'display' entry |
|
189 * of $instance definitions. |
|
190 */ |
|
191 function field_default_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) { |
|
192 list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity); |
|
193 |
|
194 $addition = array(); |
|
195 |
|
196 // Prepare incoming display specifications. |
|
197 if (is_string($display)) { |
|
198 $view_mode = $display; |
|
199 $display = field_get_display($instance, $view_mode, $entity); |
|
200 } |
|
201 else { |
|
202 $view_mode = '_custom_display'; |
|
203 } |
|
204 |
|
205 if ($display['type'] !== 'hidden') { |
|
206 // Calling the formatter function through module_invoke() can have a |
|
207 // performance impact on pages with many fields and values. |
|
208 $function = $display['module'] . '_field_formatter_view'; |
|
209 if (function_exists($function)) { |
|
210 $elements = $function($entity_type, $entity, $field, $instance, $langcode, $items, $display); |
|
211 |
|
212 if ($elements) { |
|
213 $info = array( |
|
214 '#theme' => 'field', |
|
215 '#weight' => $display['weight'], |
|
216 '#title' => $instance['label'], |
|
217 '#access' => field_access('view', $field, $entity_type, $entity), |
|
218 '#label_display' => $display['label'], |
|
219 '#view_mode' => $view_mode, |
|
220 '#language' => $langcode, |
|
221 '#field_name' => $field['field_name'], |
|
222 '#field_type' => $field['type'], |
|
223 '#field_translatable' => $field['translatable'], |
|
224 '#entity_type' => $entity_type, |
|
225 '#bundle' => $bundle, |
|
226 '#object' => $entity, |
|
227 '#items' => $items, |
|
228 '#formatter' => $display['type'] |
|
229 ); |
|
230 |
|
231 $addition[$field['field_name']] = array_merge($info, $elements); |
|
232 } |
|
233 } |
|
234 } |
|
235 |
|
236 return $addition; |
|
237 } |
|
238 |
|
239 /** |
|
240 * Copies source field values into the entity to be prepared. |
|
241 * |
|
242 * @param $entity_type |
|
243 * The type of $entity; e.g. 'node' or 'user'. |
|
244 * @param $entity |
|
245 * The entity to be prepared for translation. |
|
246 * @param $field |
|
247 * The field structure for the operation. |
|
248 * @param $instance |
|
249 * The instance structure for $field on $entity's bundle. |
|
250 * @param $langcode |
|
251 * The language the entity has to be translated in. |
|
252 * @param $items |
|
253 * $entity->{$field['field_name']}[$langcode], or an empty array if unset. |
|
254 * @param $source_entity |
|
255 * The source entity holding the field values to be translated. |
|
256 * @param $source_langcode |
|
257 * The source language from which translate. |
|
258 */ |
|
259 function field_default_prepare_translation($entity_type, $entity, $field, $instance, $langcode, &$items, $source_entity, $source_langcode) { |
|
260 $field_name = $field['field_name']; |
|
261 // If the field is untranslatable keep using LANGUAGE_NONE. |
|
262 if ($langcode == LANGUAGE_NONE) { |
|
263 $source_langcode = LANGUAGE_NONE; |
|
264 } |
|
265 if (isset($source_entity->{$field_name}[$source_langcode])) { |
|
266 $items = $source_entity->{$field_name}[$source_langcode]; |
|
267 } |
|
268 } |