One Relationship Handler to Rule Them All. (Props to solotandem for the wild idea...
[project/relation.git] / views / relation_handler_relationship.inc
1 <?php
2
3 /**
4 * @file
5 * Views relationship support.
6 */
7
8 class relation_handler_relationship extends views_handler_relationship {
9 /**
10 * Define r_index option.
11 */
12 function option_definition() {
13 $options = parent::option_definition();
14 $options['r_index'] = array('default' => -1);
15 return $options;
16 }
17
18 /**
19 * Let the user choose r_index.
20 */
21 function options_form(&$form, &$form_state) {
22 parent::options_form($form, $form_state);
23
24 $options = $this->options_form_summary_options();
25 if ($this->definition['directional']) {
26 $form['r_index'] = array(
27 '#type' => 'select',
28 '#options' => $options,
29 '#title' => t('Position of the relationship base'),
30 '#default_value' => $this->options['r_index'],
31 // check_plain()'d in the definition.
32 '#description' => t('Select whether the entity you are adding the relationship to is source or target of !relation_type_label relation.', array('!relation_type_label' => $this->definition['label'])),
33 );
34 }
35 }
36
37 /**
38 * Return the main options, which are shown in the summary title.
39 */
40 function options_form_summary_options() {
41 return $this->definition['directional'] ? array(
42 -1 => t('Any'),
43 0 => t('Source'),
44 1 => t('Target'),
45 ) : array();
46 }
47
48 function query() {
49 $field = field_info_field('endpoints');
50 $relation_data_table_name = _field_sql_storage_tablename($field);
51 $entity_id_field_name = _field_sql_storage_columnname('endpoints', 'entity_id');
52 $entity_type_field_name = _field_sql_storage_columnname('endpoints', 'entity_type');
53 $r_index_field_name = _field_sql_storage_columnname('endpoints', 'r_index');
54 $join_type = empty($this->options['required']) ? 'LEFT' : 'INNER';
55 $endpoints_twice = isset($this->definition['entity_type_left']) && isset($this->definition['entity_type_right']);
56
57 $this->ensure_my_table();
58 // Join the left table with the entity type to the endpoints field data table.
59 $join = new views_join();
60 $join->definition = array(
61 'left_table' => $this->table_alias,
62 'left_field' => $this->real_field,
63 'table' => $relation_data_table_name,
64 'field' => isset($this->definition['entity_type_left']) ? $entity_id_field_name : 'entity_id',
65 'type' => $join_type,
66 'extra' => array(
67 array(
68 'field' => 'bundle',
69 'value' => $this->definition['relation_type'],
70 ),
71 ),
72 );
73 if (isset($this->definition['entity_type_left'])) {
74 $join->definition['extra'][] = array(
75 'field' => $entity_type_field_name,
76 'value' => $this->definition['entity_type_left'],
77 );
78 }
79 if ($this->definition['directional'] && $this->options['r_index'] > -1) {
80 $join->definition['extra'][] = array(
81 'field' => $r_index_field_name,
82 'value' => $this->options['r_index'],
83 );
84 }
85 $join->construct();
86 $join->adjusted = TRUE;
87 $l = $this->query->add_table($relation_data_table_name, $this->relationship, $join);
88
89 if ($endpoints_twice) {
90 // Execute a self-join.
91 $join = new views_join();
92 $join->definition = array(
93 'left_table' => $l,
94 'left_field' => 'entity_id',
95 'table' => $relation_data_table_name,
96 'field' => 'entity_id',
97 'type' => $join_type,
98 'extra' => array(
99 array(
100 'field' => $entity_type_field_name,
101 'value' => $this->definition['entity_type_right'],
102 ),
103 ),
104 );
105 $join->construct();
106 $join->adjusted = TRUE;
107 $r = $this->query->add_table($relation_data_table_name, $this->relationship, $join);
108 }
109 else {
110 $r = $l;
111 }
112 $join = new views_join();
113 $join->definition = array(
114 'left_table' => $r,
115 'left_field' => isset($this->definition['entity_type_right']) ? $entity_id_field_name : 'entity_id',
116 'table' => $this->definition['base'],
117 'field' => $this->definition['base field'],
118 'type' => $join_type,
119 );
120 // There is no query where these conditions could be added earlier:
121 // $r might be just $l.
122 if ($endpoints_twice && $this->definition['entity_type_left'] == $this->definition['entity_type_right']) {
123 $join->definition['extra'][] = array(
124 // This definition is a bit funny but there's no other way to tell
125 // Views to use this as it is.
126 'table' => NULL,
127 'field' => "$r.$r_index_field_name != $l.$r_index_field_name AND 1",
128 'value' => 1,
129 );
130 }
131 if (isset($this->definition['entity_type_right'])) {
132 $join->definition['extra'][] = array(
133 'table' => $r,
134 'field' => $entity_type_field_name,
135 'value' => $this->definition['entity_type_right'],
136 );
137 }
138
139 $join->construct();
140 $join->adjusted = TRUE;
141 // use a short alias for this:
142 $alias = $this->definition['base'] . '_' . $this->table;
143 $this->alias = $this->query->add_relationship($alias, $join, $this->definition['base'], $this->relationship);
144 }
145 }