annotate sites/all/modules/ctools/includes/fields.inc @ 0:ff03f76ab3fe

initial version
author danieleb <danielebarchiesi@me.com>
date Wed, 21 Aug 2013 18:51:11 +0100
parents
children
rev   line source
danielebarchiesi@0 1 <?php
danielebarchiesi@0 2
danielebarchiesi@0 3 /**
danielebarchiesi@0 4 * @file
danielebarchiesi@0 5 * Extend core fields with some helper functions to reduce code complexity within views and ctools plugins.
danielebarchiesi@0 6 */
danielebarchiesi@0 7
danielebarchiesi@0 8
danielebarchiesi@0 9 /**
danielebarchiesi@0 10 * Fake an instance of a field.
danielebarchiesi@0 11 *
danielebarchiesi@0 12 * @param $field_name
danielebarchiesi@0 13 * The unique name for this field no matter what entity/bundle it may be used on.
danielebarchiesi@0 14 * @param $view_mode
danielebarchiesi@0 15 * We're building a new view mode for this function. Defaults to ctools, but we expect developers to actually name this something meaningful.
danielebarchiesi@0 16 * @param $formatter
danielebarchiesi@0 17 * The formatter key selected from the options provided by field_ui_formatter_options().
danielebarchiesi@0 18 * @param $formatter_settings
danielebarchiesi@0 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.
danielebarchiesi@0 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.
danielebarchiesi@0 21 */
danielebarchiesi@0 22 function ctools_fields_fake_field_instance($field_name, $view_mode = 'ctools', $formatter, $formatter_settings) {
danielebarchiesi@0 23 $field = field_read_field($field_name);
danielebarchiesi@0 24
danielebarchiesi@0 25 $field_type = field_info_field_types($field['type']);
danielebarchiesi@0 26
danielebarchiesi@0 27 return array(
danielebarchiesi@0 28 // Build a fake entity type and bundle.
danielebarchiesi@0 29 'field_name' => $field_name,
danielebarchiesi@0 30 'entity_type' => 'ctools',
danielebarchiesi@0 31 'bundle' => 'ctools',
danielebarchiesi@0 32
danielebarchiesi@0 33 // Use the default field settings for settings and widget.
danielebarchiesi@0 34 'settings' => field_info_instance_settings($field['type']),
danielebarchiesi@0 35 'widget' => array(
danielebarchiesi@0 36 'type' => $field_type['default_widget'],
danielebarchiesi@0 37 'settings' => array(),
danielebarchiesi@0 38 ),
danielebarchiesi@0 39
danielebarchiesi@0 40 // Build a dummy display mode.
danielebarchiesi@0 41 'display' => array(
danielebarchiesi@0 42 $view_mode => array(
danielebarchiesi@0 43 'type' => $formatter,
danielebarchiesi@0 44 'settings' => $formatter_settings,
danielebarchiesi@0 45 ),
danielebarchiesi@0 46 ),
danielebarchiesi@0 47
danielebarchiesi@0 48 // Set the other fields to their default values.
danielebarchiesi@0 49 // @see _field_write_instance().
danielebarchiesi@0 50 'required' => FALSE,
danielebarchiesi@0 51 'label' => $field_name,
danielebarchiesi@0 52 'description' => '',
danielebarchiesi@0 53 'deleted' => 0,
danielebarchiesi@0 54 );
danielebarchiesi@0 55 }
danielebarchiesi@0 56
danielebarchiesi@0 57 /**
danielebarchiesi@0 58 * Helper function for calling hook_field_formatter_settings_form() without needing to load an instance of the field.
danielebarchiesi@0 59 *
danielebarchiesi@0 60 * @param $field
danielebarchiesi@0 61 * A fully loaded field.
danielebarchiesi@0 62 * @param $formatter_type
danielebarchiesi@0 63 * The formatter key selected from the options provided by field_ui_formatter_options().
danielebarchiesi@0 64 * @param $form
danielebarchiesi@0 65 * The full form from the function that's calling this function.
danielebarchiesi@0 66 * @param $form_state
danielebarchiesi@0 67 * The full form_state from the function that's calling this function.
danielebarchiesi@0 68 * @param $view_mode
danielebarchiesi@0 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.
danielebarchiesi@0 70 */
danielebarchiesi@0 71 function ctools_fields_get_field_formatter_settings_form($field, $formatter_type, &$form, $form_state, $view_mode = 'ctools') {
danielebarchiesi@0 72 $conf = $form_state['conf'];
danielebarchiesi@0 73 $formatter = field_info_formatter_types($formatter_type);
danielebarchiesi@0 74 if (isset($formatter['settings'])) {
danielebarchiesi@0 75 $conf['formatter_settings'] += $formatter['settings'];
danielebarchiesi@0 76 }
danielebarchiesi@0 77 $function = $formatter['module'] . '_field_formatter_settings_form';
danielebarchiesi@0 78 if (function_exists($function)) {
danielebarchiesi@0 79 $instance = ctools_fields_fake_field_instance($field['field_name'], $view_mode, $formatter_type, $conf['formatter_settings']);
danielebarchiesi@0 80 $settings_form = $function($field, $instance, $view_mode, $form, $form_state);
danielebarchiesi@0 81 if ($settings_form) {
danielebarchiesi@0 82 $form['ctools_field_list']['#value'][] = $field;
danielebarchiesi@0 83 $form += $settings_form;
danielebarchiesi@0 84 }
danielebarchiesi@0 85 }
danielebarchiesi@0 86
danielebarchiesi@0 87 if (isset($field['cardinality']) && $field['cardinality'] != 1) {
danielebarchiesi@0 88 list($prefix, $suffix) = explode('@count', t('Skip the first @count item(s)'));
danielebarchiesi@0 89 $form['delta_offset'] = array(
danielebarchiesi@0 90 '#type' => 'textfield',
danielebarchiesi@0 91 '#size' => 5,
danielebarchiesi@0 92 '#field_prefix' => $prefix,
danielebarchiesi@0 93 '#field_suffix' => $suffix,
danielebarchiesi@0 94 '#default_value' => isset($conf['delta_offset']) ? $conf['delta_offset'] : 0,
danielebarchiesi@0 95 );
danielebarchiesi@0 96
danielebarchiesi@0 97 list($prefix, $suffix) = explode('@count', t('Then display at most @count item(s)'));
danielebarchiesi@0 98 $form['delta_limit'] = array(
danielebarchiesi@0 99 '#type' => 'textfield',
danielebarchiesi@0 100 '#size' => 5,
danielebarchiesi@0 101 '#field_prefix' => $prefix,
danielebarchiesi@0 102 '#field_suffix' => $suffix,
danielebarchiesi@0 103 '#description' => t('Enter 0 to display all items.'),
danielebarchiesi@0 104 '#default_value' => isset($conf['delta_limit']) ? $conf['delta_limit'] : 0,
danielebarchiesi@0 105 );
danielebarchiesi@0 106
danielebarchiesi@0 107 $form['delta_reversed'] = array(
danielebarchiesi@0 108 '#title' => t('Display in reverse order'),
danielebarchiesi@0 109 '#type' => 'checkbox',
danielebarchiesi@0 110 '#default_value' => !empty($conf['delta_reversed']),
danielebarchiesi@0 111 '#description' => t('(start from last values)'),
danielebarchiesi@0 112 );
danielebarchiesi@0 113 }
danielebarchiesi@0 114 }
danielebarchiesi@0 115
danielebarchiesi@0 116 /**
danielebarchiesi@0 117 * Helper function for generating all the formatter information associated with
danielebarchiesi@0 118 * any fields.
danielebarchiesi@0 119 * Especially useful for determining the fields that will be added to form that
danielebarchiesi@0 120 * executes hook_field_formatter_settings_form().
danielebarchiesi@0 121 *
danielebarchiesi@0 122 * @param $fields
danielebarchiesi@0 123 * An array of fully loaded fields.
danielebarchiesi@0 124 */
danielebarchiesi@0 125 function ctools_fields_get_field_formatter_info($fields) {
danielebarchiesi@0 126 $info = array();
danielebarchiesi@0 127 $field_info = module_invoke_all('field_formatter_info');
danielebarchiesi@0 128 foreach ($fields as $field) {
danielebarchiesi@0 129 foreach ($field_info as $format_name => $formatter_info) {
danielebarchiesi@0 130 if (in_array($field['type'], $formatter_info['field types'])) {
danielebarchiesi@0 131 $info += array($format_name => $formatter_info);
danielebarchiesi@0 132 }
danielebarchiesi@0 133 }
danielebarchiesi@0 134 }
danielebarchiesi@0 135 drupal_alter('field_formatter_info', $info);
danielebarchiesi@0 136 return $info;
danielebarchiesi@0 137 }
danielebarchiesi@0 138
danielebarchiesi@0 139 /**
danielebarchiesi@0 140 * Returns the label of a certain field.
danielebarchiesi@0 141 *
danielebarchiesi@0 142 * Cribbed from Views.
danielebarchiesi@0 143 */
danielebarchiesi@0 144 function ctools_field_label($field_name) {
danielebarchiesi@0 145 $label_counter = array();
danielebarchiesi@0 146 // Count the amount of instances per label per field.
danielebarchiesi@0 147 $instances = field_info_instances();
danielebarchiesi@0 148 foreach ($instances as $entity_type) {
danielebarchiesi@0 149 foreach ($entity_type as $bundle) {
danielebarchiesi@0 150 if (isset($bundle[$field_name])) {
danielebarchiesi@0 151 $label_counter[$bundle[$field_name]['label']] = isset($label_counter[$bundle[$field_name]['label']]) ? ++$label_counter[$bundle[$field_name]['label']] : 1;
danielebarchiesi@0 152 }
danielebarchiesi@0 153 }
danielebarchiesi@0 154 }
danielebarchiesi@0 155 if (empty($label_counter)) {
danielebarchiesi@0 156 return $field_name;
danielebarchiesi@0 157 }
danielebarchiesi@0 158 // Sort the field lables by it most used label and return the most used one.
danielebarchiesi@0 159 arsort($label_counter);
danielebarchiesi@0 160 $label_counter = array_keys($label_counter);
danielebarchiesi@0 161 return $label_counter[0];
danielebarchiesi@0 162 }
danielebarchiesi@0 163
danielebarchiesi@0 164 /**
danielebarchiesi@0 165 * Replacement for core _field_invoke() to invoke on a single field.
danielebarchiesi@0 166 *
danielebarchiesi@0 167 * Core only allows invoking field hooks via a private function for all fields
danielebarchiesi@0 168 * on an entire entity. However, we very often need to invoke our hooks on
danielebarchiesi@0 169 * a single field as we take things apart and only use little bits.
danielebarchiesi@0 170 *
danielebarchiesi@0 171 * @param $field_name
danielebarchiesi@0 172 * Either a field instance object or the name of the field.
danielebarchiesi@0 173 * If the 'field' key is populated it will be used as the field
danielebarchiesi@0 174 * settings.
danielebarchiesi@0 175 * @param $op
danielebarchiesi@0 176 * Possible operations include:
danielebarchiesi@0 177 * - form
danielebarchiesi@0 178 * - validate
danielebarchiesi@0 179 * - presave
danielebarchiesi@0 180 * - insert
danielebarchiesi@0 181 * - update
danielebarchiesi@0 182 * - delete
danielebarchiesi@0 183 * - delete revision
danielebarchiesi@0 184 * - view
danielebarchiesi@0 185 * - prepare translation
danielebarchiesi@0 186 * @param $entity_type
danielebarchiesi@0 187 * The type of $entity; e.g. 'node' or 'user'.
danielebarchiesi@0 188 * @param $entity
danielebarchiesi@0 189 * The fully formed $entity_type entity.
danielebarchiesi@0 190 * @param $a
danielebarchiesi@0 191 * - The $form in the 'form' operation.
danielebarchiesi@0 192 * - The value of $view_mode in the 'view' operation.
danielebarchiesi@0 193 * - Otherwise NULL.
danielebarchiesi@0 194 * @param $b
danielebarchiesi@0 195 * - The $form_state in the 'submit' operation.
danielebarchiesi@0 196 * - Otherwise NULL.
danielebarchiesi@0 197 * @param $options
danielebarchiesi@0 198 * An associative array of additional options, with the following keys:
danielebarchiesi@0 199 * - 'field_name': The name of the field whose operation should be
danielebarchiesi@0 200 * invoked. By default, the operation is invoked on all the fields
danielebarchiesi@0 201 * in the entity's bundle. NOTE: This option is not compatible with
danielebarchiesi@0 202 * the 'deleted' option; the 'field_id' option should be used
danielebarchiesi@0 203 * instead.
danielebarchiesi@0 204 * - 'field_id': The id of the field whose operation should be
danielebarchiesi@0 205 * invoked. By default, the operation is invoked on all the fields
danielebarchiesi@0 206 * in the entity's' bundles.
danielebarchiesi@0 207 * - 'default': A boolean value, specifying which implementation of
danielebarchiesi@0 208 * the operation should be invoked.
danielebarchiesi@0 209 * - if FALSE (default), the field types implementation of the operation
danielebarchiesi@0 210 * will be invoked (hook_field_[op])
danielebarchiesi@0 211 * - If TRUE, the default field implementation of the field operation
danielebarchiesi@0 212 * will be invoked (field_default_[op])
danielebarchiesi@0 213 * Internal use only. Do not explicitely set to TRUE, but use
danielebarchiesi@0 214 * _field_invoke_default() instead.
danielebarchiesi@0 215 * - 'deleted': If TRUE, the function will operate on deleted fields
danielebarchiesi@0 216 * as well as non-deleted fields. If unset or FALSE, only
danielebarchiesi@0 217 * non-deleted fields are operated on.
danielebarchiesi@0 218 * - 'language': A language code or an array of language codes keyed by field
danielebarchiesi@0 219 * name. It will be used to narrow down to a single value the available
danielebarchiesi@0 220 * languages to act on.
danielebarchiesi@0 221 *
danielebarchiesi@0 222 * @see _field_invoke()
danielebarchiesi@0 223 */
danielebarchiesi@0 224 function ctools_field_invoke_field($field_name, $op, $entity_type, $entity, &$a = NULL, &$b = NULL, $options = array()) {
danielebarchiesi@0 225 if (is_array($field_name)) {
danielebarchiesi@0 226 $instance = $field_name;
danielebarchiesi@0 227 $field = empty($field_name['field']) ? field_info_field($instance['field_name']) : $field_name['field'];
danielebarchiesi@0 228 $field_name = $instance['field_name'];
danielebarchiesi@0 229 }
danielebarchiesi@0 230 else {
danielebarchiesi@0 231 list(, , $bundle) = entity_extract_ids($entity_type, $entity);
danielebarchiesi@0 232 $instance = field_info_instance($entity_type, $field_name, $bundle);
danielebarchiesi@0 233 }
danielebarchiesi@0 234
danielebarchiesi@0 235 if (empty($instance)) {
danielebarchiesi@0 236 return;
danielebarchiesi@0 237 }
danielebarchiesi@0 238
danielebarchiesi@0 239 // Merge default options.
danielebarchiesi@0 240 $default_options = array(
danielebarchiesi@0 241 'default' => FALSE,
danielebarchiesi@0 242 'deleted' => FALSE,
danielebarchiesi@0 243 'language' => NULL,
danielebarchiesi@0 244 );
danielebarchiesi@0 245 $options += $default_options;
danielebarchiesi@0 246
danielebarchiesi@0 247 $return = array();
danielebarchiesi@0 248
danielebarchiesi@0 249 // Everything from here is unmodified code from _field_invoke() formerly
danielebarchiesi@0 250 // inside a foreach loop over the instances.
danielebarchiesi@0 251 $function = $options['default'] ? 'field_default_' . $op : $field['module'] . '_field_' . $op;
danielebarchiesi@0 252 if (function_exists($function)) {
danielebarchiesi@0 253 // Determine the list of languages to iterate on.
danielebarchiesi@0 254 $available_languages = field_available_languages($entity_type, $field);
danielebarchiesi@0 255 $languages = _field_language_suggestion($available_languages, $options['language'], $field_name);
danielebarchiesi@0 256
danielebarchiesi@0 257 foreach ($languages as $langcode) {
danielebarchiesi@0 258 $items = isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : array();
danielebarchiesi@0 259 $result = $function($entity_type, $entity, $field, $instance, $langcode, $items, $a, $b);
danielebarchiesi@0 260 if (isset($result)) {
danielebarchiesi@0 261 // For hooks with array results, we merge results together.
danielebarchiesi@0 262 // For hooks with scalar results, we collect results in an array.
danielebarchiesi@0 263 if (is_array($result)) {
danielebarchiesi@0 264 $return = array_merge($return, $result);
danielebarchiesi@0 265 }
danielebarchiesi@0 266 else {
danielebarchiesi@0 267 $return[] = $result;
danielebarchiesi@0 268 }
danielebarchiesi@0 269 }
danielebarchiesi@0 270
danielebarchiesi@0 271 // Populate $items back in the field values, but avoid replacing missing
danielebarchiesi@0 272 // fields with an empty array (those are not equivalent on update).
danielebarchiesi@0 273 if ($items !== array() || isset($entity->{$field_name}[$langcode])) {
danielebarchiesi@0 274 $entity->{$field_name}[$langcode] = $items;
danielebarchiesi@0 275 }
danielebarchiesi@0 276 }
danielebarchiesi@0 277 }
danielebarchiesi@0 278
danielebarchiesi@0 279 return $return;
danielebarchiesi@0 280 }
danielebarchiesi@0 281
danielebarchiesi@0 282 /**
danielebarchiesi@0 283 * Replacement for core _field_invoke_default() to invoke on a single field.
danielebarchiesi@0 284 *
danielebarchiesi@0 285 * @see ctools_field_invoke_field()
danielebarchiesi@0 286 * @see _field_invoke_default()
danielebarchiesi@0 287 */
danielebarchiesi@0 288 function ctools_field_invoke_field_default($field_name, $op, $entity_type, $entity, &$a = NULL, &$b = NULL, $options = array()) {
danielebarchiesi@0 289 $options['default'] = TRUE;
danielebarchiesi@0 290 return ctools_field_invoke_field($field_name, $op, $entity_type, $entity, $a, $b, $options);
danielebarchiesi@0 291 }
danielebarchiesi@0 292
danielebarchiesi@0 293 /**
danielebarchiesi@0 294 * Returns a list of field definitions of a specified type.
danielebarchiesi@0 295 *
danielebarchiesi@0 296 * @param string $field_type
danielebarchiesi@0 297 * A field type name; e.g. 'text' or 'date'.
danielebarchiesi@0 298 *
danielebarchiesi@0 299 * @return array
danielebarchiesi@0 300 * An array of field definitions of the specified type, keyed by field name.
danielebarchiesi@0 301 */
danielebarchiesi@0 302 function ctools_fields_get_fields_by_type($field_type) {
danielebarchiesi@0 303 $fields = array();
danielebarchiesi@0 304 foreach (field_info_fields() as $field_name => $field_info) {
danielebarchiesi@0 305 if ($field_info['type'] == $field_type) {
danielebarchiesi@0 306 $fields[$field_name] = $field_info;
danielebarchiesi@0 307 }
danielebarchiesi@0 308 }
danielebarchiesi@0 309 return $fields;
danielebarchiesi@0 310 }
danielebarchiesi@0 311
danielebarchiesi@0 312 /**
danielebarchiesi@0 313 * Derive the foreign keys that a field provides.
danielebarchiesi@0 314 *
danielebarchiesi@0 315 * @param $field_name
danielebarchiesi@0 316 * The name of the field.
danielebarchiesi@0 317 *
danielebarchiesi@0 318 * @return
danielebarchiesi@0 319 * An array of foreign keys according to Schema API.
danielebarchiesi@0 320 */
danielebarchiesi@0 321 function ctools_field_foreign_keys($field_name) {
danielebarchiesi@0 322 $foreign_keys = &drupal_static(__FUNCTION__, array());
danielebarchiesi@0 323 if (!isset($foreign_keys[$field_name])) {
danielebarchiesi@0 324 $foreign_keys[$field_name] = array();
danielebarchiesi@0 325 $field = field_info_field($field_name);
danielebarchiesi@0 326
danielebarchiesi@0 327 if (!empty($field['foreign keys'])) {
danielebarchiesi@0 328 $foreign_keys[$field_name] = $field['foreign keys'];
danielebarchiesi@0 329 }
danielebarchiesi@0 330 else {
danielebarchiesi@0 331 // try to fetch foreign keys from schema, as not everything
danielebarchiesi@0 332 // stores foreign keys properly in the field info.
danielebarchiesi@0 333 $module = $field['module'];
danielebarchiesi@0 334
danielebarchiesi@0 335 module_load_install($module);
danielebarchiesi@0 336 $schema = module_invoke($module, 'field_schema', $field);
danielebarchiesi@0 337 if (!empty($schema['foreign keys'])) {
danielebarchiesi@0 338 $foreign_keys[$field_name] = $schema['foreign keys'];
danielebarchiesi@0 339 }
danielebarchiesi@0 340 }
danielebarchiesi@0 341 }
danielebarchiesi@0 342
danielebarchiesi@0 343 return $foreign_keys[$field_name];
danielebarchiesi@0 344 }