Index: modules/nodereference/nodereference.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/cck/modules/nodereference/Attic/nodereference.module,v retrieving revision 1.138.2.59 diff -u -p -r1.138.2.59 nodereference.module --- modules/nodereference/nodereference.module 19 Jul 2009 13:03:56 -0000 1.138.2.59 +++ modules/nodereference/nodereference.module 19 Aug 2009 00:33:45 -0000 @@ -52,6 +52,16 @@ function nodereference_theme() { } /** + * Implementation of hook_views_api(). + */ +function nodereference_views_api() { + return array( + 'api' => 2, + 'path' => drupal_get_path('module', 'nodereference') . '/views', + ); +} + +/** * Implementaion of hook_ctools_plugin_directory(). */ function nodereference_ctools_plugin_directory($module, $plugin) { @@ -173,6 +183,31 @@ function nodereference_field_settings($o 'label' => t($field['widget']['label']), 'content_field_name' => $field['field_name'], ); + + // Add a reverse relationship to get information about referring items. + $field_types = _content_field_types(); + $types = array(); + foreach (content_types() as $type) { + if (isset($type['fields'][$field['field_name']])) { + $types[] = $type['name']; + } + } + $label_truncated = truncate_utf8(t($field['widget']['label']), 10, TRUE); + $data[$table_alias]['vid'] = array( + 'group' => t('Content'), + 'title' => t('@label (!name) - reverse reference', array('@label' => t($field['widget']['label']), '!name' => $field['field_name'])), + 'title short' => t('@label-truncated reverse reference', array('@label-truncated' => $label_truncated)), + 'help' => t($field_types[$field['type']]['label']) .' ('. t('reverse reference') .') - '. t('Appears in: @types', array('@types' => implode(', ', $types))), + 'relationship' => array( + 'base' => 'node', + 'base field' => 'vid', + 'left_field' => 'nid', + 'field' => $db_info['columns']['nid']['column'], + 'handler' => 'nodereference_handler_relationship_reverse', + 'label' => t('@label reverse reference', array('@label' => t($field['widget']['label']))), + 'content_field_name' => $field['field_name'], + ), + ); return $data; } } Index: modules/nodereference/views/nodereference.views.inc =================================================================== RCS file: modules/nodereference/views/nodereference.views.inc diff -N modules/nodereference/views/nodereference.views.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/nodereference/views/nodereference.views.inc 17 Aug 2009 02:10:01 -0000 @@ -0,0 +1,23 @@ + array( + 'path' => drupal_get_path('module', 'nodereference') . '/views/handlers', + ), + 'handlers' => array( + 'nodereference_handler_relationship_reverse' => array( + 'parent' => 'views_handler_relationship', + ), + ), + ); +} Index: modules/nodereference/views/handlers/nodereference_handler_relationship_reverse.inc =================================================================== RCS file: modules/nodereference/views/handlers/nodereference_handler_relationship_reverse.inc diff -N modules/nodereference/views/handlers/nodereference_handler_relationship_reverse.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/nodereference/views/handlers/nodereference_handler_relationship_reverse.inc 19 Aug 2009 00:26:20 -0000 @@ -0,0 +1,187 @@ +content_field = content_fields($this->definition['content_field_name']); + } + + function option_definition() { + $options = parent::option_definition(); + $options['delta'] = array('default' => -1); + + return $options; + } + + /** + * Add a delta selector for multiple fields. + */ + function options_form(&$form, &$form_state) { + $field = $this->content_field; + parent::options_form($form, $form_state); + + // Only add the form gadget if the field is multiple. + if ($field['multiple']) { + $max_delta = $field['multiple']; + // 1 means unlimited. + if ($max_delta == 1) { + $max_delta = 10; + } + + $options = array('-1' => t('All')); + for ($i = 0; $i < $max_delta; $i++) { + $options[$i] = $i + 1; + } + $form['delta'] = array( + '#type' => 'select', + '#options' => $options, + '#default_value' => $this->options['delta'], + '#title' => t('Delta'), + '#description' => t('The delta allows you to select which item in a multiple value field to key the relationship off of. Select "1" to use the first item, "2" for the second item, and so on. If you select "All", each item in the field will create a new row, which may appear to cause duplicates.'), + ); + } + } + + function ensure_my_table() { + if (!isset($this->table_alias)) { + if (!method_exists($this->query, 'ensure_table')) { vpr_trace(); exit; } + + // Since nested joins are not directly supported by Views, we are going + // to do here part of the job performed by views_query::ensure_table(). + + if (empty($this->relationship)) { + $this->relationship = $this->query->base_table; + } + + if ($this->relationship == $this->query->base_table && !empty($this->query->tables[$this->relationship][$this->table])) { + $this->table_alias = $this->query->tables[$relationship][$this->table]['alias']; + } + elseif (!array_key_exists($this->relationship, $this->query->relationships)) { + $this->table_alias = FALSE; + } + elseif ($this->table == $this->query->relationships[$this->relationship]['base']) { + $this->table_alias = $this->relationship; + } + else { + // Build the main join based on the views data cache. + $main_join = $this->query->get_join_data($this->table, $this->query->relationships[$this->relationship]['base']); + + // We want to alter the join so that it uses the field column instead + // of the vid. + $main_join_definition = $main_join->definition; + $main_join_definition['left_table'] = $this->relationship; + $main_join_definition['left_field'] = $this->definition['left_field']; + $main_join_definition['field'] = $this->definition['field']; + if (!empty($this->options['required'])) { + $main_join_definition['type'] = 'INNER'; + } + + $delta = isset($this->options['delta']) ? $this->options['delta'] : -1; + if ($delta != -1) { + if (!isset($main_join_definition['extra'])) { + $main_join_definition['extra'] = array(); + } + $main_join_definition['extra'][] = array( + 'field' => 'delta', + 'value' => $delta, + 'numeric' => TRUE, + ); + } + + // Build a new join object with our new definition. + $main_join = new nodereference_nested_join(); + $main_join->definition = $main_join_definition; + $main_join->construct(); + $main_join->adjusted = TRUE; + $this->table_alias = $this->query->ensure_table($this->table, $this->relationship, $main_join); + + // Let's build the nested join. + $nested_join_definition = $this->definition; + $nested_join_definition['table'] = $this->definition['base']; + $nested_join_definition['left_field'] = $nested_join_definition['field'] = $nested_join_definition['base field']; + $nested_join_definition['left_table'] = $this->table_alias; + $nested_join_definition['type'] = 'INNER'; + + $nested_join = new nodereference_nested_join(); + $nested_join->definition = $nested_join_definition; + $nested_join->construct(); + $nested_join->adjusted = TRUE; + $nested_alias = $nested_join_definition['table'] .'_'. $this->table; + + $this->alias = $this->query->add_relationship($nested_alias, $nested_join, $this->definition['base'], $this->relationship); + + $main_join->_set_nested_join($nested_join, $this->alias); + } + } + return $this->table_alias; + } + + function query() { + $this->ensure_my_table(); + } +} + +class nodereference_nested_join extends views_join { + var $nested_join; + var $nested_alias; + + function _set_nested_join($nested_join, $nested_alias) { + $this->nested_join = $nested_join; + $this->nested_alias = $nested_alias; + } + + function join($table, &$query, $build_main_join = FALSE) { + if (!isset($this->nested_join)) { + if ($build_main_join) { + return parent::join($table, $query); + } + return ''; + } + $output = parent::join($table, $query); + $nested_join = $this->nested_join->join($query->table_queue[$this->nested_alias], $query, TRUE); + $output = preg_replace('`JOIN ({[_a-z0-9]+} [_a-z0-9]+) ON`', "JOIN (\n\\1\n{$nested_join}\n) ON", $output); + return $output; + } +}