From a49768f28be5e560cb7873ff9e9b89e6d068cdc7 Mon Sep 17 00:00:00 2001 From: Thomas Steur <tsteur@users.noreply.github.com> Date: Mon, 15 May 2017 06:55:44 +1200 Subject: [PATCH] Fix a bug in the join generator when same table is present multiple times (#11690) * fix a bug in the join generator * add another test case to make sure the outer table foreach still works when removing an item * throw exception if table cannot be joined automatically --- .../LogQueryBuilder/JoinGenerator.php | 32 ++++++++++++ .../LogQueryBuilder/JoinGeneratorTest.php | 51 +++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/core/DataAccess/LogQueryBuilder/JoinGenerator.php b/core/DataAccess/LogQueryBuilder/JoinGenerator.php index 0324bff9b5..a7f8b5499f 100644 --- a/core/DataAccess/LogQueryBuilder/JoinGenerator.php +++ b/core/DataAccess/LogQueryBuilder/JoinGenerator.php @@ -62,6 +62,38 @@ class JoinGenerator } } } + + foreach ($this->tables as $index => $table) { + if (is_array($table)) { + if (!isset($table['tableAlias'])) { + $tableName = $table['table']; + $numTables = count($this->tables); + for ($j = $index + 1; $j < $numTables; $j++) { + if (!isset($this->tables[$j])) { + continue; + } + + $tableOther = $this->tables[$j]; + if (is_string($tableOther) && $tableOther === $tableName) { + unset($this->tables[$j]); + } + } + } + } elseif (is_string($table)) { + $numTables = count($this->tables); + + for ($j = $index + 1; $j < $numTables; $j++) { + if (isset($this->tables[$j]) && is_array($this->tables[$j]) && !isset($this->tables[$j]['tableAlias'])) { + $tableOther = $this->tables[$j]; + if ($table === $tableOther['table']) { + $message = sprintf('Please reorganize the joined tables as the table %s in %s cannot be joined correctly. We recommend to join tables with arrays first. %s', $table, json_encode($this->tables), json_encode(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10))); + throw new Exception($message); + } + } + + } + } + } } /** diff --git a/tests/PHPUnit/Unit/DataAccess/LogQueryBuilder/JoinGeneratorTest.php b/tests/PHPUnit/Unit/DataAccess/LogQueryBuilder/JoinGeneratorTest.php index 746f2e45ff..8e1ead3aec 100644 --- a/tests/PHPUnit/Unit/DataAccess/LogQueryBuilder/JoinGeneratorTest.php +++ b/tests/PHPUnit/Unit/DataAccess/LogQueryBuilder/JoinGeneratorTest.php @@ -102,6 +102,57 @@ class JoinGeneratorTest extends \PHPUnit_Framework_TestCase $this->assertEquals($expected, $generator->getJoinString()); } + public function test_generate_getJoinString_manuallyJoinedAlreadyWithCustomConditionInArray() + { + $generator = $this->generate(array( + 'log_visit', + array('table' => 'log_conversion', 'joinOn' => 'log_visit.idvisit2 = log_conversion.idvisit2'), + 'log_conversion' + )); + + $expected = 'log_visit AS log_visit '; + $expected .= 'LEFT JOIN log_conversion AS log_conversion ON log_visit.idvisit2 = log_conversion.idvisit2'; + $this->assertEquals($expected, $generator->getJoinString()); + } + + public function test_generate_getJoinString_manuallyJoinedAlreadyWithCustomConditionInArrayAndFurtherTablesAfterwards() + { + $generator = $this->generate(array( + 'log_visit', + array('table' => 'log_conversion', 'joinOn' => 'log_visit.idvisit2 = log_conversion.idvisit2'), + 'log_conversion', + 'log_link_visit_action' + )); + + $expected = 'log_visit AS log_visit '; + $expected .= 'LEFT JOIN log_conversion AS log_conversion ON log_visit.idvisit2 = log_conversion.idvisit2 '; + $expected .= 'LEFT JOIN log_link_visit_action AS log_link_visit_action ON log_link_visit_action.idvisit = log_visit.idvisit'; + $this->assertEquals($expected, $generator->getJoinString()); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Please reorganize the joined tables as the table log_conversion in {"0":"log_visit","1":"log_conversion","2":"log_link_visit_action","3":{"table":"log_conversion","joinOn":"log_link_visit_action.idvisit2 = log_conversion.idvisit2"}} cannot be joined correctly. + */ + public function test_generate_getJoinString_manuallyJoinedAlreadyWithCustomConditionInArrayInverted() + { + $generator = $this->generate(array( + 'log_visit', + 'log_conversion', + 'log_link_visit_action', + array('table' => 'log_conversion', 'joinOn' => 'log_link_visit_action.idvisit2 = log_conversion.idvisit2'), + )); + + $expected = 'log_visit AS log_visit '; + $expected .= 'LEFT JOIN log_conversion AS log_conversion ON log_visit.idvisit2 = log_conversion.idvisit2 '; + $expected .= 'LEFT JOIN log_link_visit_action AS log_link_visit_action ON log_link_visit_action.idvisit = log_visit.idvisit '; + $expected .= 'LEFT JOIN log_conversion AS log_conversion ON log_conversion.idvisit = log_visit.idvisit '; + + $expected .= 'LEFT JOIN log_conversion AS log_conversion ON log_visit.idvisit2 = log_conversion.idvisit2 '; + $expected .= 'LEFT JOIN log_link_visit_action AS log_link_visit_action ON log_link_visit_action.idvisit = log_visit.idvisit'; + $this->assertEquals($expected, $generator->getJoinString()); + } + public function test_generate_getJoinString_manuallyJoinedAlreadyPlusCustomJoinButAlsoLeft() { $generator = $this->generate(array( -- GitLab