Projet

Général

Profil

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

root / drupal7 / sites / all / modules / ctools / includes / fields.inc @ 136a805a

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
      // Allow other modules to alter the formatter settings form.
83
      $context = array(
84
        'module' => $formatter['module'],
85
        'formatter' => $formatter,
86
        'field' => $field,
87
        'instance' => $instance,
88
        'view_mode' => $view_mode,
89
        'form' => $form,
90
        'form_state' => $form_state,
91
      );
92
      drupal_alter('field_formatter_settings_form', $settings_form, $context);
93

    
94
      $settings_form['#tree'] = TRUE;
95
      $form['ctools_field_list']['#value'][] = $field;
96
      $form += $settings_form;
97
    }
98
  }
99

    
100
  if (isset($field['cardinality']) && $field['cardinality'] != 1) {
101
    list($prefix, $suffix) = explode('@count', t('Skip the first @count item(s)'));
102
    $form['delta_offset'] = array(
103
      '#type' => 'textfield',
104
      '#size' => 5,
105
      '#field_prefix' => $prefix,
106
      '#field_suffix' => $suffix,
107
      '#default_value' => isset($conf['delta_offset']) ? $conf['delta_offset'] : 0,
108
    );
109

    
110
    list($prefix, $suffix) = explode('@count', t('Then display at most @count item(s)'));
111
    $form['delta_limit'] = array(
112
      '#type' => 'textfield',
113
      '#size' => 5,
114
      '#field_prefix' => $prefix,
115
      '#field_suffix' => $suffix,
116
      '#description' => t('Enter 0 to display all items.'),
117
      '#default_value' => isset($conf['delta_limit']) ? $conf['delta_limit'] : 0,
118
    );
119

    
120
    $form['delta_reversed'] = array(
121
      '#title' => t('Display in reverse order'),
122
      '#type' => 'checkbox',
123
      '#default_value' => !empty($conf['delta_reversed']),
124
      '#description' => t('(start from last values)'),
125
    );
126
  }
127
}
128

    
129
/**
130
 * Helper function for generating all the formatter information associated with
131
 * any fields.
132
 * Especially useful for determining the fields that will be added to form that
133
 * executes hook_field_formatter_settings_form().
134
 *
135
 * @param $fields
136
 *   An array of fully loaded fields.
137
 */
138
function ctools_fields_get_field_formatter_info($fields) {
139
  $info = array();
140
  $field_info = field_info_formatter_types();
141
  foreach ($fields as $field) {
142
    foreach ($field_info as $format_name => $formatter_info) {
143
      if (in_array($field['type'], $formatter_info['field types'])) {
144
        $info += array($format_name => $formatter_info);
145
      }
146
    }
147
  }
148
  return $info;
149
}
150

    
151
/**
152
 * Returns the label of a certain field.
153
 *
154
 * Cribbed from Views.
155
 */
156
function ctools_field_label($field_name) {
157
  $label_counter = array();
158
  // Count the amount of instances per label per field.
159
  $instances = field_info_instances();
160
  foreach ($instances as $entity_type) {
161
    foreach ($entity_type as $bundle) {
162
      if (isset($bundle[$field_name])) {
163
        $label_counter[$bundle[$field_name]['label']] = isset($label_counter[$bundle[$field_name]['label']]) ? ++$label_counter[$bundle[$field_name]['label']] : 1;
164
      }
165
    }
166
  }
167
  if (empty($label_counter)) {
168
    return $field_name;
169
  }
170
  // Sort the field lables by it most used label and return the most used one.
171
  arsort($label_counter);
172
  $label_counter = array_keys($label_counter);
173
  return $label_counter[0];
174
}
175

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

    
247
  if (empty($instance)) {
248
    return;
249
  }
250

    
251
  // Merge default options.
252
  $default_options = array(
253
    'default' => FALSE,
254
    'deleted' => FALSE,
255
    'language' => NULL,
256
  );
257
  $options += $default_options;
258

    
259
  $return = array();
260

    
261
  // Everything from here is unmodified code from _field_invoke() formerly
262
  // inside a foreach loop over the instances.
263
  $function = $options['default'] ? 'field_default_' . $op : $field['module'] . '_field_' . $op;
264
  if (function_exists($function)) {
265
    // Determine the list of languages to iterate on.
266
    $available_languages = field_available_languages($entity_type, $field);
267
    $languages = _field_language_suggestion($available_languages, $options['language'], $field_name);
268

    
269
    foreach ($languages as $langcode) {
270
      $items = isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : array();
271
      $result = $function($entity_type, $entity, $field, $instance, $langcode, $items, $a, $b);
272
      if (isset($result)) {
273
        // For hooks with array results, we merge results together.
274
        // For hooks with scalar results, we collect results in an array.
275
        if (is_array($result)) {
276
          $return = array_merge($return, $result);
277
        }
278
        else {
279
          $return[] = $result;
280
        }
281
      }
282

    
283
      // Populate $items back in the field values, but avoid replacing missing
284
      // fields with an empty array (those are not equivalent on update).
285
      if ($items !== array() || isset($entity->{$field_name}[$langcode])) {
286
        $entity->{$field_name}[$langcode] = $items;
287
      }
288
    }
289
  }
290

    
291
  return $return;
292
}
293

    
294
/**
295
 * Replacement for core _field_invoke_default() to invoke on a single field.
296
 *
297
 * @see ctools_field_invoke_field()
298
 * @see _field_invoke_default()
299
 */
300
function ctools_field_invoke_field_default($field_name, $op, $entity_type, $entity, &$a = NULL, &$b = NULL, $options = array()) {
301
  $options['default'] = TRUE;
302
  return ctools_field_invoke_field($field_name, $op, $entity_type, $entity, $a, $b, $options);
303
}
304

    
305
/**
306
 * Returns a list of field definitions of a specified type.
307
 *
308
 * @param string $field_type
309
 *   A field type name; e.g. 'text' or 'date'.
310
 *
311
 * @return array
312
 *   An array of field definitions of the specified type, keyed by field name.
313
 */
314
function ctools_fields_get_fields_by_type($field_type) {
315
  $fields = array();
316
  foreach (field_info_fields() as $field_name => $field_info) {
317
    if ($field_info['type'] == $field_type) {
318
      $fields[$field_name] = $field_info;
319
    }
320
  }
321
  return $fields;
322
}
323

    
324
/**
325
 * Derive the foreign keys that a field provides.
326
 *
327
 * @param $field_name
328
 *   The name of the field.
329
 *
330
 * @return
331
 *   An array of foreign keys according to Schema API.
332
 */
333
function ctools_field_foreign_keys($field_name) {
334
  $foreign_keys = &drupal_static(__FUNCTION__, array());
335
  if (!isset($foreign_keys[$field_name])) {
336
    $foreign_keys[$field_name] = array();
337
    $field = field_info_field($field_name);
338

    
339
    if (!empty($field['foreign keys'])) {
340
      $foreign_keys[$field_name] = $field['foreign keys'];
341
    }
342
    else {
343
      // try to fetch foreign keys from schema, as not everything
344
      // stores foreign keys properly in the field info.
345
      $module = $field['module'];
346

    
347
      module_load_install($module);
348
      $schema = module_invoke($module, 'field_schema', $field);
349
      if (!empty($schema['foreign keys'])) {
350
        $foreign_keys[$field_name] = $schema['foreign keys'];
351
      }
352
    }
353
  }
354

    
355
  return $foreign_keys[$field_name];
356
}