Projet

Général

Profil

Paste
Télécharger (12 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / ctools / includes / fields.inc @ 74f6bef0

1
<?php
2

    
3
/**
4
 * @file
5
 * Extend core fields with some helper functions to reduce code complexity within views and ctools plugins.
6
 */
7

    
8

    
9
/**
10
 * Fake an instance of a field.
11
 *
12
 * @param $field_name
13
 *   The unique name for this field no matter what entity/bundle it may be used on.
14
 * @param $view_mode
15
 *   We're building a new view mode for this function.  Defaults to ctools, but we expect developers to actually name this something meaningful.
16
 * @param $formatter
17
 *   The formatter key selected from the options provided by field_ui_formatter_options().
18
 * @param $formatter_settings
19
 *   An array of key value pairs.  These will be used as #default_value for the form elements generated by a call to hook_field_formatter_settings_form() for this field type.
20
 *   Typically we'll pass an empty array to begin with and then pass this information back to ourselves on form submit so that we can set the values for later edit sessions.
21
 */
22
function ctools_fields_fake_field_instance($field_name, $view_mode = 'ctools', $formatter, $formatter_settings) {
23
  $field = field_read_field($field_name);
24

    
25
  $field_type = field_info_field_types($field['type']);
26

    
27
  return array(
28
    // Build a fake entity type and bundle.
29
    'field_name' => $field_name,
30
    'entity_type' => 'ctools',
31
    'bundle' => 'ctools',
32

    
33
    // Use the default field settings for settings and widget.
34
    'settings' => field_info_instance_settings($field['type']),
35
    'widget' => array(
36
      'type' => $field_type['default_widget'],
37
      'settings' => array(),
38
    ),
39

    
40
    // Build a dummy display mode.
41
    'display' => array(
42
      $view_mode => array(
43
        'type' => $formatter,
44
        'settings' => $formatter_settings,
45
      ),
46
    ),
47

    
48
    // Set the other fields to their default values.
49
    // @see _field_write_instance().
50
    'required' => FALSE,
51
    'label' => $field_name,
52
    'description' => '',
53
    'deleted' => 0,
54
  );
55
}
56

    
57
/**
58
 * Helper function for calling hook_field_formatter_settings_form() without needing to load an instance of the field.
59
 *
60
 * @param $field
61
 *   A fully loaded field.
62
 * @param $formatter_type
63
 *   The formatter key selected from the options provided by field_ui_formatter_options().
64
 * @param $form
65
 *   The full form from the function that's calling this function.
66
 * @param $form_state
67
 *   The full form_state from the function that's calling this function.
68
 * @param $view_mode
69
 *   We're passing a view mode from this function to the fake instance we're creating.  Defaults to ctools, but we expect developers to actually name this something meaningful.
70
 */
71
function ctools_fields_get_field_formatter_settings_form($field, $formatter_type, &$form, $form_state, $view_mode = 'ctools') {
72
  $conf = $form_state['conf'];
73
  $formatter = field_info_formatter_types($formatter_type);
74
  if (isset($formatter['settings'])) {
75
    $conf['formatter_settings'] += $formatter['settings'];
76
  }
77
  $function = $formatter['module'] . '_field_formatter_settings_form';
78
  if (function_exists($function)) {
79
    $instance = ctools_fields_fake_field_instance($field['field_name'], $view_mode, $formatter_type, $conf['formatter_settings']);
80
    $settings_form = $function($field, $instance, $view_mode, $form, $form_state);
81
    if ($settings_form) {
82
      $form['ctools_field_list']['#value'][] = $field;
83
      $form += $settings_form;
84
    }
85
  }
86

    
87
  if (isset($field['cardinality']) && $field['cardinality'] != 1) {
88
    list($prefix, $suffix) = explode('@count', t('Skip the first @count item(s)'));
89
    $form['delta_offset'] = array(
90
      '#type' => 'textfield',
91
      '#size' => 5,
92
      '#field_prefix' => $prefix,
93
      '#field_suffix' => $suffix,
94
      '#default_value' => isset($conf['delta_offset']) ? $conf['delta_offset'] : 0,
95
    );
96

    
97
    list($prefix, $suffix) = explode('@count', t('Then display at most @count item(s)'));
98
    $form['delta_limit'] = array(
99
      '#type' => 'textfield',
100
      '#size' => 5,
101
      '#field_prefix' => $prefix,
102
      '#field_suffix' => $suffix,
103
      '#description' => t('Enter 0 to display all items.'),
104
      '#default_value' => isset($conf['delta_limit']) ? $conf['delta_limit'] : 0,
105
    );
106

    
107
    $form['delta_reversed'] = array(
108
      '#title' => t('Display in reverse order'),
109
      '#type' => 'checkbox',
110
      '#default_value' => !empty($conf['delta_reversed']),
111
      '#description' => t('(start from last values)'),
112
    );
113
  }
114
}
115

    
116
/**
117
 * Helper function for generating all the formatter information associated with
118
 * any fields.
119
 * Especially useful for determining the fields that will be added to form that
120
 * executes hook_field_formatter_settings_form().
121
 *
122
 * @param $fields
123
 *   An array of fully loaded fields.
124
 */
125
function ctools_fields_get_field_formatter_info($fields) {
126
  $info = array();
127
  $field_info = module_invoke_all('field_formatter_info');
128
  foreach ($fields as $field) {
129
    foreach ($field_info as $format_name => $formatter_info) {
130
      if (in_array($field['type'], $formatter_info['field types'])) {
131
        $info += array($format_name => $formatter_info);
132
      }
133
    }
134
  }
135
  drupal_alter('field_formatter_info', $info);
136
  return $info;
137
}
138

    
139
/**
140
 * Returns the label of a certain field.
141
 *
142
 * Cribbed from Views.
143
 */
144
function ctools_field_label($field_name) {
145
  $label_counter = array();
146
  // Count the amount of instances per label per field.
147
  $instances = field_info_instances();
148
  foreach ($instances as $entity_type) {
149
    foreach ($entity_type as $bundle) {
150
      if (isset($bundle[$field_name])) {
151
        $label_counter[$bundle[$field_name]['label']] = isset($label_counter[$bundle[$field_name]['label']]) ? ++$label_counter[$bundle[$field_name]['label']] : 1;
152
      }
153
    }
154
  }
155
  if (empty($label_counter)) {
156
    return $field_name;
157
  }
158
  // Sort the field lables by it most used label and return the most used one.
159
  arsort($label_counter);
160
  $label_counter = array_keys($label_counter);
161
  return $label_counter[0];
162
}
163

    
164
/**
165
 * Replacement for core _field_invoke() to invoke on a single field.
166
 *
167
 * Core only allows invoking field hooks via a private function for all fields
168
 * on an entire entity. However, we very often need to invoke our hooks on
169
 * a single field as we take things apart and only use little bits.
170
 *
171
 * @param $field_name
172
 *   Either a field instance object or the name of the field.
173
 *   If the 'field' key is populated it will be used as the field
174
 *   settings.
175
 * @param $op
176
 *   Possible operations include:
177
 *   - form
178
 *   - validate
179
 *   - presave
180
 *   - insert
181
 *   - update
182
 *   - delete
183
 *   - delete revision
184
 *   - view
185
 *   - prepare translation
186
 * @param $entity_type
187
 *   The type of $entity; e.g. 'node' or 'user'.
188
 * @param $entity
189
 *   The fully formed $entity_type entity.
190
 * @param $a
191
 *   - The $form in the 'form' operation.
192
 *   - The value of $view_mode in the 'view' operation.
193
 *   - Otherwise NULL.
194
 * @param $b
195
 *   - The $form_state in the 'submit' operation.
196
 *   - Otherwise NULL.
197
 * @param $options
198
 *   An associative array of additional options, with the following keys:
199
 *  - 'field_name': The name of the field whose operation should be
200
 *    invoked. By default, the operation is invoked on all the fields
201
 *    in the entity's bundle. NOTE: This option is not compatible with
202
 *    the 'deleted' option; the 'field_id' option should be used
203
 *    instead.
204
 *  - 'field_id': The id of the field whose operation should be
205
 *    invoked. By default, the operation is invoked on all the fields
206
 *    in the entity's' bundles.
207
 *  - 'default': A boolean value, specifying which implementation of
208
 *    the operation should be invoked.
209
 *    - if FALSE (default), the field types implementation of the operation
210
 *      will be invoked (hook_field_[op])
211
 *    - If TRUE, the default field implementation of the field operation
212
 *      will be invoked (field_default_[op])
213
 *    Internal use only. Do not explicitely set to TRUE, but use
214
 *    _field_invoke_default() instead.
215
 *  - 'deleted': If TRUE, the function will operate on deleted fields
216
 *    as well as non-deleted fields. If unset or FALSE, only
217
 *    non-deleted fields are operated on.
218
 *  - 'language': A language code or an array of language codes keyed by field
219
 *    name. It will be used to narrow down to a single value the available
220
 *    languages to act on.
221
 *
222
 * @see _field_invoke()
223
 */
224
function ctools_field_invoke_field($field_name, $op, $entity_type, $entity, &$a = NULL, &$b = NULL, $options = array()) {
225
  if (is_array($field_name)) {
226
    $instance = $field_name;
227
    $field = empty($field_name['field']) ? field_info_field($instance['field_name']) : $field_name['field'];
228
    $field_name = $instance['field_name'];
229
  }
230
  else {
231
    list(, , $bundle) = entity_extract_ids($entity_type, $entity);
232
    $instance = field_info_instance($entity_type, $field_name, $bundle);
233
  }
234

    
235
  if (empty($instance)) {
236
    return;
237
  }
238

    
239
  // Merge default options.
240
  $default_options = array(
241
    'default' => FALSE,
242
    'deleted' => FALSE,
243
    'language' => NULL,
244
  );
245
  $options += $default_options;
246

    
247
  $return = array();
248

    
249
  // Everything from here is unmodified code from _field_invoke() formerly
250
  // inside a foreach loop over the instances.
251
  $function = $options['default'] ? 'field_default_' . $op : $field['module'] . '_field_' . $op;
252
  if (function_exists($function)) {
253
    // Determine the list of languages to iterate on.
254
    $available_languages = field_available_languages($entity_type, $field);
255
    $languages = _field_language_suggestion($available_languages, $options['language'], $field_name);
256

    
257
    foreach ($languages as $langcode) {
258
      $items = isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : array();
259
      $result = $function($entity_type, $entity, $field, $instance, $langcode, $items, $a, $b);
260
      if (isset($result)) {
261
        // For hooks with array results, we merge results together.
262
        // For hooks with scalar results, we collect results in an array.
263
        if (is_array($result)) {
264
          $return = array_merge($return, $result);
265
        }
266
        else {
267
          $return[] = $result;
268
        }
269
      }
270

    
271
      // Populate $items back in the field values, but avoid replacing missing
272
      // fields with an empty array (those are not equivalent on update).
273
      if ($items !== array() || isset($entity->{$field_name}[$langcode])) {
274
        $entity->{$field_name}[$langcode] = $items;
275
      }
276
    }
277
  }
278

    
279
  return $return;
280
}
281

    
282
/**
283
 * Replacement for core _field_invoke_default() to invoke on a single field.
284
 *
285
 * @see ctools_field_invoke_field()
286
 * @see _field_invoke_default()
287
 */
288
function ctools_field_invoke_field_default($field_name, $op, $entity_type, $entity, &$a = NULL, &$b = NULL, $options = array()) {
289
  $options['default'] = TRUE;
290
  return ctools_field_invoke_field($field_name, $op, $entity_type, $entity, $a, $b, $options);
291
}
292

    
293
/**
294
 * Returns a list of field definitions of a specified type.
295
 *
296
 * @param string $field_type
297
 *   A field type name; e.g. 'text' or 'date'.
298
 *
299
 * @return array
300
 *   An array of field definitions of the specified type, keyed by field name.
301
 */
302
function ctools_fields_get_fields_by_type($field_type) {
303
  $fields = array();
304
  foreach (field_info_fields() as $field_name => $field_info) {
305
    if ($field_info['type'] == $field_type) {
306
      $fields[$field_name] = $field_info;
307
    }
308
  }
309
  return $fields;
310
}
311

    
312
/**
313
 * Derive the foreign keys that a field provides.
314
 *
315
 * @param $field_name
316
 *   The name of the field.
317
 *
318
 * @return
319
 *   An array of foreign keys according to Schema API.
320
 */
321
function ctools_field_foreign_keys($field_name) {
322
  $foreign_keys = &drupal_static(__FUNCTION__, array());
323
  if (!isset($foreign_keys[$field_name])) {
324
    $foreign_keys[$field_name] = array();
325
    $field = field_info_field($field_name);
326

    
327
    if (!empty($field['foreign keys'])) {
328
      $foreign_keys[$field_name] = $field['foreign keys'];
329
    }
330
    else {
331
      // try to fetch foreign keys from schema, as not everything
332
      // stores foreign keys properly in the field info.
333
      $module = $field['module'];
334

    
335
      module_load_install($module);
336
      $schema = module_invoke($module, 'field_schema', $field);
337
      if (!empty($schema['foreign keys'])) {
338
        $foreign_keys[$field_name] = $schema['foreign keys'];
339
      }
340
    }
341
  }
342

    
343
  return $foreign_keys[$field_name];
344
}