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 @ e4c061ad

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 = module_invoke_all('field_formatter_info');
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
  drupal_alter('field_formatter_info', $info);
149
  return $info;
150
}
151

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

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

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

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

    
260
  $return = array();
261

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

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

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

    
292
  return $return;
293
}
294

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

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

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

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

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

    
356
  return $foreign_keys[$field_name];
357
}