/[drupal]/drupal/modules/field/field.module
ViewVC logotype

Contents of /drupal/modules/field/field.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.47 - (show annotations) (download) (as text)
Sat Oct 31 18:00:48 2009 UTC (3 weeks, 4 days ago) by dries
Branch: MAIN
CVS Tags: DRUPAL-7-0-UNSTABLE-10, HEAD
Changes since 1.46: +3 -13 lines
File MIME type: text/x-php
- Patch #615484 by yched: remove schema rebuild from field_cache_clear().
1 <?php
2 // $Id: field.module,v 1.46 2009/10/31 16:06:35 dries Exp $
3 /**
4 * @file
5 * Attach custom data fields to Drupal objects.
6 */
7
8 /*
9 * Load all public Field API functions. Drupal currently has no
10 * mechanism for auto-loading core APIs, so we have to load them on
11 * every page request.
12 */
13 module_load_include('inc', 'field', 'field.crud');
14 module_load_include('inc', 'field', 'field.default');
15 module_load_include('inc', 'field', 'field.info');
16 module_load_include('inc', 'field', 'field.multilingual');
17 module_load_include('inc', 'field', 'field.attach');
18 module_load_include('inc', 'field', 'field.form');
19
20 /**
21 * @defgroup field Field API
22 * @{
23 * Attach custom data fields to Drupal objects.
24 *
25 * The Field API allows custom data fields to be attached to Drupal
26 * objects and takes care of storing, loading, editing, and rendering
27 * field data. Any object type (node, user, etc.) can use the Field
28 * API to make itself "fieldable" and thus allow fields to be attached
29 * to it. Other modules can provide a user interface for managing custom
30 * fields via a web browser as well as a wide and flexible variety of
31 * data type, form element, and display format capabilities.
32 *
33 * - @link field_structs Data structures: Field, Instance, Bundle @endlink.
34 *
35 * - @link field_types Field Types API @endlink. Defines field types,
36 * widget types, and display formatters. Field modules use this API
37 * to provide field types like Text and Node Reference along with the
38 * associated form elements and display formatters.
39 *
40 * - @link field_crud Field CRUD API @endlink. Create, updates, and
41 * deletes fields, bundles (a.k.a. "content types"), and instances.
42 * Modules use this API, often in hook_install(), to create
43 * custom data structures.
44 *
45 * - @link field_attach Field Attach API @endlink. Connects object
46 * types to the Field API. Field Attach API functions load, store,
47 * generate Form API structures, display, and perform a variety of
48 * other functions for field data connected to individual objects.
49 * Fieldable object types like node and user use this API to make
50 * themselves fieldable.
51 *
52 * - @link field_info Field Info API @endlink. Exposes information
53 * about all fields, instances, widgets, and related information
54 * defined by or with the Field API.
55 *
56 * - @link field_storage Field Storage API @endlink. Provides a
57 * pluggable back-end storage system for actual field data. The
58 * default implementation, field_sql_storage.module, stores field data
59 * in the local SQL database.
60
61 * - @link field_purge Field API bulk data deletion @endlink. Cleans
62 * up after bulk deletion operations such as field_delete_field()
63 * and field_delete_instance().
64 */
65
66 /**
67 * Value for $field['cardinality'] property to indicate it can hold an
68 * unlimited number of values.
69 */
70 define('FIELD_CARDINALITY_UNLIMITED', -1);
71
72 /**
73 * The language code assigned to untranslatable fields.
74 *
75 * Defined by ISO639-2 for "No linguistic content / Not applicable".
76 */
77 define('FIELD_LANGUAGE_NONE', 'zxx');
78
79 /**
80 * TODO
81 */
82 define('FIELD_BEHAVIOR_NONE', 0x0001);
83 /**
84 * TODO
85 */
86 define('FIELD_BEHAVIOR_DEFAULT', 0x0002);
87 /**
88 * TODO
89 */
90 define('FIELD_BEHAVIOR_CUSTOM', 0x0004);
91
92 /**
93 * Age argument for loading the most recent version of an object's
94 * field data with field_attach_load().
95 */
96 define('FIELD_LOAD_CURRENT', 'FIELD_LOAD_CURRENT');
97 /**
98 * Age argument for loading the version of an object's field data
99 * specified in the object with field_attach_load().
100 */
101 define('FIELD_LOAD_REVISION', 'FIELD_LOAD_REVISION');
102
103 /**
104 * @name Field query flags
105 * @{
106 * Flags for field_attach_query().
107 */
108
109 /**
110 * Limit argument for field_attach_query() to request all available
111 * objects instead of a limited number.
112 */
113 define('FIELD_QUERY_NO_LIMIT', 'FIELD_QUERY_NO_LIMIT');
114
115 /**
116 * Cursor return value for field_attach_query() to indicate that no
117 * more data is available.
118 */
119 define('FIELD_QUERY_COMPLETE', 'FIELD_QUERY_COMPLETE');
120
121 /**
122 * @} End of "Field query flags".
123 */
124
125 /**
126 * Base class for all exceptions thrown by Field API functions.
127 *
128 * This class has no functionality of its own other than allowing all
129 * Field API exceptions to be caught by a single catch block.
130 */
131 class FieldException extends Exception {}
132
133 /**
134 * Exception class thrown by hook_field_update_forbid().
135 */
136 class FieldUpdateForbiddenException extends FieldException {}
137
138 /**
139 * Implement hook_flush_caches.
140 */
141 function field_flush_caches() {
142 return array('cache_field');
143 }
144
145 /**
146 * Implement hook_help().
147 */
148 function field_help($path, $arg) {
149 switch ($path) {
150 case 'admin/help#field':
151 $output = '<p>' . t('The Field API allows custom data fields to be attached to Drupal objects and takes care of storing, loading, editing, and rendering field data. Any object type (node, user, etc.) can use the Field API to make itself "fieldable" and thus allow fields to be attached to it.') . '</p>';
152 return $output;
153 }
154 }
155
156 /**
157 * Implement hook_theme().
158 */
159 function field_theme() {
160 $path = drupal_get_path('module', 'field') . '/theme';
161 $items = array(
162 'field' => array(
163 'template' => 'field',
164 'render element' => 'element',
165 'path' => $path,
166 ),
167 'field_multiple_value_form' => array(
168 'render element' => 'element',
169 ),
170 );
171 $field_formatters = field_info_formatter_types(NULL);
172 foreach ($field_formatters as $key => $field_formatter) {
173 $items['field_formatter_' . $key] = array(
174 'render element' => 'element',
175 );
176 if (isset($field_formatter['theme'])) {
177 $items['field_formatter_' . $key] += $field_formatter['theme'];
178 }
179 }
180 return $items;
181 }
182
183 /**
184 * Implement hook_cron().
185 *
186 * Purges some deleted Field API data, if any exists.
187 */
188 function field_cron() {
189 $limit = variable_get('field_purge_batch_size', 10);
190 field_purge_batch($limit);
191 }
192
193 /**
194 * Implement hook_modules_installed().
195 */
196 function field_modules_installed($modules) {
197 field_cache_clear();
198 }
199
200 /**
201 * Implement hook_modules_uninstalled().
202 */
203 function field_modules_uninstalled($modules) {
204 module_load_include('inc', 'field', 'field.crud');
205 foreach ($modules as $module) {
206 // TODO D7: field_module_delete is not yet implemented
207 // field_module_delete($module);
208 }
209 }
210
211 /**
212 * Implement hook_modules_enabled().
213 */
214 function field_modules_enabled($modules) {
215 foreach ($modules as $module) {
216 field_associate_fields($module);
217 }
218 field_cache_clear();
219 }
220
221 /**
222 * Implement hook_modules_disabled().
223 */
224 function field_modules_disabled($modules) {
225 foreach ($modules as $module) {
226 db_update('field_config')
227 ->fields(array('active' => 0))
228 ->condition('module', $module)
229 ->execute();
230 db_update('field_config')
231 ->fields(array('storage_active' => 0))
232 ->condition('storage_module', $module)
233 ->execute();
234 field_cache_clear(TRUE);
235 }
236 }
237
238 /**
239 * Allows a module to update the database for fields and columns it controls.
240 *
241 * @param string $module
242 * The name of the module to update on.
243 */
244 function field_associate_fields($module) {
245 // Associate field types.
246 $field_types =(array) module_invoke($module, 'field_info');
247 foreach ($field_types as $name => $field_info) {
248 watchdog('field', 'Updating field type %type with module %module.', array('%type' => $name, '%module' => $module));
249 db_update('field_config')
250 ->fields(array('module' => $module, 'active' => 1))
251 ->condition('type', $name)
252 ->execute();
253 }
254 // Associate storage backends.
255 $storage_types = (array) module_invoke($module, 'field_storage_info');
256 foreach ($storage_types as $name => $storage_info) {
257 watchdog('field', 'Updating field storage %type with module %module.', array('%type' => $name, '%module' => $module));
258 db_update('field_config')
259 ->fields(array('storage_module' => $module, 'storage_active' => 1))
260 ->condition('storage_type', $name)
261 ->execute();
262 }
263 }
264
265 /**
266 * Helper function to get the default value for a field on an object.
267 *
268 * @param $obj_type
269 * The type of $object; e.g. 'node' or 'user'.
270 * @param $object
271 * The object for the operation.
272 * @param $field
273 * The field structure.
274 * @param $instance
275 * The instance structure.
276 * @param $langcode
277 * The field language to fill-in with the default value.
278 */
279 function field_get_default_value($obj_type, $object, $field, $instance, $langcode = NULL) {
280 $items = array();
281 if (!empty($instance['default_value_function'])) {
282 $function = $instance['default_value_function'];
283 if (function_exists($function)) {
284 $items = $function($obj_type, $object, $field, $instance, $langcode);
285 }
286 }
287 elseif (!empty($instance['default_value'])) {
288 $items = $instance['default_value'];
289 }
290 return $items;
291 }
292
293 /**
294 * Helper function to filter out empty values.
295 *
296 * On order to keep marker rows in the database, the function ensures
297 * that the right number of 'all columns NULL' values is kept.
298 *
299 * @param array $field
300 * @param array $items
301 * @return array
302 * returns filtered and adjusted item array
303 *
304 * TODO D7: poorly named...
305 */
306 function field_set_empty($field, $items) {
307 $function = $field['module'] . '_field_is_empty';
308 // We ensure the function is loaded, but explicitly break if it is missing.
309 function_exists($function);
310 foreach ((array) $items as $delta => $item) {
311 if ($function($item, $field)) {
312 unset($items[$delta]);
313 }
314 }
315 return array_values($items);
316 }
317
318 /**
319 * Helper function to sort items in a field according to
320 * user drag-n-drop reordering.
321 */
322 function _field_sort_items($field, $items) {
323 if (($field['cardinality'] > 1 || $field['cardinality'] == FIELD_CARDINALITY_UNLIMITED) && isset($items[0]['_weight'])) {
324 usort($items, '_field_sort_items_helper');
325 foreach ($items as $delta => $item) {
326 if (is_array($items[$delta])) {
327 unset($items[$delta]['_weight']);
328 }
329 }
330 }
331 return $items;
332 }
333
334 /**
335 * Sort function for items order.
336 * (copied form element_sort(), which acts on #weight keys)
337 */
338 function _field_sort_items_helper($a, $b) {
339 $a_weight = (is_array($a) && isset($a['_weight'])) ? $a['_weight'] : 0;
340 $b_weight = (is_array($b) && isset($b['_weight'])) ? $b['_weight'] : 0;
341 if ($a_weight == $b_weight) {
342 return 0;
343 }
344 return ($a_weight < $b_weight) ? -1 : 1;
345 }
346
347 /**
348 * Same as above, using ['_weight']['#value']
349 */
350 function _field_sort_items_value_helper($a, $b) {
351 $a_weight = (is_array($a) && isset($a['_weight']['#value'])) ? $a['_weight']['#value'] : 0;
352 $b_weight = (is_array($b) && isset($b['_weight']['#value'])) ? $b['_weight']['#value'] : 0;
353 if ($a_weight == $b_weight) {
354 return 0;
355 }
356 return ($a_weight < $b_weight) ? -1 : 1;
357 }
358
359 /**
360 * Registry of available build modes.
361 */
362 function field_build_modes($obj_type) {
363 $info = &drupal_static(__FUNCTION__, array());
364
365 if (!isset($info[$obj_type])) {
366 $info[$obj_type] = module_invoke_all('field_build_modes', $obj_type);
367 }
368 return $info[$obj_type];
369 }
370
371 /**
372 * Registry of pseudo-field components in a given bundle.
373 *
374 * @param $bundle_name
375 * The bundle name.
376 * @return
377 * The array of pseudo-field elements in the bundle.
378 */
379 function field_extra_fields($bundle_name) {
380 $info = &drupal_static(__FUNCTION__, array());
381
382 if (empty($info)) {
383 $info = array();
384 $bundles = field_info_bundles();
385 foreach ($bundles as $bundle => $bundle_label) {
386 // Gather information about non-field object additions.
387 $extra = module_invoke_all('field_extra_fields', $bundle);
388 drupal_alter('field_extra_fields', $extra, $bundle);
389
390 // Add saved weights.
391 foreach (variable_get("field_extra_weights_$bundle", array()) as $key => $value) {
392 // Some stored entries might not exist anymore, for instance if uploads
393 // have been disabled or vocabularies were deleted.
394 if (isset($extra[$key])) {
395 $extra[$key]['weight'] = $value;
396 }
397 }
398 $info[$bundle] = $extra;
399 }
400 }
401 if (array_key_exists($bundle_name, $info)) {
402 return $info[$bundle_name];
403 }
404 else {
405 return array();
406 }
407 }
408
409 /**
410 * Pre-render callback to adjust weights of non-field elements on objects.
411 */
412 function _field_extra_weights_pre_render($elements) {
413 if (isset($elements['#extra_fields'])) {
414 foreach ($elements['#extra_fields'] as $key => $value) {
415 // Some core 'fields' use a different key in node forms and in 'view'
416 // render arrays. Ensure that we are not on a form first.
417 if (!isset($elements['#build_id']) && isset($value['view']) && isset($elements[$value['view']])) {
418 $elements[$value['view']]['#weight'] = $value['weight'];
419 }
420 elseif (isset($elements[$key])) {
421 $elements[$key]['#weight'] = $value['weight'];
422 }
423 }
424 }
425 return $elements;
426 }
427
428 /**
429 * Clear the field info and field date caches.
430 */
431 function field_cache_clear() {
432 cache_clear_all('*', 'cache_field', TRUE);
433 field_info_cache_clear();
434 }
435
436 /**
437 * Like filter_xss_admin(), but with a shorter list of allowed tags.
438 *
439 * Used for items entered by administrators, like field descriptions,
440 * allowed values, where some (mainly inline) mark-up may be desired
441 * (so check_plain() is not acceptable).
442 */
443 function field_filter_xss($string) {
444 return filter_xss($string, _field_filter_xss_allowed_tags());
445 }
446
447 /**
448 * List of tags allowed by field_filter_xss().
449 */
450 function _field_filter_xss_allowed_tags() {
451 return array('a', 'b', 'big', 'code', 'del', 'em', 'i', 'ins', 'pre', 'q', 'small', 'span', 'strong', 'sub', 'sup', 'tt', 'ol', 'ul', 'li', 'p', 'br', 'img');
452 }
453
454 /**
455 * Human-readable list of allowed tags, for display in help texts.
456 */
457 function _field_filter_xss_display_allowed_tags() {
458 return '<' . implode('> <', _field_filter_xss_allowed_tags()) . '>';
459 }
460
461 /**
462 * Format a field item for display.
463 *
464 * TODO D7 : do we still need field_format ?
465 * - backwards compatibility of templates - check what fallbacks we can propose...
466 * - was used by Views integration in CCK in D6 - do we need now?
467 * At least needs a little rehaul/update...
468 *
469 * Used to display a field's values outside the context of the $node, as
470 * when fields are displayed in Views, or to display a field in a template
471 * using a different formatter than the one set up on the 'Manage display' tab
472 * for the node's context.
473 *
474 * @param $field
475 * Either a field array or the name of the field.
476 * @param $item
477 * The field item(s) to be formatted (such as $node->field_foo[0],
478 * or $node->field_foo if the formatter handles multiple values itself)
479 * @param $formatter_type
480 * The name of the formatter type to use.
481 * @param $node
482 * Optionally, the containing node object for context purposes and
483 * field-instance options.
484 *
485 * @return
486 * A string containing the contents of the field item(s) sanitized for display.
487 * It will have been passed through the necessary check_plain() or check_markup()
488 * functions as necessary.
489 */
490 function field_format($obj_type, $object, $field, $item, $formatter_type = NULL, $formatter_settings = array()) {
491 if (!is_array($field)) {
492 $field = field_info_field($field);
493 }
494
495 if (field_access('view', $field, $obj_type, $object)) {
496 $field_type = field_info_field_types($field['type']);
497
498 // We need $field, $instance, $obj_type, $object to be able to display a value...
499 list(, , $bundle) = entity_extract_ids($obj_type, $object);
500 $instance = field_info_instance($obj_type, $field['field_name'], $bundle);
501
502 $display = array(
503 'type' => $formatter_type ? $formatter_type : $field_type['default_formatter'],
504 'settings' => $formatter_settings,
505 );
506 $display['settings'] += field_info_formatter_settings($display['type']);
507
508 if ($display['type'] !== 'hidden') {
509 $theme = $formatter['module'] . '_formatter_' . $display['type'];
510
511 $element = array(
512 '#theme' => $theme,
513 '#field_name' => $field['field_name'],
514 '#object_type' => $obj_type,
515 '#bundle' => $bundle,
516 '#formatter' => $display['type'],
517 '#settings' => $display['settings'],
518 '#object' => $object,
519 '#object_type' => $obj_type,
520 '#delta' => isset($item['#delta']) ? $item['#delta'] : NULL,
521 );
522
523 if (field_behaviors_formatter('multiple values', $display) == FIELD_BEHAVIOR_DEFAULT) {
524 // Single value formatter.
525
526 // hook_field('sanitize') expects an array of items, so we build one.
527 $items = array($item);
528 $function = $field['module'] . '_field_sanitize';
529 if (function_exists($function)) {
530 $function($obj_type, $object, $field, $instance, $items);
531 }
532
533 $element['#item'] = $items[0];
534 }
535 else {
536 // Multiple values formatter.
537 $items = $item;
538 $function = $field['module'] . '_field_sanitize';
539 if (function_exists($function)) {
540 $function($obj_type, $object, $field, $instance, $items);
541 }
542
543 foreach ($items as $delta => $item) {
544 $element[$delta] = array(
545 '#item' => $item,
546 '#weight' => $delta,
547 );
548 }
549 }
550
551 return theme($theme, $element);
552 }
553 }
554 }
555
556 /**
557 * Return a single field, fully themed with label and multiple values.
558 *
559 * To be used by third-party code (Views, Panels...) that needs to output
560 * an isolated field. Do *not* use inside node templates, use
561 * render($content[FIELD_NAME]) instead.
562 *
563 * The field will be displayed using the display options (label display,
564 * formatter settings...) specified in the $instance structure for the given
565 * build mode: $instance['display'][$build_mode].
566 *
567 * @param $object
568 * The object containing the field to display. Must at least contain the id key,
569 * revision key (if applicable), bundle key, and the field data.
570 * @param $field
571 * The field structure.
572 * @param $instance
573 * The instance structure for $field on $object's bundle.
574 * @param $build_mode
575 * Build mode, e.g. 'full', 'teaser'...
576 * @return
577 * The themed output for the field.
578 */
579 function field_view_field($obj_type, $object, $field, $instance, $build_mode = 'full') {
580 $output = '';
581 if (isset($object->$field['field_name'])) {
582 $items = $object->$field['field_name'];
583
584 // One-field equivalent to _field_invoke('sanitize').
585 $function = $field['module'] . '_field_sanitize';
586 if (function_exists($function)) {
587 $function($obj_type, $object, $field, $instance, $items);
588 $object->$field['field_name'] = $items;
589 }
590
591 $view = field_default_view($obj_type, $object, $field, $instance, $items, $build_mode);
592 // TODO : what about hook_field_attach_view ?
593
594 $output = $view[$field['field_name']];
595 }
596 return $output;
597 }
598
599 /**
600 * Determine whether a field has any data.
601 *
602 * @param $field
603 * A field structure.
604 * @return
605 * TRUE if the field has data for any object; FALSE otherwise.
606 */
607 function field_has_data($field) {
608 $results = field_attach_query($field['id'], array(), array('limit' => 1));
609 return !empty($results);
610 }
611
612 /**
613 * Determine whether the user has access to a given field.
614 *
615 * @param $op
616 * The operation to be performed. Possible values:
617 * - "edit"
618 * - "view"
619 * @param $field
620 * The field on which the operation is to be performed.
621 * @param $obj_type
622 * The type of $object; e.g. 'node' or 'user'.
623 * @param $object
624 * (optional) The object for the operation.
625 * @param $account
626 * (optional) The account to check, if not given use currently logged in user.
627 * @return
628 * TRUE if the operation is allowed;
629 * FALSE if the operation is denied.
630 */
631 function field_access($op, $field, $obj_type, $object = NULL, $account = NULL) {
632 global $user;
633
634 if (is_null($account)) {
635 $account = $user;
636 }
637
638 $field_access = module_invoke_all('field_access', $op, $field, $obj_type, $object, $account);
639 foreach ($field_access as $value) {
640 if ($value === FALSE) {
641 return FALSE;
642 }
643 }
644 return TRUE;
645 }
646
647 /**
648 * Helper function to extract the bundle name of from a bundle object.
649 *
650 * @param $obj_type
651 * The type of $object; e.g. 'node' or 'user'.
652 * @param $bundle
653 * The bundle object (or string if bundles for this object type do not exist
654 * as standalone objects).
655 * @return
656 * The bundle name.
657 */
658 function field_extract_bundle($obj_type, $bundle) {
659 if (is_string($bundle)) {
660 return $bundle;
661 }
662
663 $info = entity_get_info($obj_type);
664 if (is_object($bundle) && isset($info['bundle keys']['bundle']) && isset($bundle->{$info['bundle keys']['bundle']})) {
665 return $bundle->{$info['bundle keys']['bundle']};
666 }
667 }
668
669 /**
670 * Theme preprocess function for field.tpl.php.
671 *
672 * @see field.tpl.php
673 */
674 function template_preprocess_field(&$variables) {
675 $element = $variables['element'];
676 list(, , $bundle) = entity_extract_ids($element['#object_type'], $element['#object']);
677 $instance = field_info_instance($element['#object_type'], $element['#field_name'], $bundle);
678 $field = field_info_field($element['#field_name']);
679
680 $field_type_css = strtr($field['type'], '_', '-');
681 $field_name_css = strtr($field['field_name'], '_', '-');
682
683 // If the formatter is multiple, the template sees only one 'item', which
684 // will include all values.
685 $items = $element['#formatter_single'] ? $element['items'] : array($element['items']);
686
687 $additions = array(
688 'object' => $element['#object'],
689 'field' => $field,
690 'instance' => $instance,
691 'build_mode' => $element['#build_mode'],
692 'items' => $items,
693 'field_type' => $field['type'],
694 'field_name' => $field['field_name'],
695 'field_type_css' => $field_type_css,
696 'field_name_css' => $field_name_css,
697 'label' => $element['#title'],
698 'label_display' => $element['#label_display'],
699 'label_hidden' => $element['#label_display'] == 'hidden',
700 'field_language' => $element['#language'],
701 'field_translatable' => $field['translatable'],
702 'classes_array' => array(
703 'field-name-' . $field_name_css,
704 'field-type-' . $field_type_css,
705 'field-label-' . $element['#label_display'],
706 ),
707 'template_files' => array(
708 'field',
709 'field-' . $element['#field_name'],
710 'field-' . $bundle,
711 'field-' . $element['#field_name'] . '-' . $bundle,
712 ),
713 );
714 $variables = array_merge($variables, $additions);
715
716 // Initialize attributes for each item.
717 foreach ($variables['items'] as $delta => $item) {
718 $variables['item_attributes_array'][$delta] = array();
719 }
720 }
721
722 /**
723 * Theme process function for field.tpl.php.
724 *
725 * @see field.tpl.php
726 */
727 function template_process_field(&$variables) {
728 // Flatten out attributes for each item.
729 foreach ($variables['items'] as $delta => $item) {
730 $variables['item_attributes'][$delta] = drupal_attributes($variables['item_attributes_array'][$delta]);
731 }
732 }
733 /**
734 * @} End of "defgroup field"
735 */

  ViewVC Help
Powered by ViewVC 1.1.2