diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 323c55edf147bafb54c701949a9d392697cfce7d..2c85fa06b506a696289b29417287abdae745fdda 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -100,6 +100,7 @@ Views 3.x-7.x-dev o by dereine: Test pluggable default argument. o by dereine: Test exposed forms ui. o #721388 by JohnAlbin: Replace clear-block class with clearfix class + o #626704 by DamZ: Build views integration for field.module Views 6.x-3.x-dev o #396380 by merlinofchaos, dereine and dagmar: Initial support for GROUP BY queries!!!!!!!!!!!! diff --git a/includes/handlers.inc b/includes/handlers.inc index e36a0052c180f172d3341ce993e60034f9c9ee46..25b01037fbe987d1309f824adb4f9f6196894d2f 100644 --- a/includes/handlers.inc +++ b/includes/handlers.inc @@ -1377,6 +1377,8 @@ function comment_views_api() { return views_views_api(); } function locale_views_api() { return views_views_api(); } +function field_views_api() { return views_views_api(); } + function filter_views_api() { return views_views_api(); } function node_views_api() { return views_views_api(); } diff --git a/modules/field.views.inc b/modules/field.views.inc new file mode 100644 index 0000000000000000000000000000000000000000..459d74c81d2beb2f996b15e961cc3815dc6c59fd --- /dev/null +++ b/modules/field.views.inc @@ -0,0 +1,259 @@ + $bundles) { + $entity_info = entity_get_info($entity); + + $data[$current_table]['table']['join'][$entity_info['base table']] = array( + 'left_field' => $entity_info['object keys']['id'], + 'field' => 'entity_id', + 'extra' => array(array('field' => 'etid', 'value' => _field_sql_storage_etid($entity), 'numeric' => TRUE)), + ); + + if (!empty($entity_info['object keys']['revision']) && !empty($entity_info['revision table'])) { + $data[$revision_table]['table']['join'][$entity_info['revision table']] = array( + 'left_field' => $entity_info['object keys']['revision'], + 'field' => 'revision_id', + 'extra' => array(array('field' => 'etid', 'value' => _field_sql_storage_etid($entity), 'numeric' => TRUE)), + ); + + $supports_revisions = TRUE; + } + + foreach ($bundles as $bundle) { + $bundles_names[] = t('@entity:@bundle', array('@entity' => $entity, '@bundle' => $bundle)); + } + } + + $tables = array(); + $tables[FIELD_LOAD_CURRENT] = $current_table; + if ($supports_revisions) { + $tables[FIELD_LOAD_REVISION] = $revision_table; + } + + // Add the field handler for this field. + $title_short = $field['field_name']; + foreach ($tables as $type => $table) { + if ($type == FIELD_LOAD_CURRENT) { + $group = t('Fields'); + $column = 'entity_id'; + } + else { + $group = t('Fields (historical data)'); + $column = 'revision_id'; + } + + $data[$table][$column] = array( + 'group' => $group, + 'title' => $title_short, + 'title short' => $title_short, + 'help' => t('Appears in: @bundles', array('@bundles' => implode(', ', $bundles_names))), + ); + $data[$table][$column]['field'] = array( + 'field' => $column, + 'table' => $table, + 'handler' => 'views_handler_field_field', + 'click sortable' => TRUE, + 'field_name' => $field['field_name'], + 'additional fields' => array('etid'), + ); + } + + foreach ($field['columns'] as $column => $attributes) { + $sort = !empty($attributes['sortable']) ? TRUE : FALSE; + + // Identify likely filters and arguments for each column based on field type. + switch ($attributes['type']) { + case 'int': + case 'mediumint': + case 'tinyint': + case 'bigint': + case 'serial': + $filter = 'views_handler_filter_numeric'; + $argument = 'views_handler_argument_numeric'; + break; + case 'numeric': + case 'float': + $filter = 'views_handler_filter_float'; + $argument = 'views_handler_argument_numeric'; + break; + + case 'text': + case 'blob': + // TODO add markup handlers for these types + default: + $filter = 'views_handler_filter_string'; + $argument = 'views_handler_argument_string'; + break; + } + + // Note: we don't have a label available here, because we are at the field + // level, not at the instance level. + if (count($field['columns']) == 1) { + $title = t('@label (!name)', array('@label' => $field['field_name'], '!name' => $field['field_name'])); + $title_short = $field['field_name']; + } + else { + $title = t('@label (!name) - !column', array('@label' => $field['field_name'], '!name' => $field['field_name'], '!column' => $column)); + $title_short = t('@label-truncated - !column', array('@label-truncated' => $field['field_name'], '!column' => $column)); + } + + foreach ($tables as $type => $table) { + $group = $type == FIELD_LOAD_CURRENT ? t('Fields') : t('Fields (historical data)'); + $column_real_name = $field['sql'][$type][$table][$column]; + + // Load all the fields from the table by default. + $additional_fields = array_values($field['sql'][$type][$table]); + + $data[$table][$column_real_name] = array( + 'group' => $group, + 'title' => $title, + 'title short' => $title_short, + 'help' => t('Appears in: @bundles', array('@bundles' => implode(', ', $bundles_names))), + ); + + $data[$table][$column_real_name]['argument'] = array( + 'field' => $column_real_name, + 'table' => $table, + 'handler' => $argument, + 'additional fields' => $additional_fields, + 'content_field_name' => $field['field_name'], + 'empty field name' => t(''), + ); + $data[$table][$column_real_name]['filter'] = array( + 'field' => $column_real_name, + 'table' => $table, + 'handler' => $filter, + 'additional fields' => $additional_fields, + 'content_field_name' => $field['field_name'], + 'allow empty' => TRUE, + ); + if (!empty($sort)) { + $data[$table][$column_real_name]['sort'] = array( + 'field' => $column_real_name, + 'table' => $table, + 'handler' => 'content_handler_sort', + 'additional fields' => $additional_fields, + 'content_field_name' => $field['field_name'], + ); + } + + // Expose additional delta column for multiple value fields. + if ($field['cardinality'] > 1 || $field['cardinality'] == FIELD_CARDINALITY_UNLIMITED) { + $title = t('@label (!name) - delta', array('@label' => $field['field_name'], '!name' => $field['field_name'])); + $title_short = t('!name - delta', array('@name' => $field['field_name'])); + + $data[$table]['delta'] = array( + 'group' => $group, + 'title' => $title, + 'title short' => $title_short, + 'help' => t('Delta - Appears in: @bundles', array('@bundles' => implode(', ', $bundles_names))), + ); + $data[$table]['delta']['argument'] = array( + 'field' => 'delta', + 'table' => $table, + 'handler' => 'views_handler_argument_numeric', + 'additional fields' => $additional_fields, + 'empty field name' => t(''), + ); + $data[$table]['delta']['filter'] = array( + 'field' => 'delta', + 'table' => $table, + 'handler' => 'views_handler_filter_numeric', + 'additional fields' => $additional_fields, + 'allow empty' => TRUE, + ); + $data[$table]['delta']['sort'] = array( + 'field' => 'delta', + 'table' => $table, + 'handler' => 'views_handler_sort', + 'additional fields' => $additional_fields, + ); + } + } + } + + return $data; +} + +/** + * Implements hook_views_handlers(). + */ +function field_views_handlers() { + return array( + 'info' => array( + 'path' => drupal_get_path('module', 'views') . '/modules/field', + ), + 'handlers' => array( + 'views_handler_field_field' => array( + 'parent' => 'views_handler_field', + ), + ), + ); +} + + +/** + * @} + */ diff --git a/modules/field/views_handler_field_field.inc b/modules/field/views_handler_field_field.inc new file mode 100644 index 0000000000000000000000000000000000000000..9a8e37cc853e43ebacbc2ec1e8b85dfd8e6554b7 --- /dev/null +++ b/modules/field/views_handler_field_field.inc @@ -0,0 +1,118 @@ + $formatter) { + foreach ($formatter['field types'] as $formatter_field_type) { + // Check that the field type exists. + if (isset($field_types[$formatter_field_type])) { + $options[$formatter_field_type][$name] = $formatter['label']; + } + } + } + } + + if ($field_type) { + return !empty($options[$field_type]) ? $options[$field_type] : array(); + } + return $options; +} + +/** + * A field that displays fields. + */ +class views_handler_field_field extends views_handler_field { + /** + * Called to add the field to a query. + */ + function query() { + // TODO: we should try to use the data from the join if possible first. + // $join = $this->get_join(); + // That would avoid joining at all the field table. + return parent::query(); + } + + function option_definition() { + $options = parent::option_definition(); + + $field = field_info_field($this->definition['field_name']); + $field_type = field_info_field_types($field['type']); + + $options['type'] = array( + 'default' => $field_type['default_formatter'], + 'translatable' => TRUE, + ); + + return $options; + } + + function options_form(&$form, &$form_state) { + parent::options_form($form, $form_state); + + $field = field_info_field($this->definition['field_name']); + $formatters = _field_view_formatter_options($field['type']); + + $form['type'] = array( + '#type' => 'select', + '#title' => t('Formatter'), + '#options' => $formatters, + '#default_value' => $this->options['type'], + ); + } + + function pre_render(&$values) { + if (!empty($values) && empty($values[0]->_object)) { + + // OMG, this is *ugly*. + $obj_type_map = db_query('SELECT etid, type FROM {field_config_entity_type}')->fetchAllKeyed(); + + // Load the full objects. + $objects_by_type = array(); + foreach ($values as $key => $object) { + // Derive the entity type. For some field types, etid might be empty. + if (isset($object->{$this->aliases['etid']}) && isset($obj_type_map[$object->{$this->aliases['etid']}])) { + $obj_type = $obj_type_map[$object->{$this->aliases['etid']}]; + $entity_id = $object->{$this->field_alias}; + $objects_by_type[$obj_type][$key] = $entity_id; + } + } + + // Load the objects. + foreach ($objects_by_type as $obj_type => $oids) { + $objects = entity_load($obj_type, $oids); + foreach ($oids as $key => $entity_id) { + if (isset($objects[$entity_id])) { + $values[$key]->_obj_type = $obj_type; + $values[$key]->_object = $objects[$entity_id]; + } + } + } + } + } + + function render($values) { + if (isset($values->_obj_type)) { + $field_name = $this->definition['field_name']; + $display = array( + 'type' => $this->options['type'], + 'label' => 'hidden', + ); + + return drupal_render(field_view_field($values->_obj_type, $values->_object, $field_name, $display)); + } + else { + return ''; + } + } +} + diff --git a/views.info b/views.info index 73880475330b7c239348faac318b0e41ac241739..3a954bde9ad37e230364e7dc5e67d8a86f17a436 100644 --- a/views.info +++ b/views.info @@ -88,6 +88,8 @@ files[] = modules/comment/views_handler_sort_ncs_last_comment_name.inc files[] = modules/comment/views_handler_sort_ncs_last_updated.inc files[] = modules/comment/views_plugin_row_comment_rss.inc files[] = modules/comment/views_plugin_row_comment_view.inc +files[] = modules/field.views.inc +files[] = modules/field/views_handler_field_field.inc files[] = modules/locale.views.inc files[] = modules/locale/views_handler_argument_locale_group.inc files[] = modules/locale/views_handler_argument_locale_language.inc