Projet

Général

Profil

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

root / drupal7 / sites / all / modules / ctools / includes / fields.inc @ 7e72b748

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
    $field = empty($field_name['field']) ? field_info_field($instance['field_name']) : $field_name['field'];
242
    $field_name = $instance['field_name'];
243
  }
244
  else {
245
    list(, , $bundle) = entity_extract_ids($entity_type, $entity);
246
    $instance = field_info_instance($entity_type, $field_name, $bundle);
247
  }
248

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

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

    
261
  $return = array();
262

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

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

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

    
293
  return $return;
294
}
295

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

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

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

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

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

    
357
  return $foreign_keys[$field_name];
358
}