From 155a314b8c51f36989a654882522595a16d4511a Mon Sep 17 00:00:00 2001 From: Alex Pott <alex.a.pott@googlemail.com> Date: Tue, 20 Jan 2015 13:18:41 +0000 Subject: [PATCH] Issue #2378729 by jibran: JoinPluginBase doesn't allow extra conditions on left table --- .../src/Plugin/views/join/JoinPluginBase.php | 83 +++++++++++++++++-- .../views/src/Tests/Plugin/JoinTest.php | 31 +++++++ core/modules/views/views.api.php | 22 +++++ 3 files changed, 130 insertions(+), 6 deletions(-) diff --git a/core/modules/views/src/Plugin/views/join/JoinPluginBase.php b/core/modules/views/src/Plugin/views/join/JoinPluginBase.php index b9ce5a515a1c..051955e4bfb9 100644 --- a/core/modules/views/src/Plugin/views/join/JoinPluginBase.php +++ b/core/modules/views/src/Plugin/views/join/JoinPluginBase.php @@ -21,8 +21,8 @@ * They must be annotated with \Drupal\views\Annotation\ViewsJoin annotation, * and they must be in namespace directory Plugin\views\join. * - * Here is an example of how to join from table one to table two so it produces - * the following SQL: + * Here are some examples of how to join from table one to table two so it + * produces the following SQL: * @code * INNER JOIN {two} ON one.field_a = two.field_b * @endcode @@ -33,7 +33,67 @@ * 'field' => 'field_b', * 'left_table' => 'one', * 'left_field' => 'field_a', - * 'operator' => '=' + * 'operator' => '=', + * ); + * $join = Views::pluginManager('join')->createInstance('standard', $configuration); + * @endcode + * @code + * INNER JOIN {two} ON one.field_a = two.field_b AND one.field_c = 'some_val' + * @endcode + * The required php code for this kind of functionality is the following: + * @code + * $configuration = array( + * 'table' => 'two', + * 'field' => 'field_b', + * 'left_table' => 'one', + * 'left_field' => 'field_a', + * 'operator' => '=', + * 'extra' => array( + * 0 => array( + * 'left_field' => 'field_c', + * 'value' => 'some_val', + * ), + * ), + * ); + * $join = Views::pluginManager('join')->createInstance('standard', $configuration); + * @endcode + * @code + * INNER JOIN {two} ON one.field_a = two.field_b AND two.field_d = 'other_val' + * @endcode + * The required php code for this kind of functionality is the following: + * @code + * $configuration = array( + * 'table' => 'two', + * 'field' => 'field_b', + * 'left_table' => 'one', + * 'left_field' => 'field_a', + * 'operator' => '=', + * 'extra' => array( + * 0 => array( + * 'field' => 'field_d', + * 'value' => 'other_val', + * ), + * ), + * ); + * $join = Views::pluginManager('join')->createInstance('standard', $configuration); + * @endcode + * @code + * INNER JOIN {two} ON one.field_a = two.field_b AND one.field_c = two.field_d + * @endcode + * The required php code for this kind of functionality is the following: + * @code + * $configuration = array( + * 'table' => 'two', + * 'field' => 'field_b', + * 'left_table' => 'one', + * 'left_field' => 'field_a', + * 'operator' => '=', + * 'extra' => array( + * 0 => array( + * 'left_field' => 'field_c', + * 'field' => 'field_d', + * ), + * ), * ); * $join = Views::pluginManager('join')->createInstance('standard', $configuration); * @endcode @@ -98,6 +158,8 @@ class JoinPluginBase extends PluginBase implements JoinPluginInterface { * existing alias. If you use realtime joins, it works better. * - field(optional): Field or formula. In formulas we can reference the * right table by using %alias. + * - left_field(optional): Field or formula. In formulas we can reference + * the left table by using %alias. * - operator(optional): The operator used, Defaults to "=". * - value: Must be set. If an array, operator will be defaulted to IN. * - numeric: If true, the value will not be surrounded in quotes. @@ -257,18 +319,27 @@ public function buildJoin($select_query, $table, $view_query) { else { // With a single value, the '=' operator is implicit. $operator = !empty($info['operator']) ? $info['operator'] : '='; + $placeholder = ':views_join_condition_' . $select_query->nextPlaceholder(); + } + // Set 'field' as join table field if available or set 'left field' as + // join table field is not set. + if (isset($info['field'])) { + $join_table_field = "$join_table$info[field]"; // Allow the value to be set either with the 'value' element or // with 'left_field'. if (isset($info['left_field'])) { $placeholder = "$left[alias].$info[left_field]"; } else { - $placeholder = ':views_join_condition_' . $select_query->nextPlaceholder(); $arguments[$placeholder] = $info['value']; } } - - $extras[] = "$join_table$info[field] $operator $placeholder"; + // Set 'left field' as join table field is not set. + else { + $join_table_field = "$left[alias].$info[left_field]"; + $arguments[$placeholder] = $info['value']; + } + $extras[] = "$join_table_field $operator $placeholder"; } if ($extras) { diff --git a/core/modules/views/src/Tests/Plugin/JoinTest.php b/core/modules/views/src/Tests/Plugin/JoinTest.php index c557a9400fd3..28dbc4c64166 100644 --- a/core/modules/views/src/Tests/Plugin/JoinTest.php +++ b/core/modules/views/src/Tests/Plugin/JoinTest.php @@ -149,6 +149,7 @@ public function testBasePlugin() { $tables = $query->getTables(); $join_info = $tables['users3']; + $this->assertTrue(strpos($join_info['condition'], "views_test_data.uid = users3.uid") !== FALSE, 'Make sure the join condition appears in the query.'); $this->assertTrue(strpos($join_info['condition'], "users3.name = :views_join_condition_0") !== FALSE, 'Make sure the first extra join condition appears in the query and uses the first placeholder.'); $this->assertTrue(strpos($join_info['condition'], "users3.name <> :views_join_condition_1") !== FALSE, 'Make sure the second extra join condition appears in the query and uses the second placeholder.'); $this->assertEqual(array_values($join_info['arguments']), array($random_name_1, $random_name_2), 'Make sure the arguments are in the right order'); @@ -174,7 +175,37 @@ public function testBasePlugin() { $tables = $query->getTables(); $join_info = $tables['users4']; + $this->assertTrue(strpos($join_info['condition'], "views_test_data.uid = users4.uid") !== FALSE, 'Make sure the join condition appears in the query.'); + $this->assertTrue(strpos($join_info['condition'], "users4.name = :views_join_condition_2") !== FALSE, 'Make sure the first extra join condition appears in the query.'); $this->assertTrue(strpos($join_info['condition'], "users4.name IN ( :views_join_condition_3, :views_join_condition_4, :views_join_condition_5 )") !== FALSE, 'The IN condition for the join is properly formed.'); + + // Test that all the conditions are properly built. + $configuration['extra'] = array( + array( + 'field' => 'langcode', + 'value' => 'en' + ), + array( + 'left_field' => 'status', + 'value' => 0, + 'numeric' => TRUE, + ), + array( + 'field' => 'name', + 'left_field' => 'name' + ), + ); + $join = $this->manager->createInstance('standard', $configuration); + $table = array('alias' => 'users5'); + $join->buildJoin($query, $table, $view->query); + + $tables = $query->getTables(); + $join_info = $tables['users5']; + $this->assertTrue(strpos($join_info['condition'], "views_test_data.uid = users5.uid") !== FALSE, 'Make sure the join condition appears in the query.'); + $this->assertTrue(strpos($join_info['condition'], "users5.langcode = :views_join_condition_6") !== FALSE, 'Make sure the first extra join condition appears in the query.'); + $this->assertTrue(strpos($join_info['condition'], "views_test_data.status = :views_join_condition_7") !== FALSE, 'Make sure the second extra join condition appears in the query.'); + $this->assertTrue(strpos($join_info['condition'], "users5.name = views_test_data.name") !== FALSE, 'Make sure the third extra join condition appears in the query.'); + $this->assertEqual(array_values($join_info['arguments']), array('en', 0), 'Make sure the arguments are in the right order'); } } diff --git a/core/modules/views/views.api.php b/core/modules/views/views.api.php index 120bed0725fd..9f2813b395bb 100644 --- a/core/modules/views/views.api.php +++ b/core/modules/views/views.api.php @@ -188,6 +188,28 @@ function hook_views_data() { 'left_field' => 'nid', // Foreign key field in example_table to use in the join. 'field' => 'nid', + // An array of extra conditions on the join. + 'extra' => array( + 0 => array( + // Adds AND node.published = TRUE to the join. + 'field' => 'published', + 'value' => TRUE, + ), + 1 => array( + // Adds AND example_table.numeric_field = 1 to the join. + 'left_field' => 'numeric_field', + 'value' => 1, + // If true, the value will not be surrounded in quotes. + 'numeric' => TRUE, + ), + 2 => array( + // Adds AND example_table.boolean_field <> node.published to the join. + 'field' => 'published', + 'left_field' => 'boolean_field', + // The operator used, Defaults to "=". + 'operator' => '!=', + ), + ), ), ); -- GitLab