Author: dr
Date: Thu Aug 2 11:05:25 2007
New Revision: 5802
Log:
- Implemented Breadth-first fetching of subtrees.
Modified:
trunk/Tree/src/backends/db_parent_child.php
trunk/Tree/src/backends/memory.php
trunk/Tree/src/backends/xml.php
trunk/Tree/src/tree_node.php
trunk/Tree/tests/db_parent_child_tree.php
trunk/Tree/tests/memory_tree.php
trunk/Tree/tests/tree.php
trunk/Tree/tests/xml_tree.php
Modified: trunk/Tree/src/backends/db_parent_child.php
==============================================================================
--- trunk/Tree/src/backends/db_parent_child.php [iso-8859-1] (original)
+++ trunk/Tree/src/backends/db_parent_child.php [iso-8859-1] Thu Aug 2
11:05:25 2007
@@ -101,13 +101,13 @@
* @param ezcTreeNodeList $list
* @param string $nodeId
*/
- private function addChildNodes( ezcTreeNodeList $list, $nodeId )
+ private function addChildNodesDepthFirst( ezcTreeNodeList $list, $nodeId )
{
$className = $this->properties['nodeClassName'];
foreach ( $this->fetchChildRecords( $nodeId ) as $record )
{
$list->addNode( new $className( $this, $record['id'] ) );
- $this->addChildNodes( $list, $record['id'] );
+ $this->addChildNodesDepthFirst( $list, $record['id'] );
}
}
@@ -152,6 +152,22 @@
}
/**
+ * Returns the node with ID $id and all its children, sorted accoring to
+ * the `Depth-first sorting`_ algorithm.
+ *
+ * @param string $id
+ * @return ezcTreeNodeList
+ */
+ public function fetchSubtreeDepthFirst( $nodeId )
+ {
+ $className = $this->properties['nodeClassName'];
+ $list = new ezcTreeNodeList;
+ $list->addNode( new $className( $this, $nodeId ) );
+ $this->addChildNodesDepthFirst( $list, $nodeId );
+ return $list;
+ }
+
+ /**
* Alias for fetchSubtreeDepthFirst().
*
* @param string $id
@@ -160,6 +176,27 @@
public function fetchSubtree( $nodeId )
{
return $this->fetchSubtreeDepthFirst( $nodeId );
+ }
+
+ /**
+ * Adds the children nodes of the node with ID $nodeId to the
+ * ezcTreeNodeList $list.
+ *
+ * @param ezcTreeNodeList $list
+ * @param string $nodeId
+ */
+ private function addChildNodesBreadthFirst( ezcTreeNodeList $list, $nodeId
)
+ {
+ $className = $this->properties['nodeClassName'];
+ $childRecords = $this->fetchChildRecords( $nodeId )->fetchAll();
+ foreach ( $childRecords as $record )
+ {
+ $list->addNode( new $className( $this, $record['id'] ) );
+ }
+ foreach ( $childRecords as $record )
+ {
+ $this->addChildNodesBreadthFirst( $list, $record['id'] );
+ }
}
/**
@@ -171,21 +208,10 @@
*/
public function fetchSubtreeBreadthFirst( $nodeId )
{
- }
-
- /**
- * Returns the node with ID $id and all its children, sorted accoring to
- * the `Depth-first sorting`_ algorithm.
- *
- * @param string $id
- * @return ezcTreeNodeList
- */
- public function fetchSubtreeDepthFirst( $nodeId )
- {
$className = $this->properties['nodeClassName'];
$list = new ezcTreeNodeList;
$list->addNode( new $className( $this, $nodeId ) );
- $this->addChildNodes( $list, $nodeId );
+ $this->addChildNodesBreadthFirst( $list, $nodeId );
return $list;
}
Modified: trunk/Tree/src/backends/memory.php
==============================================================================
--- trunk/Tree/src/backends/memory.php [iso-8859-1] (original)
+++ trunk/Tree/src/backends/memory.php [iso-8859-1] Thu Aug 2 11:05:25 2007
@@ -142,35 +142,13 @@
* @param ezcTreeNodeList $list
* @param string $nodeId
*/
- private function addChildNodes( ezcTreeNodeList $list, ezcTreeMemoryNode
$memoryNode )
+ private function addChildNodesDepthFirst( ezcTreeNodeList $list,
ezcTreeMemoryNode $memoryNode )
{
foreach ( $memoryNode->children as $id => $childMemoryNode )
{
$list->addNode( $childMemoryNode->node );
- $this->addChildNodes( $list, $childMemoryNode );
- }
- }
-
- /**
- * Alias for fetchSubtreeDepthFirst().
- *
- * @param string $id
- * @return ezcTreeNodeList
- */
- public function fetchSubtree( $nodeId )
- {
- return $this->fetchSubtreeDepthFirst( $nodeId );
- }
-
- /**
- * Returns the node with ID $id and all its children, sorted accoring to
- * the `Breadth-first sorting`_ algorithm.
- *
- * @param string $id
- * @return ezcTreeNodeList
- */
- public function fetchSubtreeBreadthFirst( $nodeId )
- {
+ $this->addChildNodesDepthFirst( $list, $childMemoryNode );
+ }
}
/**
@@ -185,7 +163,53 @@
$list = new ezcTreeNodeList;
$memoryNode = $this->getNodeById( $nodeId );
$list->addNode( $memoryNode->node );
- $this->addChildNodes( $list, $memoryNode );
+ $this->addChildNodesDepthFirst( $list, $memoryNode );
+ return $list;
+ }
+
+ /**
+ * Alias for fetchSubtreeDepthFirst().
+ *
+ * @param string $id
+ * @return ezcTreeNodeList
+ */
+ public function fetchSubtree( $nodeId )
+ {
+ return $this->fetchSubtreeDepthFirst( $nodeId );
+ }
+
+ /**
+ * Adds the children nodes of the node $memoryNode to the
+ * ezcTreeNodeList $list.
+ *
+ * @param ezcTreeNodeList $list
+ * @param string $nodeId
+ */
+ private function addChildNodesBreadthFirst( ezcTreeNodeList $list,
ezcTreeMemoryNode $memoryNode )
+ {
+ foreach ( $memoryNode->children as $id => $childMemoryNode )
+ {
+ $list->addNode( $childMemoryNode->node );
+ }
+ foreach ( $memoryNode->children as $id => $childMemoryNode )
+ {
+ $this->addChildNodesBreadthFirst( $list, $childMemoryNode );
+ }
+ }
+
+ /**
+ * Returns the node with ID $id and all its children, sorted accoring to
+ * the `Breadth-first sorting`_ algorithm.
+ *
+ * @param string $id
+ * @return ezcTreeNodeList
+ */
+ public function fetchSubtreeBreadthFirst( $nodeId )
+ {
+ $list = new ezcTreeNodeList;
+ $memoryNode = $this->getNodeById( $nodeId );
+ $list->addNode( $memoryNode->node );
+ $this->addChildNodesBreadthFirst( $list, $memoryNode );
return $list;
}
Modified: trunk/Tree/src/backends/xml.php
==============================================================================
--- trunk/Tree/src/backends/xml.php [iso-8859-1] (original)
+++ trunk/Tree/src/backends/xml.php [iso-8859-1] Thu Aug 2 11:05:25 2007
@@ -216,36 +216,14 @@
* @param ezcTreeNodeList $list
* @param string $nodeId
*/
- private function addChildNodes( ezcTreeNodeList $list, $nodeId )
+ private function addChildNodesDepthFirst( ezcTreeNodeList $list, $nodeId )
{
$className = $this->properties['nodeClassName'];
foreach ( $this->fetchChildIds( $nodeId ) as $childId )
{
$list->addNode( new $className( $this, $childId ) );
- $this->addChildNodes( $list, $childId );
- }
- }
-
- /**
- * Alias for fetchSubtreeDepthFirst().
- *
- * @param string $id
- * @return ezcTreeNodeList
- */
- public function fetchSubtree( $nodeId )
- {
- return $this->fetchSubtreeDepthFirst( $nodeId );
- }
-
- /**
- * Returns the node with ID $id and all its children, sorted accoring to
- * the `Breadth-first sorting`_ algorithm.
- *
- * @param string $id
- * @return ezcTreeNodeList
- */
- public function fetchSubtreeBreadthFirst( $nodeId )
- {
+ $this->addChildNodesDepthFirst( $list, $childId );
+ }
}
/**
@@ -260,7 +238,55 @@
$className = $this->properties['nodeClassName'];
$list = new ezcTreeNodeList;
$list->addNode( new $className( $this, $nodeId ) );
- $this->addChildNodes( $list, $nodeId );
+ $this->addChildNodesDepthFirst( $list, $nodeId );
+ return $list;
+ }
+
+ /**
+ * Alias for fetchSubtreeDepthFirst().
+ *
+ * @param string $id
+ * @return ezcTreeNodeList
+ */
+ public function fetchSubtree( $nodeId )
+ {
+ return $this->fetchSubtreeDepthFirst( $nodeId );
+ }
+
+ /**
+ * Adds the children nodes of the node with ID $nodeId to the
+ * ezcTreeNodeList $list.
+ *
+ * @param ezcTreeNodeList $list
+ * @param string $nodeId
+ */
+ private function addChildNodesBreadthFirst( ezcTreeNodeList $list, $nodeId
)
+ {
+ $className = $this->properties['nodeClassName'];
+ $childIds = $this->fetchChildIds( $nodeId );
+ foreach ( $childIds as $childId )
+ {
+ $list->addNode( new $className( $this, $childId ) );
+ }
+ foreach ( $childIds as $childId )
+ {
+ $this->addChildNodesDepthFirst( $list, $childId );
+ }
+ }
+
+ /**
+ * Returns the node with ID $id and all its children, sorted accoring to
+ * the `Breadth-first sorting`_ algorithm.
+ *
+ * @param string $id
+ * @return ezcTreeNodeList
+ */
+ public function fetchSubtreeBreadthFirst( $nodeId )
+ {
+ $className = $this->properties['nodeClassName'];
+ $list = new ezcTreeNodeList;
+ $list->addNode( new $className( $this, $nodeId ) );
+ $this->addChildNodesBreadthFirst( $list, $nodeId );
return $list;
}
Modified: trunk/Tree/src/tree_node.php
==============================================================================
--- trunk/Tree/src/tree_node.php [iso-8859-1] (original)
+++ trunk/Tree/src/tree_node.php [iso-8859-1] Thu Aug 2 11:05:25 2007
@@ -170,6 +170,17 @@
}
/**
+ * Returns this node and all its children, sorted accoring to the
+ * Depth-first sorting algorithm.
+ *
+ * @return ezcTreeNodeList
+ */
+ public function fetchSubtreeDepthFirst()
+ {
+ return $this->tree->fetchSubtreeDepthFirst( $this->id );
+ }
+
+ /**
* Alias for fetchSubtreeDepthFirst().
*
* @see fetchSubtreeDepthFirst
@@ -192,17 +203,6 @@
}
/**
- * Returns this node and all its children, sorted accoring to the
- * Depth-first sorting algorithm.
- *
- * @return ezcTreeNodeList
- */
- public function fetchSubtreeDepthFirst()
- {
- return $this->tree->fetchSubtreeDepthFirst( $this->id );
- }
-
- /**
* Returns the number of direct children of this node
*
* @return int
Modified: trunk/Tree/tests/db_parent_child_tree.php
==============================================================================
--- trunk/Tree/tests/db_parent_child_tree.php [iso-8859-1] (original)
+++ trunk/Tree/tests/db_parent_child_tree.php [iso-8859-1] Thu Aug 2 11:05:25
2007
@@ -26,6 +26,18 @@
protected function tearDown()
{
+ }
+
+ protected function setUpEmptyTestTree()
+ {
+ $store = new ezcTreeDbExternalTableDataStore( $this->dbh, 'data',
'id', 'data' );
+ $tree = new ezcTreeDbParentChild(
+ $this->dbh,
+ 'parent_child',
+ $store
+ );
+ $this->emptyTables();
+ return $tree;
}
protected function setUpTestTree()
Modified: trunk/Tree/tests/memory_tree.php
==============================================================================
--- trunk/Tree/tests/memory_tree.php [iso-8859-1] (original)
+++ trunk/Tree/tests/memory_tree.php [iso-8859-1] Thu Aug 2 11:05:25 2007
@@ -18,9 +18,15 @@
{
private $tempDir;
+ protected function setUpEmptyTestTree()
+ {
+ $tree = ezcTreeMemory::create( new ezcTreeMemoryDataStore() );
+ return $tree;
+ }
+
protected function setUpTestTree()
{
- $tree = ezcTreeMemory::create( new ezcTreeMemoryDataStore() );
+ $tree = $this->setUpEmptyTestTree();
$tree->setRootNode( $root = $tree->createNode( 1, 'Node 1' ) );
$root->addChild( $node2 = $tree->createNode( 2, 'Node 2' ) );
Modified: trunk/Tree/tests/tree.php
==============================================================================
--- trunk/Tree/tests/tree.php [iso-8859-1] (original)
+++ trunk/Tree/tests/tree.php [iso-8859-1] Thu Aug 2 11:05:25 2007
@@ -384,6 +384,54 @@
self::assertSame( '8', $nodeList[8]->id );
}
+ public function testTreeFetchSubtreeBreadthFirstOnNode()
+ {
+ $tree = $this->setUpTestTree();
+
+ $nodeList = $tree->fetchNodeById( 4 )->fetchSubtreeBreadthFirst();
+ self::assertSame( 4, $nodeList->size );
+ self::assertSame( '4', $nodeList[4]->id );
+ self::assertSame( '6', $nodeList[6]->id );
+ self::assertSame( '7', $nodeList[7]->id );
+ self::assertSame( '8', $nodeList[8]->id );
+ }
+
+ public function testTreeFetchSubtreeBreadthFirstOnTree()
+ {
+ $tree = $this->setUpTestTree();
+
+ $nodeList = $tree->fetchSubtreeBreadthFirst( 4 );
+ self::assertSame( 4, $nodeList->size );
+ self::assertSame( '4', $nodeList[4]->id );
+ self::assertSame( '6', $nodeList[6]->id );
+ self::assertSame( '7', $nodeList[7]->id );
+ self::assertSame( '8', $nodeList[8]->id );
+ }
+
+ public function testTreeFetchSubtreeDepthFirstOnNode()
+ {
+ $tree = $this->setUpTestTree();
+
+ $nodeList = $tree->fetchNodeById( 4 )->fetchSubtreeDepthFirst();
+ self::assertSame( 4, $nodeList->size );
+ self::assertSame( '4', $nodeList[4]->id );
+ self::assertSame( '6', $nodeList[6]->id );
+ self::assertSame( '7', $nodeList[7]->id );
+ self::assertSame( '8', $nodeList[8]->id );
+ }
+
+ public function testTreeFetchSubtreeDepthFirstOnTree()
+ {
+ $tree = $this->setUpTestTree();
+
+ $nodeList = $tree->fetchSubtreeDepthFirst( 4 );
+ self::assertSame( 4, $nodeList->size );
+ self::assertSame( '4', $nodeList[4]->id );
+ self::assertSame( '6', $nodeList[6]->id );
+ self::assertSame( '7', $nodeList[7]->id );
+ self::assertSame( '8', $nodeList[8]->id );
+ }
+
public function testTreeFetchChildrenOnNode()
{
$tree = $this->setUpTestTree();
@@ -705,6 +753,162 @@
}
}
}
+
+ private function addTestData( $tree )
+ {
+ $primates = array(
+ 'Hominoidea' => array(
+ 'Hylobatidae' => array(
+ 'Hylobates' => array(
+ 'Lar Gibbon',
+ 'Agile Gibbon',
+ 'Müller\'s Bornean Gibbon',
+ 'Silvery Gibbon',
+ 'Pileated Gibbon',
+ 'Kloss\'s Gibbon',
+ ),
+ 'Hoolock' => array(
+ 'Western Hoolock Gibbon',
+ 'Eastern Hoolock Gibbon',
+ ),
+ 'Symphalangus' => array(),
+ 'Nomascus' => array(
+ 'Black Crested Gibbon',
+ 'Eastern Black Crested Gibbon',
+ 'White-cheecked Crested Gibbon',
+ 'Yellow-cheecked Gibbon',
+ ),
+ ),
+ 'Hominidae' => array(
+ 'Pongo' => array(
+ 'Bornean Orangutan',
+ 'Sumatran Orangutan',
+ ),
+ 'Gorilla' => array(
+ 'Western Gorilla' => array(
+ 'Western Lowland Gorilla',
+ 'Cross River Gorilla',
+ ),
+ 'Eastern Gorilla' => array(
+ 'Mountain Gorilla',
+ 'Eastern Lowland Gorilla',
+ ),
+ ),
+ 'Homo' => array(
+ 'Homo Sapiens' => array(
+ 'Homo Sapiens Sapiens'
+ ),
+ ),
+ 'Pan' => array(
+ 'Common Chimpanzee',
+ 'Bonobo',
+ ),
+ ),
+ ),
+ );
+
+ $root = $tree->createNode( 'Hominoidea', 'Hominoidea' );
+ $tree->setRootNode( $root );
+
+ $this->addChildren( $root, $primates['Hominoidea'] );
+ }
+
+ private function addChildren( ezcTreeNode $node, array $children )
+ {
+ foreach( $children as $name => $child )
+ {
+ if ( is_array( $child ) )
+ {
+ $newNode = $node->tree->createNode( $name, $name );
+ $node->addChild( $newNode );
+ $this->addChildren( $newNode, $child );
+ }
+ else
+ {
+ $newNode = $node->tree->createNode( $child, $child );
+ $node->addChild( $newNode );
+ }
+ }
+ }
+
+ public function testTreeCreateExtensive()
+ {
+ $tree = $this->setUpEmptyTestTree();
+ self::assertSame( false, $tree->nodeExists( '1' ) );
+ $this->addTestData( $tree );
+
+ self::assertSame( true, $tree->nodeExists( 'Homo Sapiens Sapiens' ) );
+ self::assertSame( true, $tree->isDecendantOf( 'Common Chimpanzee',
'Hominoidea' ) );
+ self::assertSame( 4, $tree->getChildCount( 'Hominidae' ) );
+ self::assertSame( 16, $tree->getChildCountRecursive( 'Hominidae' ) );
+ self::assertSame( true, $tree->isSiblingOf( 'Gorilla', 'Homo' ) );
+ }
+
+ public function testTreeFetchSubtreeDepthFirst()
+ {
+ $tree = $this->setUpEmptyTestTree();
+ $this->addTestData( $tree );
+
+ $expected = array(
+ 'Gorilla', 'Western Gorilla', 'Western Lowland Gorilla',
+ 'Cross River Gorilla', 'Eastern Gorilla', 'Mountain Gorilla',
+ 'Eastern Lowland Gorilla'
+ );
+ $list = $tree->fetchSubtreeDepthFirst( 'Gorilla' );
+ $nodes = $list->getNodes();
+ self::assertSame( 7, $list->size );
+ self::assertSame( 7, count( $nodes ) );
+
+ // test with fetched nodes as base
+ reset( $expected );
+ foreach ( $nodes as $key => $item )
+ {
+ self::assertSame( current( $expected ), $key );
+ next( $expected );
+ }
+
+ // test with expected array as base
+ reset( $nodes );
+ foreach( $expected as $key )
+ {
+ self::assertType( 'ezcTreeNode', current( $nodes ) );
+ self::assertSame( current( $nodes )->id, $key );
+ next( $nodes );
+ }
+ }
+
+ public function testTreeFetchSubtreeBreadthFirst()
+ {
+ $tree = $this->setUpEmptyTestTree();
+ $this->addTestData( $tree );
+
+ $expected = array(
+ 'Gorilla', 'Western Gorilla', 'Eastern Gorilla',
+ 'Western Lowland Gorilla', 'Cross River Gorilla',
+ 'Mountain Gorilla', 'Eastern Lowland Gorilla'
+ );
+ $list = $tree->fetchSubtreeBreadthFirst( 'Gorilla' );
+ $nodes = $list->getNodes();
+ self::assertSame( 7, $list->size );
+ self::assertSame( 7, count( $nodes ) );
+
+ // test with fetched nodes as base
+ reset( $expected );
+ foreach ( $nodes as $key => $item )
+ {
+ self::assertSame( current( $expected ), $key );
+ next( $expected );
+ }
+
+ // test with expected array as base
+ reset( $nodes );
+ foreach( $expected as $key )
+ {
+ self::assertType( 'ezcTreeNode', current( $nodes ) );
+ self::assertSame( current( $nodes )->id, $key );
+ next( $nodes );
+ }
+ }
}
?>
Modified: trunk/Tree/tests/xml_tree.php
==============================================================================
--- trunk/Tree/tests/xml_tree.php [iso-8859-1] (original)
+++ trunk/Tree/tests/xml_tree.php [iso-8859-1] Thu Aug 2 11:05:25 2007
@@ -26,6 +26,15 @@
protected function tearDown()
{
$this->removeTempDir();
+ }
+
+ protected function setUpEmptyTestTree()
+ {
+ $tree = ezcTreeXml::create(
+ $this->tempDir . '/test.xml',
+ new ezcTreeXmlInternalDataStore()
+ );
+ return $tree;
}
protected function setUpTestTree()
--
svn-components mailing list
[email protected]
http://lists.ez.no/mailman/listinfo/svn-components