danielebarchiesi@0: $field_name, danielebarchiesi@0: 'entity_type' => 'ctools', danielebarchiesi@0: 'bundle' => 'ctools', danielebarchiesi@0: danielebarchiesi@0: // Use the default field settings for settings and widget. danielebarchiesi@0: 'settings' => field_info_instance_settings($field['type']), danielebarchiesi@0: 'widget' => array( danielebarchiesi@0: 'type' => $field_type['default_widget'], danielebarchiesi@0: 'settings' => array(), danielebarchiesi@0: ), danielebarchiesi@0: danielebarchiesi@0: // Build a dummy display mode. danielebarchiesi@0: 'display' => array( danielebarchiesi@0: $view_mode => array( danielebarchiesi@0: 'type' => $formatter, danielebarchiesi@0: 'settings' => $formatter_settings, danielebarchiesi@0: ), danielebarchiesi@0: ), danielebarchiesi@0: danielebarchiesi@0: // Set the other fields to their default values. danielebarchiesi@0: // @see _field_write_instance(). danielebarchiesi@0: 'required' => FALSE, danielebarchiesi@0: 'label' => $field_name, danielebarchiesi@0: 'description' => '', danielebarchiesi@0: 'deleted' => 0, danielebarchiesi@0: ); danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: /** danielebarchiesi@0: * Helper function for calling hook_field_formatter_settings_form() without needing to load an instance of the field. danielebarchiesi@0: * danielebarchiesi@0: * @param $field danielebarchiesi@0: * A fully loaded field. danielebarchiesi@0: * @param $formatter_type danielebarchiesi@0: * The formatter key selected from the options provided by field_ui_formatter_options(). danielebarchiesi@0: * @param $form danielebarchiesi@0: * The full form from the function that's calling this function. danielebarchiesi@0: * @param $form_state danielebarchiesi@0: * The full form_state from the function that's calling this function. danielebarchiesi@0: * @param $view_mode danielebarchiesi@0: * 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: */ danielebarchiesi@0: function ctools_fields_get_field_formatter_settings_form($field, $formatter_type, &$form, $form_state, $view_mode = 'ctools') { danielebarchiesi@0: $conf = $form_state['conf']; danielebarchiesi@0: $formatter = field_info_formatter_types($formatter_type); danielebarchiesi@0: if (isset($formatter['settings'])) { danielebarchiesi@0: $conf['formatter_settings'] += $formatter['settings']; danielebarchiesi@0: } danielebarchiesi@0: $function = $formatter['module'] . '_field_formatter_settings_form'; danielebarchiesi@0: if (function_exists($function)) { danielebarchiesi@0: $instance = ctools_fields_fake_field_instance($field['field_name'], $view_mode, $formatter_type, $conf['formatter_settings']); danielebarchiesi@0: $settings_form = $function($field, $instance, $view_mode, $form, $form_state); danielebarchiesi@0: if ($settings_form) { danielebarchiesi@0: $form['ctools_field_list']['#value'][] = $field; danielebarchiesi@0: $form += $settings_form; danielebarchiesi@0: } danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: if (isset($field['cardinality']) && $field['cardinality'] != 1) { danielebarchiesi@0: list($prefix, $suffix) = explode('@count', t('Skip the first @count item(s)')); danielebarchiesi@0: $form['delta_offset'] = array( danielebarchiesi@0: '#type' => 'textfield', danielebarchiesi@0: '#size' => 5, danielebarchiesi@0: '#field_prefix' => $prefix, danielebarchiesi@0: '#field_suffix' => $suffix, danielebarchiesi@0: '#default_value' => isset($conf['delta_offset']) ? $conf['delta_offset'] : 0, danielebarchiesi@0: ); danielebarchiesi@0: danielebarchiesi@0: list($prefix, $suffix) = explode('@count', t('Then display at most @count item(s)')); danielebarchiesi@0: $form['delta_limit'] = array( danielebarchiesi@0: '#type' => 'textfield', danielebarchiesi@0: '#size' => 5, danielebarchiesi@0: '#field_prefix' => $prefix, danielebarchiesi@0: '#field_suffix' => $suffix, danielebarchiesi@0: '#description' => t('Enter 0 to display all items.'), danielebarchiesi@0: '#default_value' => isset($conf['delta_limit']) ? $conf['delta_limit'] : 0, danielebarchiesi@0: ); danielebarchiesi@0: danielebarchiesi@0: $form['delta_reversed'] = array( danielebarchiesi@0: '#title' => t('Display in reverse order'), danielebarchiesi@0: '#type' => 'checkbox', danielebarchiesi@0: '#default_value' => !empty($conf['delta_reversed']), danielebarchiesi@0: '#description' => t('(start from last values)'), danielebarchiesi@0: ); danielebarchiesi@0: } danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: /** danielebarchiesi@0: * Helper function for generating all the formatter information associated with danielebarchiesi@0: * any fields. danielebarchiesi@0: * Especially useful for determining the fields that will be added to form that danielebarchiesi@0: * executes hook_field_formatter_settings_form(). danielebarchiesi@0: * danielebarchiesi@0: * @param $fields danielebarchiesi@0: * An array of fully loaded fields. danielebarchiesi@0: */ danielebarchiesi@0: function ctools_fields_get_field_formatter_info($fields) { danielebarchiesi@0: $info = array(); danielebarchiesi@0: $field_info = module_invoke_all('field_formatter_info'); danielebarchiesi@0: foreach ($fields as $field) { danielebarchiesi@0: foreach ($field_info as $format_name => $formatter_info) { danielebarchiesi@0: if (in_array($field['type'], $formatter_info['field types'])) { danielebarchiesi@0: $info += array($format_name => $formatter_info); danielebarchiesi@0: } danielebarchiesi@0: } danielebarchiesi@0: } danielebarchiesi@0: drupal_alter('field_formatter_info', $info); danielebarchiesi@0: return $info; danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: /** danielebarchiesi@0: * Returns the label of a certain field. danielebarchiesi@0: * danielebarchiesi@0: * Cribbed from Views. danielebarchiesi@0: */ danielebarchiesi@0: function ctools_field_label($field_name) { danielebarchiesi@0: $label_counter = array(); danielebarchiesi@0: // Count the amount of instances per label per field. danielebarchiesi@0: $instances = field_info_instances(); danielebarchiesi@0: foreach ($instances as $entity_type) { danielebarchiesi@0: foreach ($entity_type as $bundle) { danielebarchiesi@0: if (isset($bundle[$field_name])) { danielebarchiesi@0: $label_counter[$bundle[$field_name]['label']] = isset($label_counter[$bundle[$field_name]['label']]) ? ++$label_counter[$bundle[$field_name]['label']] : 1; danielebarchiesi@0: } danielebarchiesi@0: } danielebarchiesi@0: } danielebarchiesi@0: if (empty($label_counter)) { danielebarchiesi@0: return $field_name; danielebarchiesi@0: } danielebarchiesi@0: // Sort the field lables by it most used label and return the most used one. danielebarchiesi@0: arsort($label_counter); danielebarchiesi@0: $label_counter = array_keys($label_counter); danielebarchiesi@0: return $label_counter[0]; danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: /** danielebarchiesi@0: * Replacement for core _field_invoke() to invoke on a single field. danielebarchiesi@0: * danielebarchiesi@0: * Core only allows invoking field hooks via a private function for all fields danielebarchiesi@0: * on an entire entity. However, we very often need to invoke our hooks on danielebarchiesi@0: * a single field as we take things apart and only use little bits. danielebarchiesi@0: * danielebarchiesi@0: * @param $field_name danielebarchiesi@0: * Either a field instance object or the name of the field. danielebarchiesi@0: * If the 'field' key is populated it will be used as the field danielebarchiesi@0: * settings. danielebarchiesi@0: * @param $op danielebarchiesi@0: * Possible operations include: danielebarchiesi@0: * - form danielebarchiesi@0: * - validate danielebarchiesi@0: * - presave danielebarchiesi@0: * - insert danielebarchiesi@0: * - update danielebarchiesi@0: * - delete danielebarchiesi@0: * - delete revision danielebarchiesi@0: * - view danielebarchiesi@0: * - prepare translation danielebarchiesi@0: * @param $entity_type danielebarchiesi@0: * The type of $entity; e.g. 'node' or 'user'. danielebarchiesi@0: * @param $entity danielebarchiesi@0: * The fully formed $entity_type entity. danielebarchiesi@0: * @param $a danielebarchiesi@0: * - The $form in the 'form' operation. danielebarchiesi@0: * - The value of $view_mode in the 'view' operation. danielebarchiesi@0: * - Otherwise NULL. danielebarchiesi@0: * @param $b danielebarchiesi@0: * - The $form_state in the 'submit' operation. danielebarchiesi@0: * - Otherwise NULL. danielebarchiesi@0: * @param $options danielebarchiesi@0: * An associative array of additional options, with the following keys: danielebarchiesi@0: * - 'field_name': The name of the field whose operation should be danielebarchiesi@0: * invoked. By default, the operation is invoked on all the fields danielebarchiesi@0: * in the entity's bundle. NOTE: This option is not compatible with danielebarchiesi@0: * the 'deleted' option; the 'field_id' option should be used danielebarchiesi@0: * instead. danielebarchiesi@0: * - 'field_id': The id of the field whose operation should be danielebarchiesi@0: * invoked. By default, the operation is invoked on all the fields danielebarchiesi@0: * in the entity's' bundles. danielebarchiesi@0: * - 'default': A boolean value, specifying which implementation of danielebarchiesi@0: * the operation should be invoked. danielebarchiesi@0: * - if FALSE (default), the field types implementation of the operation danielebarchiesi@0: * will be invoked (hook_field_[op]) danielebarchiesi@0: * - If TRUE, the default field implementation of the field operation danielebarchiesi@0: * will be invoked (field_default_[op]) danielebarchiesi@0: * Internal use only. Do not explicitely set to TRUE, but use danielebarchiesi@0: * _field_invoke_default() instead. danielebarchiesi@0: * - 'deleted': If TRUE, the function will operate on deleted fields danielebarchiesi@0: * as well as non-deleted fields. If unset or FALSE, only danielebarchiesi@0: * non-deleted fields are operated on. danielebarchiesi@0: * - 'language': A language code or an array of language codes keyed by field danielebarchiesi@0: * name. It will be used to narrow down to a single value the available danielebarchiesi@0: * languages to act on. danielebarchiesi@0: * danielebarchiesi@0: * @see _field_invoke() danielebarchiesi@0: */ danielebarchiesi@0: function ctools_field_invoke_field($field_name, $op, $entity_type, $entity, &$a = NULL, &$b = NULL, $options = array()) { danielebarchiesi@0: if (is_array($field_name)) { danielebarchiesi@0: $instance = $field_name; danielebarchiesi@0: $field = empty($field_name['field']) ? field_info_field($instance['field_name']) : $field_name['field']; danielebarchiesi@0: $field_name = $instance['field_name']; danielebarchiesi@0: } danielebarchiesi@0: else { danielebarchiesi@0: list(, , $bundle) = entity_extract_ids($entity_type, $entity); danielebarchiesi@0: $instance = field_info_instance($entity_type, $field_name, $bundle); danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: if (empty($instance)) { danielebarchiesi@0: return; danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: // Merge default options. danielebarchiesi@0: $default_options = array( danielebarchiesi@0: 'default' => FALSE, danielebarchiesi@0: 'deleted' => FALSE, danielebarchiesi@0: 'language' => NULL, danielebarchiesi@0: ); danielebarchiesi@0: $options += $default_options; danielebarchiesi@0: danielebarchiesi@0: $return = array(); danielebarchiesi@0: danielebarchiesi@0: // Everything from here is unmodified code from _field_invoke() formerly danielebarchiesi@0: // inside a foreach loop over the instances. danielebarchiesi@0: $function = $options['default'] ? 'field_default_' . $op : $field['module'] . '_field_' . $op; danielebarchiesi@0: if (function_exists($function)) { danielebarchiesi@0: // Determine the list of languages to iterate on. danielebarchiesi@0: $available_languages = field_available_languages($entity_type, $field); danielebarchiesi@0: $languages = _field_language_suggestion($available_languages, $options['language'], $field_name); danielebarchiesi@0: danielebarchiesi@0: foreach ($languages as $langcode) { danielebarchiesi@0: $items = isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : array(); danielebarchiesi@0: $result = $function($entity_type, $entity, $field, $instance, $langcode, $items, $a, $b); danielebarchiesi@0: if (isset($result)) { danielebarchiesi@0: // For hooks with array results, we merge results together. danielebarchiesi@0: // For hooks with scalar results, we collect results in an array. danielebarchiesi@0: if (is_array($result)) { danielebarchiesi@0: $return = array_merge($return, $result); danielebarchiesi@0: } danielebarchiesi@0: else { danielebarchiesi@0: $return[] = $result; danielebarchiesi@0: } danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: // Populate $items back in the field values, but avoid replacing missing danielebarchiesi@0: // fields with an empty array (those are not equivalent on update). danielebarchiesi@0: if ($items !== array() || isset($entity->{$field_name}[$langcode])) { danielebarchiesi@0: $entity->{$field_name}[$langcode] = $items; danielebarchiesi@0: } danielebarchiesi@0: } danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: return $return; danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: /** danielebarchiesi@0: * Replacement for core _field_invoke_default() to invoke on a single field. danielebarchiesi@0: * danielebarchiesi@0: * @see ctools_field_invoke_field() danielebarchiesi@0: * @see _field_invoke_default() danielebarchiesi@0: */ danielebarchiesi@0: function ctools_field_invoke_field_default($field_name, $op, $entity_type, $entity, &$a = NULL, &$b = NULL, $options = array()) { danielebarchiesi@0: $options['default'] = TRUE; danielebarchiesi@0: return ctools_field_invoke_field($field_name, $op, $entity_type, $entity, $a, $b, $options); danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: /** danielebarchiesi@0: * Returns a list of field definitions of a specified type. danielebarchiesi@0: * danielebarchiesi@0: * @param string $field_type danielebarchiesi@0: * A field type name; e.g. 'text' or 'date'. danielebarchiesi@0: * danielebarchiesi@0: * @return array danielebarchiesi@0: * An array of field definitions of the specified type, keyed by field name. danielebarchiesi@0: */ danielebarchiesi@0: function ctools_fields_get_fields_by_type($field_type) { danielebarchiesi@0: $fields = array(); danielebarchiesi@0: foreach (field_info_fields() as $field_name => $field_info) { danielebarchiesi@0: if ($field_info['type'] == $field_type) { danielebarchiesi@0: $fields[$field_name] = $field_info; danielebarchiesi@0: } danielebarchiesi@0: } danielebarchiesi@0: return $fields; danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: /** danielebarchiesi@0: * Derive the foreign keys that a field provides. danielebarchiesi@0: * danielebarchiesi@0: * @param $field_name danielebarchiesi@0: * The name of the field. danielebarchiesi@0: * danielebarchiesi@0: * @return danielebarchiesi@0: * An array of foreign keys according to Schema API. danielebarchiesi@0: */ danielebarchiesi@0: function ctools_field_foreign_keys($field_name) { danielebarchiesi@0: $foreign_keys = &drupal_static(__FUNCTION__, array()); danielebarchiesi@0: if (!isset($foreign_keys[$field_name])) { danielebarchiesi@0: $foreign_keys[$field_name] = array(); danielebarchiesi@0: $field = field_info_field($field_name); danielebarchiesi@0: danielebarchiesi@0: if (!empty($field['foreign keys'])) { danielebarchiesi@0: $foreign_keys[$field_name] = $field['foreign keys']; danielebarchiesi@0: } danielebarchiesi@0: else { danielebarchiesi@0: // try to fetch foreign keys from schema, as not everything danielebarchiesi@0: // stores foreign keys properly in the field info. danielebarchiesi@0: $module = $field['module']; danielebarchiesi@0: danielebarchiesi@0: module_load_install($module); danielebarchiesi@0: $schema = module_invoke($module, 'field_schema', $field); danielebarchiesi@0: if (!empty($schema['foreign keys'])) { danielebarchiesi@0: $foreign_keys[$field_name] = $schema['foreign keys']; danielebarchiesi@0: } danielebarchiesi@0: } danielebarchiesi@0: } danielebarchiesi@0: danielebarchiesi@0: return $foreign_keys[$field_name]; danielebarchiesi@0: }