From 3537ee13e19671dc478e742e9e643449a12e2630 Mon Sep 17 00:00:00 2001
From: Jim Berry <jim@boombatower.com>
Date: Mon, 5 Dec 2011 20:23:13 +0000
Subject: [PATCH] #1361780: Replace relationship definitions to cover all the bases and so Relation plays well with Views.

---
 views/relation.views.inc                |   64 +++++++++++++++++++++++++++++++
 views/relation_handler_relationship.inc |   50 ++++++++++++++++++++++++
 2 files changed, 114 insertions(+), 0 deletions(-)

diff --git a/views/relation.views.inc b/views/relation.views.inc
index 9765c1e..e0d224f 100644
--- a/views/relation.views.inc
+++ b/views/relation.views.inc
@@ -156,6 +156,10 @@ function relation_views_data() {
       'handler' => 'views_handler_sort',
     ),
   );
+
+  // Define the base group of this table.
+  $data['field_data_endpoints']['table']['group']  = t('Endpoints');
+
   return $data;
 }
 
@@ -245,6 +249,66 @@ function relation_views_data_alter(&$data) {
             'join_handler' => 'relation_handler_base_right_join',
           ),
         );
+
+        // Define [join and] relationship from relation to endpoints.
+        $data['relation']['relation_base_' . $type . '_right_endpoints'] = array(
+          'title' => t('Endpoints: @relation_type_label (relation -> endpoints)', $t_arguments),
+          'help' => t('Provides a relationship from the relation table to endpoints relative to the "@relation_type_label" relation', $t_arguments),
+          'relationship' => array(
+            // relation_handler_relationship::options_form() relies on this check_plain().
+            'label' => check_plain('Endpoints::' . $relation_type->label),
+            'base' => 'field_data_endpoints',
+            'base field' => 'entity_id',
+            'relationship field' => 'rid',
+            'handler' => 'relation_handler_relationship', // To choose the r_index option.
+            'relation_type' => $type, // USE THIS as bundle
+            'entity_type_left' => 'field_data_endpoints', // Not used.
+            'entity_type_right' => $entity_type_right, // Use this as endpoint_entity_type.
+            'directional' => $relation_type->directional, // Not used.
+            'max_arity' => $relation_type->max_arity,
+            'join_handler' => 'relation_handler_relation_endpoint_join', // To add the r_index condition to join.
+          ),
+        );
+
+        // Define join and relationship from endpoints to entity.
+        $data['field_data_endpoints']['table']['join'] = array(
+          // Directly links to the $entity_type_right table.
+          $entity_type_right => array(
+            'left_field' => $entity_infos[$entity_type_right]['entity keys']['id'],
+            'field' => 'endpoints_entity_id',
+          ),
+        );
+        $data['field_data_endpoints']['endpoints_base_' . $type . '_right_' . $entity_type_right] = array(
+          'title' => t('Endpoints: @relation_type_label (endpoints -> @right)', $t_arguments),
+          'help' => t('Provides a relationship from the endpoints table to @right relative to the "@relation_type_label" relation', $t_arguments),
+          'relationship' => array(
+            // relation_handler_relationship::options_form() relies on this check_plain().
+            'label' => check_plain('Endpoints::' . $relation_type->label),
+            'base' => $base_table_right,
+            'base field' => $entity_infos[$entity_type_right]['entity keys']['id'],
+            'relationship field' => 'endpoints_entity_id',
+          ),
+        );
+
+        // Define [join and] relationship from endpoints to endpoints.
+        $data['field_data_endpoints']['endpoints_base_' . $type . '_right_endpoints'] = array(
+          'title' => t('Endpoints: @relation_type_label (endpoints -> endpoints)', $t_arguments),
+          'help' => t('Provides a relationship from the endpoints table to endpoints relative to the "@relation_type_label" relation', $t_arguments),
+          'relationship' => array(
+            // relation_handler_relationship::options_form() relies on this check_plain().
+            'label' => check_plain('Endpoints::' . $relation_type->label),
+            'base' => 'field_data_endpoints',
+            'base field' => 'entity_id',
+            'relationship field' => 'entity_id',
+            'handler' => 'relation_handler_relationship',
+            'relation_type' => $type, // USE THIS as bundle
+            'entity_type_left' => 'field_data_endpoints', // Not used.
+            'entity_type_right' => $entity_type_right, // Use this as endpoint_entity_type.
+            'directional' => $relation_type->directional, // Not used.
+            'max_arity' => $relation_type->max_arity, // Is this needed?
+            'join_handler' => 'relation_handler_endpoint_endpoint_join',
+          ),
+        );
       }
     }
   }
diff --git a/views/relation_handler_relationship.inc b/views/relation_handler_relationship.inc
index 001addc..d6fda1c 100644
--- a/views/relation_handler_relationship.inc
+++ b/views/relation_handler_relationship.inc
@@ -121,3 +121,53 @@ class relation_handler_base_right_join extends views_join {
     $select_query->addJoin($this->type, $table['table'], $table['alias'], $conditions);
   }
 }
+
+class relation_handler_endpoint_endpoint_join extends views_join {
+  /**
+   * Build the SQL for the join this object represents.
+   *
+   * This does an endpoint to endpoint join relative to a relation.
+   */
+  function build_join($select_query, $table, $view_query) {
+    $entity_type_field_name = _field_sql_storage_columnname('endpoints', 'entity_type');
+    $r_index_field_name = _field_sql_storage_columnname('endpoints', 'r_index');
+
+    $entity_type_right = $this->definition['entity_type_right'];
+    $relation_type = $this->definition['relation_type'];
+
+    // Note: the Views naming convention on left versus right is opposite the
+    // actual order in the join clause.
+
+    // The aliased name of the existing endpoint table we are joining to.
+    $l = $this->left_table;
+    // The aliased name of the current endpoint table.
+    $r = $table['alias'];
+
+    // Self-join the endpoints table but grab a different endpoint (r_index).
+    $conditions = "$r.entity_id = $l.entity_id AND $r.$r_index_field_name != $l.$r_index_field_name";
+    if ($this->options['r_index'] > -1) {
+      // Grab a specific index.
+      $conditions .= " AND $r.$r_index_field_name = " . $this->options['r_index'];
+    }
+    // Restrict the join to the proper entity type and bundle.
+    $conditions .= " AND $r.$entity_type_field_name = '$entity_type_right' AND $r.bundle = '$relation_type'";
+
+    // Add a self-join.
+    $select_query->addJoin($this->type, $table['table'], $table['alias'], $conditions);
+  }
+}
+
+class relation_handler_relation_endpoint_join extends views_join {
+  /**
+   * Construct the views_join object.
+   *
+   * This does a relation to endpoint join.
+   */
+  function construct($table = NULL, $left_table = NULL, $left_field = NULL, $field = NULL, $extra = array(), $type = 'LEFT') {
+    parent::construct($table, $left_table, $left_field, $field, $extra, $type);
+    $r_index_field_name = _field_sql_storage_columnname('endpoints', 'r_index');
+    if ($this->options['r_index'] > -1) {
+      $this->extra = array(array('field' => $r_index_field_name, 'value' => $this->options['r_index']));
+    }
+  }
+}
-- 
1.7.4.1

