Author: dr Date: Wed Aug 15 14:14:39 2007 New Revision: 5920 Log: - Added the copy() method to copy a tree, including all nodes and associated data, to a new (empty) tree.
Added: trunk/Tree/tests/copy_tree.php (with props) trunk/TreeDatabaseTiein/tests/copy_tree.php (with props) trunk/TreeDatabaseTiein/tests/files/all-types.dba Modified: trunk/DatabaseSchema/src/handlers/xml/xmlwritersubstitute.php trunk/Tree/src/backends/xml.php trunk/Tree/src/tree.php trunk/Tree/tests/suite.php trunk/TreeDatabaseTiein/tests/suite.php Modified: trunk/DatabaseSchema/src/handlers/xml/xmlwritersubstitute.php ============================================================================== --- trunk/DatabaseSchema/src/handlers/xml/xmlwritersubstitute.php [iso-8859-1] (original) +++ trunk/DatabaseSchema/src/handlers/xml/xmlwritersubstitute.php [iso-8859-1] Wed Aug 15 14:14:39 2007 @@ -15,7 +15,7 @@ * @version //autogentag// * @access private */ -class XMLWriter +class XMLWriterX { private $elementStack; private $uriFs = false; 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] Wed Aug 15 14:14:39 2007 @@ -107,6 +107,8 @@ $dom = new DomDocument(); $dom->load( $xmlFile ); + $dom->formatOutput = true; + $errors = libxml_get_errors(); libxml_clear_errors(); if ( count( $errors ) ) @@ -141,6 +143,7 @@ public static function create( $xmlFile, ezcTreeXmlDataStore $store ) { $dom = new DomDocument( '1.0', 'utf-8' ); + $dom->formatOutput = true; $element = $dom->createElement( 'tree' ); $element->setAttributeNode( new DOMAttr( 'xmlns', 'http://components.ez.no/Tree' ) ); Modified: trunk/Tree/src/tree.php ============================================================================== --- trunk/Tree/src/tree.php [iso-8859-1] (original) +++ trunk/Tree/src/tree.php [iso-8859-1] Wed Aug 15 14:14:39 2007 @@ -350,6 +350,52 @@ abstract public function move( $nodeId, $targetParentId ); /** + * Copies all the children of node $fromNode to node $toNode recursively. + * + * This method copies all children recursively from $fromNode to $toNode. + * The $fromNode belongs to the $from tree and the $toNode to the $to tree. + * Data associated with the nodes is copied as well from the store + * associated with the $from tree to the $to tree. + * + * @param ezcTree $from + * @param ezcTree $to + * @param ezcTreeNode $fromNode + * @param ezcTreeNode $toNode + */ + private static function copyChildren( ezcTree $from, ezcTree $to, ezcTreeNode $fromNode, ezcTreeNode $toNode ) + { + $children = $fromNode->fetchChildren(); + foreach( new ezcTreeNodeListIterator( $from, $children, true ) as $childNodeKey => $childNodeData ) + { + $fromChildNode = $from->fetchNodeById( $childNodeKey ); + $toChildNode = new ezcTreeNode( $to, $childNodeKey, $childNodeData ); + $toNode->addChild( $toChildNode ); + self::copyChildren( $from, $to, $fromChildNode, $toChildNode ); + } + } + + /** + * Copies the tree in $from to the empty tree in $to. + * + * This method copies all the nodes, including associated data from the + * used data store, from the tree $from to the tree $to. Because this + * function uses internally setRootNode() the target tree will be cleared + * out automatically. The method will not check whether the $from and $to + * trees share the same database table or data store, so make sure they are + * different to prevent unexpected behavior. + * + * @param ezcTree $from + * @param ezcTree $to + */ + public static function copy( ezcTree $from, ezcTree $to ) + { + $fromRootNode = $from->getRootNode(); + $to->setRootNode( new ezcTreeNode( $to, $fromRootNode->id, $fromRootNode->data ) ); + $toRootNode = $to->getRootNode(); + self::copyChildren( $from, $to, $fromRootNode, $toRootNode ); + } + + /** * Starts an transaction in which all tree modifications are queued until * the transaction is committed with the commit() method. */ Added: trunk/Tree/tests/copy_tree.php ============================================================================== --- trunk/Tree/tests/copy_tree.php (added) +++ trunk/Tree/tests/copy_tree.php [iso-8859-1] Wed Aug 15 14:14:39 2007 @@ -1,0 +1,148 @@ +<?php +/** + * @copyright Copyright (C) 2005-2007 eZ systems as. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + * @version //autogentag// + * @filesource + * @package Tree + * @subpackage Tests + */ + +/** + * @package Tree + * @subpackage Tests + */ +class ezcTreeCopyTest extends ezcTestCase +{ + protected function setUp() + { + static $i = 0; + + $this->tempDir = $this->createTempDir( __CLASS__ . sprintf( '_%03d_', ++$i ) ) . '/'; + $this->storeFromXml = new ezcTreeXmlInternalDataStore(); + $this->storeFromMem = new ezcTreeMemoryDataStore(); + $this->storeToXml = new ezcTreeXmlInternalDataStore(); + $this->storeToMem = new ezcTreeMemoryDataStore(); + } + + protected 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', + 'Homo Superior' + ), + ), + '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 ); + } + } + } + + protected function doCopyTest( $treeFrom, $treeTo ) + { + ezcTree::copy( $treeFrom, $treeTo ); + + self::assertSame( 35, $treeFrom->getChildCountRecursive( 'Hominoidea' ) ); + self::assertSame( 35, $treeTo->getChildCountRecursive( 'Hominoidea' ) ); + + $pathFrom = $treeFrom->fetchPath( 'Homo Superior' ); + $pathTo = $treeTo->fetchPath( 'Homo Superior' ); + self::assertEquals( 5, $pathFrom->size ); + self::assertEquals( 5, $pathTo->size ); + self::assertSame( array_keys( $pathFrom->nodes ), array_keys( $pathTo->nodes ) ); + + $node = $treeFrom->fetchNodeById( 'Müller\'s Bornean Gibbon' ); + self::assertSame( "Müller's Bornean Gibbon", $node->data ); + + $node = $treeTo->fetchNodeById( 'Müller\'s Bornean Gibbon' ); + self::assertSame( "Müller's Bornean Gibbon", $node->data ); + } + + public function testTreeMemoryToXML() + { + $treeFrom = ezcTreeMemory::create( $this->storeFromMem ); + $this->addTestData( $treeFrom ); + $treeTo = ezcTreeXml::create( $this->tempDir . 'testTreeMemoryToXML.xml', $this->storeToXml ); + self::doCopyTest( $treeFrom, $treeTo ); + } + + public function testTreeXmlToMemory() + { + $treeFrom = ezcTreeXml::create( $this->tempDir . 'testTreeMemoryToXML.xml', $this->storeFromXml ); + $this->addTestData( $treeFrom ); + $treeTo = ezcTreeMemory::create( $this->storeToMem ); + self::doCopyTest( $treeFrom, $treeTo ); + } + + public static function suite() + { + return new PHPUnit_Framework_TestSuite( "ezcTreeCopyTest" ); + } +} + +?> Propchange: trunk/Tree/tests/copy_tree.php ------------------------------------------------------------------------------ svn:eol-style = native Modified: trunk/Tree/tests/suite.php ============================================================================== --- trunk/Tree/tests/suite.php [iso-8859-1] (original) +++ trunk/Tree/tests/suite.php [iso-8859-1] Wed Aug 15 14:14:39 2007 @@ -19,6 +19,7 @@ require_once 'visitor.php'; require_once 'memory_tree.php'; require_once 'xml_tree.php'; +require_once 'copy_tree.php'; /** * @package Tree @@ -38,6 +39,7 @@ $this->addTest( ezcTreeVisitorTest::suite() ); $this->addTest( ezcTreeMemoryTest::suite() ); $this->addTest( ezcTreeXmlTest::suite() ); + $this->addTest( ezcTreeCopyTest::suite() ); } public static function suite() Added: trunk/TreeDatabaseTiein/tests/copy_tree.php ============================================================================== --- trunk/TreeDatabaseTiein/tests/copy_tree.php (added) +++ trunk/TreeDatabaseTiein/tests/copy_tree.php [iso-8859-1] Wed Aug 15 14:14:39 2007 @@ -1,0 +1,153 @@ +<?php +/** + * @copyright Copyright (C) 2005-2007 eZ systems as. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + * @version //autogentag// + * @filesource + * @package Tree + * @subpackage Tests + */ + +require_once 'Tree/tests/copy_tree.php'; + +/** + * @package Tree + * @subpackage Tests + */ +class ezcTreeDbCopyTest extends ezcTreeCopyTest +{ + protected $tables = array( 'materialized_path', 'nested_set', 'parent_child', 'data', 'datam' ); + + protected function setUp() + { + static $i = 0; + + $this->tempDir = $this->createTempDir( __CLASS__ . sprintf( '_%03d_', ++$i ) ) . '/'; + try + { + $this->dbh = ezcDbInstance::get(); + $this->removeTables(); + $this->loadSchemas(); + } + catch ( Exception $e ) + { + $this->markTestSkipped( $e->getMessage() ); + } + $this->storeFrom = new ezcTreeDbExternalTableDataStore( $this->dbh, 'dataFrom', 'id', 'data' ); + $this->storeTo = new ezcTreeDbExternalTableDataStore( $this->dbh, 'dataTo', 'id', 'data' ); + $this->storeFromXml = new ezcTreeXmlInternalDataStore(); + $this->storeFromMem = new ezcTreeMemoryDataStore(); + $this->storeToXml = new ezcTreeXmlInternalDataStore(); + $this->storeToMem = new ezcTreeMemoryDataStore(); + } + + protected function tearDown() + { + $this->removeTempDir(); + } + + private function loadSchemas() + { + $schema = ezcDbSchema::createFromFile( 'array', dirname( __FILE__ ) . "/files/all-types.dba" ); + $schema->writeToDb( $this->dbh ); + } + + protected function emptyTables() + { + $db = $this->dbh; + + foreach ( $this->tables as $table ) + { + $q = $db->createDeleteQuery(); + $q->deleteFrom( $table ); + $s = $q->prepare(); + $s->execute(); + } + } + + protected function removeTables() + { + try + { + foreach ( $this->tables as $table ) + { + $this->dbh->exec( "DROP TABLE $table" ); + } + } + catch ( Exception $e ) + { + // ignore + } + } + + public function testTreeParentChildToMaterializedPath() + { + $treeFrom = new ezcTreeDbParentChild( $this->dbh, 'parent_child', $this->storeFrom ); + $this->addTestData( $treeFrom ); + $treeTo = new ezcTreeDbMaterializedPath( $this->dbh, 'materialized_path', $this->storeTo ); + self::doCopyTest( $treeFrom, $treeTo ); + } + + public function testTreeParentChildToNestedSet() + { + $treeFrom = new ezcTreeDbParentChild( $this->dbh, 'parent_child', $this->storeFrom ); + $this->addTestData( $treeFrom ); + $treeTo = new ezcTreeDbNestedSet( $this->dbh, 'nested_set', $this->storeTo ); + self::doCopyTest( $treeFrom, $treeTo ); + } + + public function testTreeParentChildToXML() + { + $treeFrom = new ezcTreeDbParentChild( $this->dbh, 'parent_child', $this->storeFrom ); + $this->addTestData( $treeFrom ); + $treeTo = ezcTreeXml::create( $this->tempDir . 'testTreeParentChildToXML.xml', $this->storeToXml ); + self::doCopyTest( $treeFrom, $treeTo ); + } + + public function testTreeParentChildToMemory() + { + $treeFrom = new ezcTreeDbParentChild( $this->dbh, 'parent_child', $this->storeFrom ); + $this->addTestData( $treeFrom ); + $treeTo = ezcTreeMemory::create( $this->storeToMem ); + self::doCopyTest( $treeFrom, $treeTo ); + } + + public function testTreeMaterializedPathToParentChild() + { + $treeFrom = new ezcTreeDbMaterializedPath( $this->dbh, 'materialized_path', $this->storeFrom ); + $this->addTestData( $treeFrom ); + $treeTo = new ezcTreeDbParentChild( $this->dbh, 'parent_child', $this->storeTo ); + self::doCopyTest( $treeFrom, $treeTo ); + } + + public function testTreeMaterializedPathToNestedSet() + { + $treeFrom = new ezcTreeDbMaterializedPath( $this->dbh, 'materialized_path', $this->storeFrom ); + $this->addTestData( $treeFrom ); + $treeTo = new ezcTreeDbNestedSet( $this->dbh, 'nested_set', $this->storeTo ); + self::doCopyTest( $treeFrom, $treeTo ); + } + + public function testTreeNestedSetToMaterializedPath() + { + $treeFrom = new ezcTreeDbNestedSet( $this->dbh, 'nested_set', $this->storeFrom ); + $this->addTestData( $treeFrom ); + $treeTo = new ezcTreeDbMaterializedPath( $this->dbh, 'materialized_path', $this->storeTo ); + self::doCopyTest( $treeFrom, $treeTo ); + } + + public function testTreeNestedSetToParentChild() + { + $treeFrom = new ezcTreeDbNestedSet( $this->dbh, 'nested_set', $this->storeFrom ); + $this->addTestData( $treeFrom ); + $treeTo = new ezcTreeDbParentChild( $this->dbh, 'parent_child', $this->storeTo ); + self::doCopyTest( $treeFrom, $treeTo ); + } + + public static function suite() + { + return new PHPUnit_Framework_TestSuite( "ezcTreeDbCopyTest" ); + } +} + +?> Propchange: trunk/TreeDatabaseTiein/tests/copy_tree.php ------------------------------------------------------------------------------ svn:eol-style = native Added: trunk/TreeDatabaseTiein/tests/files/all-types.dba ============================================================================== --- trunk/TreeDatabaseTiein/tests/files/all-types.dba (added) +++ trunk/TreeDatabaseTiein/tests/files/all-types.dba [iso-8859-1] Wed Aug 15 14:14:39 2007 @@ -1,0 +1,268 @@ +<?php +return array ( + 0 => + array ( + 'materialized_path' => + ezcDbSchemaTable::__set_state(array( + 'fields' => + array ( + 'id' => + ezcDbSchemaField::__set_state(array( + 'type' => 'text', + 'length' => 128, + 'notNull' => true, + 'default' => NULL, + 'autoIncrement' => false, + 'unsigned' => false, + )), + 'parent_id' => + ezcDbSchemaField::__set_state(array( + 'type' => 'text', + 'length' => 128, + 'notNull' => false, + 'default' => NULL, + 'autoIncrement' => false, + 'unsigned' => false, + )), + 'path' => + ezcDbSchemaField::__set_state(array( + 'type' => 'text', + 'length' => 1000, + 'notNull' => true, + 'default' => NULL, + 'autoIncrement' => false, + 'unsigned' => false, + )), + ), + 'indexes' => + array ( + 'primary' => + ezcDbSchemaIndex::__set_state(array( + 'indexFields' => + array ( + 'id' => + ezcDbSchemaIndexField::__set_state(array( + 'sorting' => NULL, + )), + ), + 'primary' => true, + 'unique' => true, + )), + 'path' => + ezcDbSchemaIndex::__set_state(array( + 'indexFields' => + array ( + 'path' => + ezcDbSchemaIndexField::__set_state(array( + 'sorting' => NULL, + )), + ), + 'primary' => false, + 'unique' => true, + )), + ), + )), + 'nested_set' => + ezcDbSchemaTable::__set_state(array( + 'fields' => + array ( + 'id' => + ezcDbSchemaField::__set_state(array( + 'type' => 'text', + 'length' => 128, + 'notNull' => true, + 'default' => NULL, + 'autoIncrement' => false, + 'unsigned' => false, + )), + 'parent_id' => + ezcDbSchemaField::__set_state(array( + 'type' => 'text', + 'length' => 128, + 'notNull' => false, + 'default' => NULL, + 'autoIncrement' => false, + 'unsigned' => false, + )), + 'lft' => + ezcDbSchemaField::__set_state(array( + 'type' => 'integer', + 'length' => 0, + 'notNull' => true, + 'default' => NULL, + 'autoIncrement' => false, + 'unsigned' => false, + )), + 'rgt' => + ezcDbSchemaField::__set_state(array( + 'type' => 'integer', + 'length' => 0, + 'notNull' => true, + 'default' => NULL, + 'autoIncrement' => false, + 'unsigned' => false, + )), + ), + 'indexes' => + array ( + 'primary' => + ezcDbSchemaIndex::__set_state(array( + 'indexFields' => + array ( + 'id' => + ezcDbSchemaIndexField::__set_state(array( + 'sorting' => NULL, + )), + ), + 'primary' => true, + 'unique' => true, + )), + 'lft' => + ezcDbSchemaIndex::__set_state(array( + 'indexFields' => + array ( + 'lft' => + ezcDbSchemaIndexField::__set_state(array( + 'sorting' => NULL, + )), + ), + 'primary' => false, + 'unique' => false, + )), + 'rgt' => + ezcDbSchemaIndex::__set_state(array( + 'indexFields' => + array ( + 'rgt' => + ezcDbSchemaIndexField::__set_state(array( + 'sorting' => NULL, + )), + ), + 'primary' => false, + 'unique' => false, + )), + ), + )), + 'parent_child' => + ezcDbSchemaTable::__set_state(array( + 'fields' => + array ( + 'id' => + ezcDbSchemaField::__set_state(array( + 'type' => 'text', + 'length' => 128, + 'notNull' => true, + 'default' => NULL, + 'autoIncrement' => false, + 'unsigned' => false, + )), + 'parent_id' => + ezcDbSchemaField::__set_state(array( + 'type' => 'text', + 'length' => 128, + 'notNull' => false, + 'default' => NULL, + 'autoIncrement' => false, + 'unsigned' => false, + )), + ), + 'indexes' => + array ( + 'primary' => + ezcDbSchemaIndex::__set_state(array( + 'indexFields' => + array ( + 'id' => + ezcDbSchemaIndexField::__set_state(array( + 'sorting' => NULL, + )), + ), + 'primary' => true, + 'unique' => true, + )), + ), + )), + 'dataFrom' => + ezcDbSchemaTable::__set_state(array( + 'fields' => + array ( + 'id' => + ezcDbSchemaField::__set_state(array( + 'type' => 'text', + 'length' => 128, + 'notNull' => true, + 'default' => NULL, + 'autoIncrement' => false, + 'unsigned' => false, + )), + 'data' => + ezcDbSchemaField::__set_state(array( + 'type' => 'text', + 'length' => 255, + 'notNull' => true, + 'default' => NULL, + 'autoIncrement' => false, + 'unsigned' => false, + )), + ), + 'indexes' => + array ( + 'primary' => + ezcDbSchemaIndex::__set_state(array( + 'indexFields' => + array ( + 'id' => + ezcDbSchemaIndexField::__set_state(array( + 'sorting' => NULL, + )), + ), + 'primary' => true, + 'unique' => true, + )), + ), + )), + 'dataTo' => + ezcDbSchemaTable::__set_state(array( + 'fields' => + array ( + 'id' => + ezcDbSchemaField::__set_state(array( + 'type' => 'text', + 'length' => 128, + 'notNull' => true, + 'default' => NULL, + 'autoIncrement' => false, + 'unsigned' => false, + )), + 'data' => + ezcDbSchemaField::__set_state(array( + 'type' => 'text', + 'length' => 255, + 'notNull' => true, + 'default' => NULL, + 'autoIncrement' => false, + 'unsigned' => false, + )), + ), + 'indexes' => + array ( + 'primary' => + ezcDbSchemaIndex::__set_state(array( + 'indexFields' => + array ( + 'id' => + ezcDbSchemaIndexField::__set_state(array( + 'sorting' => NULL, + )), + ), + 'primary' => true, + 'unique' => true, + )), + ), + )), + ), + 1 => + array( + ), +); ?> + Modified: trunk/TreeDatabaseTiein/tests/suite.php ============================================================================== --- trunk/TreeDatabaseTiein/tests/suite.php [iso-8859-1] (original) +++ trunk/TreeDatabaseTiein/tests/suite.php [iso-8859-1] Wed Aug 15 14:14:39 2007 @@ -15,6 +15,7 @@ require_once 'db_materialized_path_tree.php'; require_once 'db_nested_set_tree.php'; require_once 'db_parent_child_tree.php'; +require_once 'copy_tree.php'; /** * @package TreeDatabaseTiein @@ -30,6 +31,7 @@ $this->addTest( ezcTreeDbMaterializedPathTest::suite() ); $this->addTest( ezcTreeDbNestedSetTest::suite() ); $this->addTest( ezcTreeDbParentChildTest::suite() ); + $this->addTest( ezcTreeDbCopyTest::suite() ); } public static function suite() -- svn-components mailing list svn-components@lists.ez.no http://lists.ez.no/mailman/listinfo/svn-components