فهرست منبع

Issue #2343599: Multiple relationships between same tables were only available in one direction, now available from both directions.

Lacey Sanderson 10 سال پیش
والد
کامیت
9bcd54fcdf
3فایلهای تغییر یافته به همراه183 افزوده شده و 93 حذف شده
  1. 129 77
      tripal_views/api/tripal_views.api.inc
  2. 21 4
      tripal_views/includes/tripal_views_integration.inc
  3. 33 12
      tripal_views/tripal_views.views.inc

+ 129 - 77
tripal_views/api/tripal_views.api.inc

@@ -150,10 +150,21 @@ function mymodule_admin_landing_page() {
               'filter' => array( ... ),
               ...
             ),
-            'join' => array( //describe a table that joins to this one via this field
-              'table' => 'featureprop', //table to join to
-              'field' => 'feature_id', //field in above table (featureprop)
-              'handler' => 'views_handler_join_chado_aggregator', //handler to use
+            // Describe any joins involving this field.
+            // Note: you can include both foreign keys (feature.type_id => cvterm.cvterm_id)
+            // and referring tables (ie: feature.feature_id <= feature_relationship.subject_id)
+            'joins' => array(
+              'feature_relationship' => array( //table to join to.
+                'subject_id' => array( //field in above table (feature_relationship)
+                  'table' => 'featureprop', //table to join to
+                  'field' => 'feature_id', //field in above table (feature_relationship)
+                  'handler' => 'views_join', //handler to use for joining
+                  'relationship_handler' => 'views_handler_relationship', //handler to use when a relationship is added.
+                  'relationship_only' => FALSE, //whether to join automatically (FALSE) or not (TRUE)
+                ),
+                ...
+              ),
+              ...
             ),
           )
         ),
@@ -591,10 +602,21 @@ function tripal_rebuild_views_integrations($delete_first = FALSE) {
           'filter' => array( ... ),
           ...
         ),
-        'join' => array( //describe a table that joins to this one via this field
-          'table' => 'featureprop', //table to join to
-          'field' => 'feature_id', //field in above table (featureprop)
-          'handler' => 'views_handler_join_chado_aggregator', //handler to use
+        // Describe any joins involving this field.
+        // Note: you can include both foreign keys (feature.type_id => cvterm.cvterm_id)
+        // and referring tables (ie: feature.feature_id <= feature_relationship.subject_id)
+        'joins' => array(
+          'feature_relationship' => array( //table to join to.
+            'subject_id' => array( //field in above table (feature_relationship)
+              'table' => 'featureprop', //table to join to
+              'field' => 'feature_id', //field in above table (feature_relationship)
+              'handler' => 'views_join', //handler to use for joining
+              'relationship_handler' => 'views_handler_relationship', //handler to use when a relationship is added.
+              'relationship_only' => FALSE, //whether to join automatically (FALSE) or not (TRUE)
+            ),
+            ...
+          ),
+          ...
         ),
       )
     ),
@@ -733,42 +755,59 @@ function tripal_add_views_integration($defn_array, $setup_id = FALSE) {
         }
 
         // Insert Joins
+        // Note: The new defn_array structure accounts for 1+ joins to the same
+        // table (ie: feature_relationship => feature : subject_id & object_id)
+        // by making $field['joins'] an array of left_field keys.
         if (!is_array($field['joins'])) {
           $field['joins'] = array();
         }
-        foreach ($field['joins'] as $join) {
-          $join_record = array(
-            'setup_id' => $view_record['setup_id'],
-            'base_table' => $defn_array['table'],
-            'base_field' => $field['name'],
-            'left_table' => $join['table'],
-            'left_field' => $join['field'],
-          );
-
-          $join_record['handler'] = (!empty($join['handler'])) ? $join['handler'] : 'views_join';
-          $join_record['relationship_handler'] = (!empty($join['relationship_handler'])) ? $join['relationship_handler'] : 'views_handler_relationship';
-          $join_record['relationship_only'] = (!empty($join['relationship_only'])) ? $join['relationship_only'] : 0;
-
-          if ($view_record['setup_id'] && $defn_array['table'] && $field['name'] && $join['table'] && $join['field']) {
-            $status = drupal_write_record('tripal_views_join', $join_record);
-          }
-          else {
-            $status = FALSE;
+        foreach ($field['joins'] as $joins) {
+          // To keep backwards compatibility with the old defn_array which just
+          // jumped right into the table definition allowing only a single join,
+          // we need to check for old defn_arrays and transform them into the
+          // new format.
+          if (isset($joins['table'])) {
+            $left_field = $joins['field'];
+            $joins = array(
+              $left_field => $joins
+            );
           }
-          if (!$status) {
-            drupal_set_message(
-              t(
-                'Unable to join %left_table.%left_field with %table.%field',
-                array(
-                  '%left_table' => $join['table'],
-                  '%left_field' => $join['field'],
-                  '%table' => $defn_array['table'],
-                  '%field' => $field['name']
-                )
-              ),
-              'error'
+
+          // Loop on left fields
+          foreach ($joins as $left_field => $join) {
+            $join_record = array(
+              'setup_id' => $view_record['setup_id'],
+              'base_table' => $defn_array['table'],
+              'base_field' => $field['name'],
+              'left_table' => $join['table'],
+              'left_field' => $left_field,
             );
-            $no_errors = FALSE;
+
+            $join_record['handler'] = (!empty($join['handler'])) ? $join['handler'] : 'views_join';
+            $join_record['relationship_handler'] = (!empty($join['relationship_handler'])) ? $join['relationship_handler'] : 'views_handler_relationship';
+            $join_record['relationship_only'] = (!empty($join['relationship_only'])) ? $join['relationship_only'] : 0;
+
+            if ($view_record['setup_id'] && $defn_array['table'] && $field['name'] && $join['table'] && $left_field) {
+              $status = drupal_write_record('tripal_views_join', $join_record);
+            }
+            else {
+              $status = FALSE;
+            }
+            if (!$status) {
+              drupal_set_message(
+                t(
+                  'Unable to join %left_table.%left_field with %table.%field',
+                  array(
+                    '%left_table' => $join['table'],
+                    '%left_field' => $left_field,
+                    '%table' => $defn_array['table'],
+                    '%field' => $field['name']
+                  )
+                ),
+                'error'
+              );
+              $no_errors = FALSE;
+            }
           }
         }
 
@@ -821,7 +860,6 @@ function tripal_export_views_integration($setup_id) {
   );
 
   // Add fields
-  // D7 TODO: Check DBTNG changes work
   $resource = db_query("SELECT * FROM {tripal_views_field} WHERE setup_id=:setup", array(':setup' => $setup_id));
   foreach ($resource as $r) {
     $defn_array['fields'][ $r->column_name ] = array(
@@ -835,7 +873,6 @@ function tripal_export_views_integration($setup_id) {
   }
 
   // Add handlers
-  // D7 TODO: Check DBTNG changes work
   $resource = db_query("SELECT * FROM {tripal_views_handlers} WHERE setup_id=:setup", array(':setup' => $setup_id));
   foreach ($resource as $r) {
     $defn_array['fields'][ $r->column_name ]['handlers'][ $r->handler_type ] = array(
@@ -844,10 +881,9 @@ function tripal_export_views_integration($setup_id) {
   }
 
   // Add joins
-  // D7 TODO: Check DBTNG changes work
   $resource = db_query("SELECT * FROM {tripal_views_join} WHERE setup_id=:setup", array(':setup' => $setup_id));
   foreach ($resource as $r) {
-    $defn_array['fields'][ $r->base_field ]['joins'][ $r->left_table ] = array(
+    $defn_array['fields'][ $r->base_field ]['joins'][ $r->left_table ][ $r->left_field ] = array(
       'table' => $r->left_table,
       'field' => $r->left_field,
       'handler' => $r->handler,
@@ -970,7 +1006,6 @@ function tripal_clone_views_integration($table_name, $new_priority = NULL, $temp
     $defn_array['priority'] = $defn_array['priority'] - 1;
   }
 
-  // D7 TODO: Check DBTNG changes work
   tripal_add_views_integration($defn_array);
   $setup_id = db_query(
     "SELECT setup_id FROM {tripal_views} WHERE table_name=:table AND priority=:priority",
@@ -1103,45 +1138,62 @@ function tripal_add_field_to_views_integration($table_name, $priority, $field) {
     }
 
     // Insert Joins
+    // Note: The new defn_array structure accounts for 1+ joins to the same
+    // table (ie: feature_relationship => feature : subject_id & object_id)
+    // by making $field['joins'] an array of left_field keys.
     if (!is_array($field['joins'])) {
       $field['joins'] = array();
     }
-    foreach ($field['joins'] as $join) {
-      $join_record = array(
-        'setup_id' => $setup_id,
-        'base_table' => $defn_array['table'],
-        'base_field' => $field['name'],
-        'left_table' => $join['table'],
-        'left_field' => $join['field'],
-      );
-
-      if (!empty($join['handler'])) {
-        $join_record['handler'] = $join['handler'];
-      }
-      else {
-        $join_record['handler'] = 'views_join';
+    foreach ($field['joins'] as $joins) {
+      // To keep backwards compatibility with the old defn_array which just
+      // jumped right into the table definition allowing only a single join,
+      // we need to check for old defn_arrays and transform them into the
+      // new format.
+      if (isset($joins['table'])) {
+        $left_field = $joins['field'];
+        $joins = array(
+          $left_field => $joins
+        );
       }
 
-      if ($setup_id && $defn_array['table'] && $field['name'] && $join['table'] && $join['field']) {
-        $status = drupal_write_record('tripal_views_join', $join_record);
-      }
-      else {
-        $status = FALSE;
-      }
-      if (!$status) {
-        drupal_set_message(
-          t(
-            'Unable to join %left_table.%left_field with %table.%field',
-            array(
-              '%left_table' => $join['table'],
-              '%left_field' => $join['field'],
-              '%table' => $defn_array['table'],
-              '%field' => $field['name']
-            )
-          ),
-          'error'
+      // Loop on left fields
+      foreach ($joins as $left_field => $join) {
+        $join_record = array(
+          'setup_id' => $setup_id,
+          'base_table' => $defn_array['table'],
+          'base_field' => $field['name'],
+          'left_table' => $join['table'],
+          'left_field' => $join['field'],
         );
-        $no_errors = FALSE;
+
+        if (!empty($join['handler'])) {
+          $join_record['handler'] = $join['handler'];
+        }
+        else {
+          $join_record['handler'] = 'views_join';
+        }
+
+        if ($setup_id && $defn_array['table'] && $field['name'] && $join['table'] && $join['field']) {
+          $status = drupal_write_record('tripal_views_join', $join_record);
+        }
+        else {
+          $status = FALSE;
+        }
+        if (!$status) {
+          drupal_set_message(
+            t(
+              'Unable to join %left_table.%left_field with %table.%field',
+              array(
+                '%left_table' => $join['table'],
+                '%left_field' => $join['field'],
+                '%table' => $defn_array['table'],
+                '%field' => $field['name']
+              )
+            ),
+            'error'
+          );
+          $no_errors = FALSE;
+        }
       }
     }
 

+ 21 - 4
tripal_views/includes/tripal_views_integration.inc

@@ -111,6 +111,7 @@ function tripal_views_get_integration_array_for_chado_table($table_name, $base_t
           'field' => array('name' => 'views_handler_field_numeric'),
           'filter' => array('name' => 'views_handler_filter_numeric'),
           'sort' => array('name' => 'views_handler_sort'),
+          'argument' => array('name' => 'views_handler_argument_numeric'),
         );
       }
       elseif (preg_match('/^serial/', $field_schema['type'])) {
@@ -123,6 +124,7 @@ function tripal_views_get_integration_array_for_chado_table($table_name, $base_t
           'field' => array('name' => 'views_handler_field_numeric'),
           'filter' => array('name' => 'views_handler_filter_numeric'),
           'sort' => array('name' => 'views_handler_sort'),
+          'argument' => array('name' => 'views_handler_argument_numeric'),
         );
         $defn_array['fields'][$field_name]['type'] = 'int';
       }
@@ -136,6 +138,7 @@ function tripal_views_get_integration_array_for_chado_table($table_name, $base_t
           'field' => array('name' => 'views_handler_field'),
           'filter' => array('name' => 'views_handler_filter_string'),
           'sort' => array('name' => 'views_handler_sort'),
+          'argument' => array('name' => 'views_handler_argument_string'),
         );
       }
       elseif (preg_match('/^text/', $field_schema['type'])) {
@@ -148,6 +151,7 @@ function tripal_views_get_integration_array_for_chado_table($table_name, $base_t
           'field' => array('name' => 'views_handler_field'),
           'filter' => array('name' => 'views_handler_filter_string'),
           'sort' => array('name' => 'views_handler_sort'),
+          'argument' => array('name' => 'views_handler_argument_string'),
         );
       }
       elseif (preg_match('/^boolean/', $field_schema['type'])) {
@@ -172,6 +176,7 @@ function tripal_views_get_integration_array_for_chado_table($table_name, $base_t
           'field' => array('name' => 'views_handler_field_date'),
           'filter' => array('name' => 'views_handler_filter_date'),
           'sort' => array('name' => 'views_handler_sort_date'),
+          'argument' => array('name' => 'views_handler_argument_date'),
         );
       }
       else {
@@ -184,6 +189,7 @@ function tripal_views_get_integration_array_for_chado_table($table_name, $base_t
           'field' => array('name' => 'views_handler_field'),
           'filter' => array('name' => 'views_handler_filter_string'),
           'sort' => array('name' => 'views_handler_sort'),
+          'argument' => array('name' => 'views_handler_argument_string'),
         );
       }
 
@@ -203,11 +209,13 @@ function tripal_views_get_integration_array_for_chado_table($table_name, $base_t
   }
   foreach ($schema['foreign keys'] as $foreign_key_schema) {
     foreach ($foreign_key_schema['columns'] as $left_field => $right_field) {
-      // Join
-      $defn_array['fields'][$left_field]['joins'][ $foreign_key_schema['table'] ] = array(
+
+      // Note: Even though there can only be a single join  for a foreign key
+      // we make the joins an array keyed by left_field to ensure that both
+      // foeign key and referring_tables (see below) can be processed the same.
+      $defn_array['fields'][$left_field]['joins'][ $foreign_key_schema['table'] ][ $left_field ] = array(
         'table' => $foreign_key_schema['table'],
         'field' => $right_field,
-        /**D6 'handler' => 'views_handler_join_chado_aggregator'*/
         'handler' => 'views_handler_join',
         'relationship_handler' => 'views_handler_relationship',
       );
@@ -215,6 +223,10 @@ function tripal_views_get_integration_array_for_chado_table($table_name, $base_t
   }
 
   // Add in reverse relationships
+  // Note: The array structure is set up with the left_field keyed array to
+  // handle more than one join between the same set of tables on different
+  // fields. For example, the reverse relationship between feature &
+  // feature_relationship needs to join on both the subject_id and object_id.
   if (isset($schema['referring_tables'])) {
     foreach ($schema['referring_tables'] as $referring_table) {
 
@@ -222,12 +234,17 @@ function tripal_views_get_integration_array_for_chado_table($table_name, $base_t
       $referring_schema = chado_get_schema($referring_table);
       $referring_schema_fk_columns = $referring_schema['foreign keys'][$table_name]['columns'];
       foreach ($referring_schema_fk_columns as $left_field => $right_field) {
-        $defn_array['fields'][$right_field]['joins'][ $referring_table ] = array(
+
+        // Also notice that it doesn't matter whether this is the first or second
+        // reverse join on this table ($referring_table) to be added since
+        // having $left_field as the key keeps them separate.
+        $defn_array['fields'][$right_field]['joins'][ $referring_table ][ $left_field ] = array(
           'table' => $referring_table,
           'field' => $left_field,
           'relationship_handler' => 'views_handler_relationship',
           'relationship_only' => 1
         );
+
       }
     }
   }

+ 33 - 12
tripal_views/tripal_views.views.inc

@@ -340,7 +340,7 @@ function tripal_views_views_data() {
         if (!$join->relationship_only) {
           $data[$left_table]['table']['join'][$base_table] = array(
             'left_field' => $base_field,
-            'field' => $left_table . '_id',
+            'field' => $left_field,
           );
           if ($handler) {
             $data[$left_table]['table']['join'][$base_table]['handler'] = $handler;
@@ -356,15 +356,36 @@ function tripal_views_views_data() {
             'DEPRECATED: Currently using tripal_views_handlers to store relationship for %base => %left when you should be using tripal_views_joins.',
             array('%base' => $base_table, '%left' => $left_table));
         }
-        // add relationship entry
+
+        // Add relationship entry.
+        // NOTE: we use a fake field name to allow us to have multiple
+        // relationships for the same field (ie: feature.feature_id has many
+        // Many relationships but views only supports a single one).
         $fake_field = $base_field . '_to_' . $left_table;
+
+        // Bug Fix: The old $fake_field used above doesn't take into account
+        // multiple relationships to the same left table. To keep backwards
+        // compatibility, this old fake_field needs to continue to be used for
+        // the LAST recorded relationship. However, for all previously set
+        // relationships we can use an improved fake name which takes into
+        // account the left field and ensures all relationships for a single
+        // left table are not condensed into a single relationship.
+        if (array_key_exists($fake_field, $data[$base_table])) {
+          $improved_fake_field = $base_field . '_to_' . $left_table . "." . $left_field;
+          // Again, note that we can't just change the fake_name after finding
+          // there is more than one relationship because then the FIRST
+          // relationship would keep the old fake_name rather than the LAST
+          // which keeps backwards compatiblity since the old naming caused all
+          // previous relationships be be overridden by the next one.
+          $data[$base_table][$improved_fake_field] = $data[$base_table][$fake_field];
+        }
         $data[$base_table][$fake_field] = array(
-          'title' => "$base_title.$base_field => $left_title",
-          'help' => "Joins $base_title.$base_field to $left_title",
+          'title' => "$base_title.$base_field => $left_title.$left_field",
+          'help' => t("Joins @base to @left", array('@base' => "$base_title.$base_field", '@left' => "$left_title.$left_field")),
           'relationship' => array(
             'handler' => $join->relationship_handler,
-            'title' => t("$base_field => $left_title"),
-            'label' => t("$base_field => $left_title"),
+            'title' => t("$base_field => $left_title ($left_field)"),
+            'label' => t("$base_field => $left_title ($left_field)"),
             'real field' => $base_field,
             'base' => $left_table,
             'base field' => $left_field
@@ -582,11 +603,11 @@ function tripal_views_views_data_alter(&$data) {
           $data[$linker_table][$base_field] = array(
             'group' => $base_title,
             'title' => $base_title . 'Node',
-            'help' => "Links $base_title to it's node.",
+            'help' => t("Links @base_title to it's node.", array('@base_title' => $base_title)),
             'relationship' => array(
               'handler' => 'views_handler_relationship',
-              'title' => t("$base_title => Node"),
-              'label' => t("$base_title => Node"),
+              'title' => t("@base_title => Node", array('@base_title' => $base_title)),
+              'label' => t("@base_title => Node", array('@base_title' => $base_title)),
               'real field' => 'nid',
               'base' => 'node',
               'base field' => 'nid'
@@ -599,11 +620,11 @@ function tripal_views_views_data_alter(&$data) {
           $data['node'][$base_field] = array(
             'group' => $base_title,
             'title' => $base_title,
-            'help' => "Links node to chado $base_title.",
+            'help' => t("Links node to chado @base_title.", array('@base_title' => $base_title)),
             'relationship' => array(
               'handler' => 'views_handler_relationship',
-              'title' => t("Node => $base_title"),
-              'label' => t("Node => $base_title"),
+              'title' => t("Node => @base_title", array('@base_title' => $base_title)),
+              'label' => t("Node => @base_title", array('@base_title' => $base_title)),
               'real field' => 'nid',
               'base' => $linker_table,
               'base field' => 'nid'