Skip to content

Commit

Permalink
Fix select of siblings
Browse files Browse the repository at this point in the history
  • Loading branch information
JanPietrzyk committed Oct 5, 2017
1 parent 9ce3846 commit 29b737b
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 30 deletions.
56 changes: 41 additions & 15 deletions src/NestedSetQueryFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ public function createSubtreeThroughMultipleNodesQueryBuilder(string $tableExpre

$directNodeSubSelect = $this->connection->createQueryBuilder()
->select([
"{$queryAlias}directNode." . $this->pkCol,
"{$queryAlias}directNode." . $this->leftCol,
"{$queryAlias}directNode." . $this->rightCol,
"{$queryAlias}directNode." . $this->levelCol,
Expand All @@ -151,8 +152,10 @@ public function createSubtreeThroughMultipleNodesQueryBuilder(string $tableExpre
->from($this->connection->quoteIdentifier($tableExpression), "{$queryAlias}directNode")
->andWhere("{$queryAlias}directNode.{$this->pkCol} IN (:{$queryAlias}nodeIds)");

$siblingQuery = $this->connection->createQueryBuilder()

$parentQuery = $this->connection->createQueryBuilder()
->select([
"{$queryAlias}SiblingNode." . $this->pkCol,
"{$queryAlias}SiblingNode." . $this->leftCol,
"{$queryAlias}SiblingNode." . $this->rightCol,
"{$queryAlias}SiblingNode." . $this->levelCol,
Expand All @@ -161,18 +164,29 @@ public function createSubtreeThroughMultipleNodesQueryBuilder(string $tableExpre
->from($this->connection->quoteIdentifier($tableExpression), "{$queryAlias}SiblingNode")
->innerJoin(
"{$queryAlias}SiblingNode",
$this->connection->quoteIdentifier($tableExpression),
"{$queryAlias}ParentNode",
"
{$queryAlias}SiblingNode.{$this->leftCol} >= {$queryAlias}ParentNode.{$this->leftCol}
AND {$queryAlias}SiblingNode.{$this->rightCol} <= {$queryAlias}ParentNode.{$this->rightCol}
AND {$queryAlias}SiblingNode.{$this->levelCol} = {$queryAlias}ParentNode.{$this->levelCol} + 1
AND {$queryAlias}SiblingNode.{$this->rootCol} = {$queryAlias}ParentNode.{$this->rootCol}
"
)
->innerJoin(
"{$queryAlias}ParentNode",
'(' . $directNodeSubSelect->getSQL() . ')',
"{$queryAlias}SelectedNode",
"
{$queryAlias}SiblingNode.{$this->leftCol} >= {$queryAlias}SelectedNode.{$this->leftCol}
AND {$queryAlias}SiblingNode.{$this->rightCol} >= {$queryAlias}SelectedNode.{$this->rightCol}
AND {$queryAlias}SiblingNode.{$this->levelCol} = {$queryAlias}SelectedNode.{$this->levelCol}
AND {$queryAlias}SiblingNode.{$this->rootCol} = {$queryAlias}SelectedNode.{$this->rootCol}
{$queryAlias}ParentNode.{$this->leftCol} < {$queryAlias}SelectedNode.{$this->leftCol}
AND {$queryAlias}ParentNode.{$this->rightCol} > {$queryAlias}SelectedNode.{$this->rightCol}
AND {$queryAlias}ParentNode.{$this->rootCol} = {$queryAlias}SelectedNode.{$this->rootCol}
"
);

$childrenQuery = $this->connection->createQueryBuilder()
->select([
"{$queryAlias}ChildNode." . $this->pkCol,
"{$queryAlias}ChildNode." . $this->leftCol,
"{$queryAlias}ChildNode." . $this->rightCol,
"{$queryAlias}ChildNode." . $this->levelCol,
Expand All @@ -191,18 +205,30 @@ public function createSubtreeThroughMultipleNodesQueryBuilder(string $tableExpre
"
);

$idQuery = $this->connection->createQueryBuilder()
->select("{$queryAlias}Group.{$this->pkCol}")
->from($this->connection->quoteIdentifier($tableExpression), "{$queryAlias}Group")
$rootQuery = $this->connection->createQueryBuilder()
->select([
"{$queryAlias}RootNode." . $this->pkCol,
"{$queryAlias}RootNode." . $this->leftCol,
"{$queryAlias}RootNode." . $this->rightCol,
"{$queryAlias}RootNode." . $this->levelCol,
"{$queryAlias}RootNode." . $this->rootCol,
])
->from($this->connection->quoteIdentifier($tableExpression), "{$queryAlias}RootNode")
->innerJoin(
"{$queryAlias}Group",
'((' . $childrenQuery->getSQL() . ') UNION (' . $siblingQuery->getSQL() . '))',
"{$queryAlias}SourceNode",
"
{$queryAlias}Group.{$this->leftCol} <= {$queryAlias}SourceNode.{$this->leftCol}
AND {$queryAlias}Group.{$this->rightCol} >= {$queryAlias}SourceNode.{$this->rightCol}
AND {$queryAlias}Group.{$this->rootCol} = {$queryAlias}SourceNode.{$this->rootCol}
"{$queryAlias}RootNode",
'(' . $directNodeSubSelect->getSQL() . ')',
"{$queryAlias}SelectedNode",
"
{$queryAlias}RootNode.{$this->levelCol} = 0
AND {$queryAlias}RootNode.{$this->rootCol} = {$queryAlias}SelectedNode.{$this->rootCol}
"
);

$idQuery = $this->connection->createQueryBuilder()
->select("{$queryAlias}Group.{$this->pkCol}")
->from(
'((' . $childrenQuery->getSQL() . ') UNION (' . $parentQuery->getSQL() . ') UNION (' . $rootQuery->getSQL() . ')) ',
"{$queryAlias}Group"
)
->groupBy("{$queryAlias}Group.id");

Expand Down
32 changes: 17 additions & 15 deletions tests/NestedSetQueryFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,47 +105,43 @@ public function test_fetch_all_roots()
$this->assertEquals('Clothing', $rows[1]['name']);
}

public function test_fetch_subtree_with_a_single_selected_node()
public function test_fetch_subtree_with_root_only_selected()
{
\NestedSetBootstrap::printTree(1);

$qb = $this->queryFactory
->createSubtreeThroughMultipleNodesQueryBuilder('tree', 't', 'root_id', [5])
->createSubtreeThroughMultipleNodesQueryBuilder('tree', 't', 'root_id', [1])
->select('*');

$this->assertSubTree(
[
'Clothing',
'Mens',
'Suits',
'Slacks',
'Jackets',
'Women',
],
$qb->execute()->fetchAll()
);
}

public function test_fetch_subtree_with_root_only_selected()
public function test_fetch_subtree_with_a_single_selected_node_slacks()
{

$qb = $this->queryFactory
->createSubtreeThroughMultipleNodesQueryBuilder('tree', 't', 'root_id', [1])
->createSubtreeThroughMultipleNodesQueryBuilder('tree', 't', 'root_id', [5])
->select('*');

$this->assertSubTree(
[
'Clothing',
'Mens',
'Suits',
'Slacks',
'Jackets',
'Women',
],
$qb->execute()->fetchAll()
);
}

public function test_fetch_subtree_with_selected_nodes()
public function test_fetch_subtree_with_selected_nodes_mens_and_dresses()
{

$qb = $this->queryFactory
->createSubtreeThroughMultipleNodesQueryBuilder('tree', 't', 'root_id', [2, 7])
->select('*');
Expand All @@ -164,7 +160,10 @@ public function test_fetch_subtree_with_selected_nodes()
],
$qb->execute()->fetchAll()
);
}

public function test_fetch_subtree_with_selected_nodes_mens_and_women()
{
$qb = $this->queryFactory
->createSubtreeThroughMultipleNodesQueryBuilder('tree', 't', 'root_id', [3, 2])
->select('*');
Expand All @@ -183,7 +182,7 @@ public function test_fetch_subtree_with_selected_nodes()
);
}

public function test_fetch_subtree_with_selected_nodes_uses_the_depth_parameter()
public function test_fetch_subtree_with_selected_nodes_with_a_two_as_a_depth_parameter()
{
$qb = $this->queryFactory
->createSubtreeThroughMultipleNodesQueryBuilder('tree', 't', 'root_id', [2, 3], 2)
Expand All @@ -205,7 +204,10 @@ public function test_fetch_subtree_with_selected_nodes_uses_the_depth_parameter(
],
$qb->execute()->fetchAll()
);
}

public function test_fetch_subtree_with_selected_nodes_with_a_zero_depth_parameter()
{
$qb = $this->queryFactory
->createSubtreeThroughMultipleNodesQueryBuilder('tree', 't', 'root_id', [3, 2], 0)
->select('*');
Expand All @@ -222,10 +224,10 @@ public function test_fetch_subtree_with_selected_nodes_uses_the_depth_parameter(

private function assertSubTree(array $expectedNames, array $rows)
{
$names = array_map(function(array $node) {
$names = array_map(function (array $node) {
return $node['name'];
}, $rows);

$this->assertEquals($expectedNames, $names, 'Got: ' . print_r($names, true));
$this->assertEquals($expectedNames, $names, 'Got: ' . print_r($names, true) . "\n and expected: " . print_r($expectedNames, true));
}
}

0 comments on commit 29b737b

Please sign in to comment.