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 @ 6e3ce7c2

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
 * Fake an instance of a field.
10
 *
11
 * @param $field_name
12
 *   The unique name for this field no matter what entity/bundle it may be used on.
13
 * @param $view_mode
14
 *   We're building a new view mode for this function.  Defaults to ctools, but we expect developers to actually name this something meaningful.
15
 * @param $formatter
16
 *   The formatter key selected from the options provided by field_ui_formatter_options().
17
 * @param $formatter_settings
18
 *   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.
19
 *   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.
20
 */
21
function ctools_fields_fake_field_instance($field_name, $view_mode = 'ctools', $formatter, $formatter_settings) {
22
  $field = field_read_field($field_name);
23

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

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

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

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

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

    
56
/**
57
 * Helper function for calling hook_field_formatter_settings_form() without needing to load an instance of the field.
58
 *
59
 * @param $field
60
 *   A fully loaded field.
61
 * @param $formatter_type
62
 *   The formatter key selected from the options provided by field_ui_formatter_options().
63
 * @param $form
64
 *   The full form from the function that's calling this function.
65
 * @param $form_state
66
 *   The full form_state from the function that's calling this function.
67
 * @param $view_mode
68
 *   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.
69
 */
70
function ctools_fields_get_field_formatter_settings_form($field, $formatter_type, &$form, $form_state, $view_mode = 'ctools') {
71
  $conf = $form_state['conf'];
72
  $formatter = field_info_formatter_types($formatter_type);
73
  if (isset($formatter['settings'])) {
74
    $conf['formatter_settings'] += $formatter['settings'];
75
  }
76
  $function = $formatter['module'] . '_field_formatter_settings_form';
77

    
78
  $instance = ctools_fields_fake_field_instance($field['field_name'], $view_mode, $formatter_type, $conf['formatter_settings']);
79
  if (function_exists($function)) {
80
    $settings_form = $function($field, $instance, $view_mode, $form, $form_state);
81
  }
82
  if (empty($settings_form)) {
83
    $settings_form = array();
84
  }
85

    
86
  // Allow other modules to alter the formatter settings form.
87
  $context = array(
88
    'module' => $formatter['module'],
89
    'formatter' => $formatter,
90
    'field' => $field,
91
    'instance' => $instance,
92
    'view_mode' => $view_mode,
93
    'form' => $form,
94
    'form_state' => $form_state,
95
  );
96
  drupal_alter('field_formatter_settings_form', $settings_form, $context);
97

    
98
  $settings_form['#tree'] = TRUE;
99
  $form['ctools_field_list']['#value'][] = $field;
100
  $form += $settings_form;
101

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

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

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

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

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

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

    
256
  // Merge default options.
257
  $default_options = array(
258
    'default' => FALSE,
259
    'deleted' => FALSE,
260
    'language' => NULL,
261
  );
262
  $options += $default_options;
263

    
264
  $return = array();
265

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

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

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

    
296
  return $return;
297
}
298

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

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

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

    
344
    if (!empty($field['foreign keys'])) {
345
      $foreign_keys[$field_name] = $field['foreign keys'];
346
    }
347
    else {
348
      // Try to fetch foreign keys from schema, as not everything
349
      // stores foreign keys properly in the field info.
350
      $module = $field['module'];
351

    
352
      module_load_install($module);
353
      $schema = module_invoke($module, 'field_schema', $field);
354
      if (!empty($schema['foreign keys'])) {
355
        $foreign_keys[$field_name] = $schema['foreign keys'];
356
      }
357
    }
358
  }
359

    
360
  return $foreign_keys[$field_name];
361
}