cms/drupal/modules/field/field.default.inc
changeset 541 e756a8c72c3d
equal deleted inserted replaced
540:07239de796bb 541:e756a8c72c3d
       
     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 }