Author: dr
Date: Mon Jan  7 16:58:04 2008
New Revision: 7088

Log:
- Implemented issue #12139: Allow tree node keys to be auto-generated.

Added:
    trunk/Tree/docs/files/royals.xml
    trunk/Tree/docs/tutorial_example_create_auto_id.php   (with props)
    trunk/TreeDatabaseTiein/src/exceptions/
    trunk/TreeDatabaseTiein/src/exceptions/invalid_schema.php   (with props)
Modified:
    trunk/Tree/ChangeLog
    trunk/Tree/docs/tutorial.txt
    trunk/Tree/src/backends/memory.php
    trunk/Tree/src/backends/xml.php
    trunk/Tree/src/tree.php
    trunk/Tree/tests/tree.php
    trunk/Tree/tests/xml_tree.php
    trunk/TreeDatabaseTiein/ChangeLog
    trunk/TreeDatabaseTiein/DEPS
    trunk/TreeDatabaseTiein/design/class_diagram.png
    trunk/TreeDatabaseTiein/src/backends/db.php
    trunk/TreeDatabaseTiein/src/backends/db_materialized_path.php
    trunk/TreeDatabaseTiein/src/backends/db_nested_set.php
    trunk/TreeDatabaseTiein/src/backends/db_parent_child.php
    trunk/TreeDatabaseTiein/src/tree_db_autoload.php
    trunk/TreeDatabaseTiein/tests/db_materialized_path_tree.php
    trunk/TreeDatabaseTiein/tests/db_materialized_path_tree_diff_separator.php
    trunk/TreeDatabaseTiein/tests/db_nested_set_tree.php
    trunk/TreeDatabaseTiein/tests/db_parent_child_tree.php
    trunk/TreeDatabaseTiein/tests/files/materialized_path.dba
    trunk/TreeDatabaseTiein/tests/files/nested_set.dba
    trunk/TreeDatabaseTiein/tests/files/parent_child.dba

Modified: trunk/Tree/ChangeLog
==============================================================================
--- trunk/Tree/ChangeLog [iso-8859-1] (original)
+++ trunk/Tree/ChangeLog [iso-8859-1] Mon Jan  7 16:58:04 2008
@@ -1,3 +1,9 @@
+1.1alpha1 - [RELEASEDATE]
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Implemented issue #12139: Allow tree node keys to be auto-generated.
+
+
 1.0 - Monday 17 December 2007
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 

Added: trunk/Tree/docs/files/royals.xml
==============================================================================
--- trunk/Tree/docs/files/royals.xml (added)
+++ trunk/Tree/docs/files/royals.xml [iso-8859-1] Mon Jan  7 16:58:04 2008
@@ -1,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<tree xmlns="http://components.ez.no/Tree"; 
xmlns:etd="http://components.ez.no/Tree/data"; prefix="id" lastNodeId="8">
+  <node id="id1">
+    <etd:data>Beatrix</etd:data>
+    <node id="id2">
+      <etd:data>Willem-Alexander</etd:data>
+      <node id="id4">
+        <etd:data>Catharina</etd:data>
+      </node>
+      <node id="id5">
+        <etd:data>Alexia</etd:data>
+      </node>
+      <node id="id6">
+        <etd:data>Ariane</etd:data>
+      </node>
+    </node>
+    <node id="id3">
+      <etd:data>Friso</etd:data>
+      <node id="id7">
+        <etd:data>Luana</etd:data>
+      </node>
+      <node id="id8">
+        <etd:data>Zaria</etd:data>
+      </node>
+    </node>
+  </node>
+</tree>

Modified: trunk/Tree/docs/tutorial.txt
==============================================================================
--- trunk/Tree/docs/tutorial.txt [iso-8859-1] (original)
+++ trunk/Tree/docs/tutorial.txt [iso-8859-1] Mon Jan  7 16:58:04 2008
@@ -164,6 +164,27 @@
 ezcTreeDbExternalTableDataStore->__construct().  Lines 10 to 13 proceed to add
 two new nodes to the $rootNode and lines 15-26 add further nodes to the
 $nonMetal and $nobleGasses nodes.
+
+Auto-generated IDs
+``````````````````
+
+The Tree component also supports auto-generated IDs for tree nodes. In order to
+let the component generate IDs for you, you need to set the Tree property
+"autoId" to "true". In the example below we create another tree structure, but
+let the Tree component generate the IDs automatically:
+
+.. include:: tutorial_example_create_auto_id.php
+   :literal:
+
+The main change compared to the previous example is the setting of autoId to
+true in line 6. When autoId is set, the ID argument to ezcTree::createNode()
+can be null. In that case an ID is automatically generated.
+
+This property *must* be set immediately after instantiating the tree, unless an
+already existing tree is opened through the ezcTreeXml class. For database
+backends, there are a few extra requirements for the schema. The "id" field
+should be defined as an auto-increment integer field, or an integer field
+linked with a sequence.
 
 
 Back-ends

Added: trunk/Tree/docs/tutorial_example_create_auto_id.php
==============================================================================
--- trunk/Tree/docs/tutorial_example_create_auto_id.php (added)
+++ trunk/Tree/docs/tutorial_example_create_auto_id.php [iso-8859-1] Mon Jan  7 
16:58:04 2008
@@ -1,0 +1,24 @@
+<?php
+require_once 'tutorial_autoload.php';
+
+$store = new ezcTreeXmlInternalDataStore();
+$tree = ezcTreeXml::create( 'files/royals.xml', $store );
+$tree->autoId = true;
+
+$rootNode = $tree->createNode( null, 'Beatrix' );
+$tree->setRootNode( $rootNode );
+
+$willem = $tree->createNode( null, 'Willem-Alexander' );
+$rootNode->addChild( $willem );
+$friso = $tree->createNode( null, 'Friso' );
+$rootNode->addChild( $friso );
+
+echo $friso->id, "\n";
+
+$willem->addChild( $tree->createNode( null, 'Catharina' ) );
+$willem->addChild( $tree->createNode( null, 'Alexia' ) );
+$willem->addChild( $tree->createNode( null, 'Ariane' ) );
+
+$friso->addChild( $tree->createNode( null, 'Luana' ) );
+$friso->addChild( $tree->createNode( null, 'Zaria' ) );
+?>

Propchange: trunk/Tree/docs/tutorial_example_create_auto_id.php
------------------------------------------------------------------------------
    svn:eol-style = native

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] Mon Jan  7 16:58:04 2008
@@ -53,6 +53,13 @@
     private $rootNode;
 
     /**
+     * Stores the last auto generated ID that was used.
+     *
+     * @var integer $autoNodeId
+     */
+    private $autoNodeId = 0;
+
+    /**
      * Constructs a new ezcTreeMemory object.
      *
      * The store that is used for data storage should be passed as the
@@ -63,6 +70,18 @@
     protected function __construct( ezcTreeMemoryDataStore $store )
     {
         $this->properties['store'] = $store;
+        $this->properties['autoId'] = false;
+    }
+
+    /**
+     * This method generates the next node ID.
+     *
+     * @return integer
+     */
+    protected function generateNodeID()
+    {
+        $this->autoNodeId++;
+        return $this->autoNodeId;
     }
 
     /**

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] Mon Jan  7 16:58:04 2008
@@ -59,6 +59,11 @@
         </attribute>
       </optional>
       <optional>
+        <attribute name="lastNodeId">
+          <data type="string"/>
+        </attribute>
+      </optional>
+      <optional>
         <ref name="node"/>
       </optional>
     </element>
@@ -99,6 +104,13 @@
     private $xmlFile;
 
     /**
+     * Stores the last auto generated ID that was used.
+     *
+     * @var integer $autoNodeId
+     */
+    private $autoNodeId = 0;
+
+    /**
      * Constructs a new ezcTreeXml object from the XML data in $xmlFile and 
using
      * the $store to retrieve data from.
      *
@@ -141,12 +153,21 @@
         // Figure out the prefix - which is the "prefix" attribute on the root 
node.
         $document = $dom->documentElement;
         $prefix = $document->getAttribute( 'prefix' );
+
+        // Figure out the last auto generated ID
+        $autoId = false;
+        $this->autoNodeId = $document->getAttribute( 'lastNodeId' );
+        if ( $this->autoNodeId !== "" )
+        {
+            $autoId = true;
+        }
 
         // Set member variables
         $this->dom = $dom;
         $this->xmlFile = $xmlFile;
         $this->properties['store'] = $store;
         $this->properties['prefix'] = $prefix;
+        $this->properties['autoId'] = $autoId;
     }
 
     /**
@@ -244,6 +265,25 @@
     public function saveFile()
     {
         $this->dom->save( $this->xmlFile );
+    }
+
+    /**
+     * This method generates the next node ID.
+     *
+     * It uses the stored last generated ID, and also stores this in an
+     * attribute on the root node so that it can be correctly incremented
+     * without having to search for the last generated ID in the whole tree.
+     *
+     * @return integer
+     */
+    protected function generateNodeID()
+    {
+        $this->autoNodeId++;
+
+        $document = $this->dom->documentElement;
+        $document->setAttributeNode( new DOMAttr( 'lastNodeId', 
$this->autoNodeId ) );
+
+        return $this->autoNodeId;
     }
 
     /**

Modified: trunk/Tree/src/tree.php
==============================================================================
--- trunk/Tree/src/tree.php [iso-8859-1] (original)
+++ trunk/Tree/src/tree.php [iso-8859-1] Mon Jan  7 16:58:04 2008
@@ -48,6 +48,9 @@
  * @property      string              $nodeClassName
  *                Which class is used as tree node - this class *must* inherit
  *                the ezcTreeNode class.
+ * @property      boolean             $autoId
+ *                When set to true, you can add nodes to the database without
+ *                setting the ID. This only works with numeric keys however.
  * 
  * @package Tree
  * @version //autogentag//
@@ -122,6 +125,14 @@
             case 'store':
                 throw new ezcBasePropertyPermissionException( $name, 
ezcBasePropertyPermissionException::READ );
 
+            case 'autoId':
+                if ( !is_bool( $value ) )
+                {
+                    throw new ezcBaseValueException( $name, $value, 'boolean' 
);
+                }
+                $this->properties[$name] = $value;
+                break;
+
             case 'nodeClassName':
                 if ( !is_string( $value ) )
                 {
@@ -156,6 +167,7 @@
     {
         switch ( $name )
         {
+            case 'autoId':
             case 'store':
             case 'nodeClassName':
                 return isset( $this->properties[$name] );
@@ -176,6 +188,13 @@
     {
         /* The default implementation does not check anything */
     }
+
+    /**
+     * This method generates the next node ID.
+     *
+     * @return integer
+     */
+    abstract protected function generateNodeID();
 
     /**
      * Creates a new tree node with node ID $nodeId and $data.
@@ -191,6 +210,17 @@
      */
     public function createNode( $nodeId, $data )
     {
+        if ( $nodeId === null )
+        {
+            if ( $this->properties['autoId'] )
+            {
+                $nodeId = $this->generateNodeID();
+            }
+            else
+            {
+                throw new ezcTreeInvalidIdException( null, '' );
+            }
+        }
         $this->checkNodeID( $nodeId );
         $className = $this->properties['nodeClassName'];
         return new $className( $this, $nodeId, $data );
@@ -219,7 +249,7 @@
      * Returns the node identified by the ID $nodeId.
      *
      * @param string $nodeId
-     * @throws ezcTreeInvalidIdException if there is no node with ID $nodeId
+     * @throws ezcTreeUnknownIdException if there is no node with ID $nodeId
      * @return ezcTreeNode
      */
     public function fetchNodeById( $nodeId )

Modified: trunk/Tree/tests/tree.php
==============================================================================
--- trunk/Tree/tests/tree.php [iso-8859-1] (original)
+++ trunk/Tree/tests/tree.php [iso-8859-1] Mon Jan  7 16:58:04 2008
@@ -17,7 +17,7 @@
  * @package Tree
  * @subpackage Tests
  */
-class ezcTreeTest extends ezcTestCase
+abstract class ezcTreeTest extends ezcTestCase
 {
     public function testGetRootNode1()
     {
@@ -955,6 +955,60 @@
             next( $nodes );
         }
     }
+
+    public function testTreeNullIdWithoutAutogen()
+    {
+        $tree = $this->setUpEmptyTestTree();
+        try
+        {
+            $root = $tree->createNode( null, 'Hominoidea' );
+            self::fail( "Expected exception not thrown" );
+        }
+        catch ( ezcTreeInvalidIdException $e )
+        {
+            self::assertSame( "The node ID '' contains the invalid character 
''.", $e->getMessage() );
+        }
+    }
+
+    public function testTreeNullIdWithAutogen()
+    {
+        $tree = $this->setUpEmptyTestTree( 'data', 'data', '_auto' );
+        $tree->autoId = true;
+        $root = $tree->createNode( null, 'Paenungulata' );
+        self::assertSame( "1", $root->id );
+        $tree->setRootNode( $root );
+
+        $newNode = $tree->createNode( null, 'Hyracoidea' );
+        $root->addChild( $newNode );
+        self::assertSame( "2", $newNode->id );
+
+        $newNode = $tree->createNode( null, 'Proboscidea' );
+        $root->addChild( $newNode );
+        self::assertSame( "3", $newNode->id );
+    }
+
+    public function testTreeNullIdWithAutogenWithReload()
+    {
+        $tree = $this->setUpEmptyTestTree( 'data', 'data', '_auto' );
+        $tree->autoId = true;
+        $root = $tree->createNode( null, 'Paenungulata' );
+        $tree->setRootNode( $root );
+
+        $newNode = $tree->createNode( null, 'Hyracoidea' );
+        $root->addChild( $newNode );
+
+        $newNode = $tree->createNode( null, 'Proboscidea' );
+        $root->addChild( $newNode );
+        self::assertSame( "3", $newNode->id );
+
+        // start over
+        $tree = $this->setUpTestTree( 'data', 'data', '_auto' );
+        $tree->autoId = true;
+
+        // fetch a node
+        $node = $tree->fetchNodeById( 3 );
+    }
+
 }
 
 ?>

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] Mon Jan  7 16:58:04 2008
@@ -250,6 +250,78 @@
         self::assertSame( "Camels", $camelus->data );
     }
 
+    public function testReloadAutoGenId()
+    {
+        $tree = ezcTreeXml::create(
+            $this->tempDir . '/new-tree.xml', 
+            new ezcTreeXmlInternalDataStore()
+        );
+        $tree->autoId = true;
+
+        $root = $tree->createNode( null, "Camelinae" );
+        $tree->setRootNode( $root );
+
+        $root->addChild( $tree->createNode( null, "Lama" ) );
+        $root->addChild( $tree->createNode( null, "Vicugna" ) );
+        $root->addChild( $tree->createNode( null, "Camelus" ) );
+
+        // start over
+        $tree = new ezcTreeXml(
+            $this->tempDir . '/new-tree.xml', 
+            new ezcTreeXmlInternalDataStore()
+        );
+
+        $root = $tree->getRootNode();
+        $newNode = $tree->createNode( null, "Oempa" );
+        $root->addChild( $newNode );
+
+        $camelus = $tree->fetchNodeById( 5 );
+        self::assertSame( "Oempa", $camelus->data );
+    }
+
+    public function testReloadAutoGenIdWithPrefix()
+    {
+        $tree = ezcTreeXml::create(
+            $this->tempDir . '/new-tree.xml', 
+            new ezcTreeXmlInternalDataStore(),
+            'ezc'
+        );
+        $tree->autoId = true;
+
+        $root = $tree->createNode( null, "Camelinae" );
+        $tree->setRootNode( $root );
+
+        $root->addChild( $tree->createNode( null, "Lama" ) );
+        $root->addChild( $tree->createNode( null, "Vicugna" ) );
+        $root->addChild( $tree->createNode( null, "Camelus" ) );
+
+        // start over
+        $tree = new ezcTreeXml(
+            $this->tempDir . '/new-tree.xml', 
+            new ezcTreeXmlInternalDataStore()
+        );
+        $root = $tree->getRootNode();
+        $newNode = $tree->createNode( null, "Oempa" );
+        $root->addChild( $newNode );
+
+        $camelus = $tree->fetchNodeById( 5 );
+        self::assertSame( "Oempa", $camelus->data );
+
+        // start over
+        $tree = new ezcTreeXml(
+            $this->tempDir . '/new-tree.xml', 
+            new ezcTreeXmlInternalDataStore()
+        );
+        $root = $tree->fetchNodeById( 5 );
+        $newNode = $tree->createNode( null, "Loempa" );
+        $root->addChild( $newNode );
+
+        $camelus = $tree->fetchNodeById( 5 );
+        self::assertSame( "Oempa", $camelus->data );
+        $camelus = $tree->fetchNodeById( 6 );
+        self::assertSame( "Loempa", $camelus->data );
+    }
+
     public static function suite()
     {
          return new PHPUnit_Framework_TestSuite( "ezcTreeXmlTest" );

Modified: trunk/TreeDatabaseTiein/ChangeLog
==============================================================================
--- trunk/TreeDatabaseTiein/ChangeLog [iso-8859-1] (original)
+++ trunk/TreeDatabaseTiein/ChangeLog [iso-8859-1] Mon Jan  7 16:58:04 2008
@@ -1,3 +1,9 @@
+1.1alpha1 - [RELEASEDATE]
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Implemented issue #12139: Allow tree node keys to be auto-generated.
+
+
 1.0 - Monday 17 December 2007
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 

Modified: trunk/TreeDatabaseTiein/DEPS
==============================================================================
--- trunk/TreeDatabaseTiein/DEPS [iso-8859-1] (original)
+++ trunk/TreeDatabaseTiein/DEPS [iso-8859-1] Mon Jan  7 16:58:04 2008
@@ -1,2 +1,2 @@
-Tree: 1.0
+Tree: 1.1alpha1
 Database: 1.3

Modified: trunk/TreeDatabaseTiein/design/class_diagram.png
==============================================================================
Binary files - no diff available.

Modified: trunk/TreeDatabaseTiein/src/backends/db.php
==============================================================================
--- trunk/TreeDatabaseTiein/src/backends/db.php [iso-8859-1] (original)
+++ trunk/TreeDatabaseTiein/src/backends/db.php [iso-8859-1] Mon Jan  7 
16:58:04 2008
@@ -57,6 +57,68 @@
         $this->dbh = $dbh;
         $this->indexTableName = $indexTableName;
         $this->properties['store'] = $store;
+        $this->properties['autoId'] = false;
+    }
+
+    /**
+     * Creates the query to insert an empty node into the database, so that 
the last-inserted ID can be obtained.
+     *
+     * @return ezcQueryInsert
+     */
+    abstract protected function createAddEmptyNodeQuery();
+
+    /**
+     * Creates the query to insert/update an empty node in the database.
+     *
+     * The query is constructed for the child with ID $id
+     *
+     * @param mixed $id
+     * @return ezcQuery
+     */
+    protected function createAddNodeQuery( $id )
+    {
+        $db = $this->dbh;
+
+        if ( $this->properties['autoId'] )
+        {
+            $q = $db->createUpdateQuery();
+            $q->update( $db->quoteIdentifier( $this->indexTableName ) )
+              ->where( $q->expr->eq( 'id', $q->bindValue( $id ) ) );
+        }
+        else
+        {
+            $q = $db->createInsertQuery();
+            $q->insertInto( $db->quoteIdentifier( $this->indexTableName ) );
+        }
+        return $q;
+    }
+
+    /**
+     * This method generates the next node ID.
+     *
+     * It does so by inserting a new empty node into the database, and uses
+     * lastInsertId() to obtain the ID for the newly inserted node.
+     *
+     * @return integer
+     */
+    protected function generateNodeID()
+    {
+        $db = $this->dbh;
+        $q = $this->createAddEmptyNodeQuery();
+
+        $s = $q->prepare();
+
+        try
+        {
+            $s->execute();
+        }
+        catch ( PDOException $e )
+        {
+            throw new ezcTreeDbInvalidSchemaException( "generating a new node 
ID", $e->getMessage() );
+        }
+
+        $r = $db->lastInsertId( $this->indexTableName . '_id_seq' );
+        return $r;
     }
 
     /**

Modified: trunk/TreeDatabaseTiein/src/backends/db_materialized_path.php
==============================================================================
--- trunk/TreeDatabaseTiein/src/backends/db_materialized_path.php [iso-8859-1] 
(original)
+++ trunk/TreeDatabaseTiein/src/backends/db_materialized_path.php [iso-8859-1] 
Mon Jan  7 16:58:04 2008
@@ -20,6 +20,9 @@
  * Supported field types are either integer or a string type. The third field
  * 'path' will contain the path string. This should be a text field. The size
  * of the field determines the maximum depth the tree can have.
+ * In order to use auto-generated IDs, the 'id' field needs to be an
+ * auto-incrementing integer field, by using either an auto-increment field, or
+ * a sequence.
  *
  * @property-read ezcTreeDbDataStore $store
  *                The data store that is used for retrieving/storing data.
@@ -494,6 +497,22 @@
     }
 
     /**
+     * Creates the query to insert an empty node into the database, so that 
the last-inserted ID can be obtained.
+     *
+     * @return ezcQueryInsert
+     */
+    protected function createAddEmptyNodeQuery()
+    {
+        $db = $this->dbh;
+
+        $q = $db->createInsertQuery();
+        $q->insertInto( $db->quoteIdentifier( $this->indexTableName ) )
+          ->set( 'path', 0 );
+
+        return $q;
+    }
+
+    /**
      * Adds the node $childNode as child of the node with ID $parentId.
      *
      * @param string $parentId
@@ -512,9 +531,8 @@
         // Fetch parent information
         list( $parentParentId, $path ) = $this->fetchNodeInformation( 
$parentId );
 
-        $q = $db->createInsertQuery();
-        $q->insertInto( $db->quoteIdentifier( $this->indexTableName ) )
-          ->set( 'parent_id', $q->bindValue( $parentId ) )
+        $q = $this->createAddNodeQuery( $childNode->id );
+        $q->set( 'parent_id', $q->bindValue( $parentId ) )
           ->set( 'id', $q->bindValue( $childNode->id ) )
           ->set( 'path', $q->bindValue( $path . 
$this->properties['separationChar'] . $childNode->id ) );
         $s = $q->prepare();

Modified: trunk/TreeDatabaseTiein/src/backends/db_nested_set.php
==============================================================================
--- trunk/TreeDatabaseTiein/src/backends/db_nested_set.php [iso-8859-1] 
(original)
+++ trunk/TreeDatabaseTiein/src/backends/db_nested_set.php [iso-8859-1] Mon Jan 
 7 16:58:04 2008
@@ -20,6 +20,9 @@
  * Supported field types are either integer or a string type.  The other two
  * fields "lft" and "rgt" will store the left and right values that the
  * algorithm requires. These two fields should be of an integer type.
+ * In order to use auto-generated IDs, the 'id' field needs to be an
+ * auto-incrementing integer field, by using either an auto-increment field, or
+ * a sequence.
  *
  * @property-read ezcTreeDbDataStore $store
  *                The data store that is used for retrieving/storing data.
@@ -201,6 +204,23 @@
     }
 
     /**
+     * Creates the query to insert an empty node into the database, so that 
the last-inserted ID can be obtained.
+     *
+     * @return ezcQueryInsert
+     */
+    protected function createAddEmptyNodeQuery()
+    {
+        $db = $this->dbh;
+
+        $q = $db->createInsertQuery();
+        $q->insertInto( $db->quoteIdentifier( $this->indexTableName ) )
+          ->set( 'lft', 0 )
+          ->set( 'rgt', 0 );
+
+        return $q;
+    }
+
+    /**
      * Updates the left and right values of the nodes that are added while
      * adding a whole subtree as child of a node.
      *
@@ -285,9 +305,8 @@
         //     id = $childNode->id,
         //     lft = $newLeft,
         //     rgt = $newRight
-        $q = $db->createInsertQuery();
-        $q->insertInto( $db->quoteIdentifier( $this->indexTableName ) )
-          ->set( 'parent_id', $q->bindValue( $parentId ) )
+        $q = $this->createAddNodeQuery( $childNode->id );
+        $q->set( 'parent_id', $q->bindValue( $parentId ) )
           ->set( 'id', $q->bindValue( $childNode->id ) )
           ->set( 'lft', $q->bindValue( $newLeft ) )
           ->set( 'rgt', $q->bindValue( $newRight ) );

Modified: trunk/TreeDatabaseTiein/src/backends/db_parent_child.php
==============================================================================
--- trunk/TreeDatabaseTiein/src/backends/db_parent_child.php [iso-8859-1] 
(original)
+++ trunk/TreeDatabaseTiein/src/backends/db_parent_child.php [iso-8859-1] Mon 
Jan  7 16:58:04 2008
@@ -18,6 +18,9 @@
  * first one 'id' will contain the node's ID, the second one 'parent_id' the ID
  * of the node's parent. Both fields should be of the same database field type.
  * Supported field types are either integer or a string type.
+ * In order to use auto-generated IDs, the 'id' field needs to be an
+ * auto-incrementing integer field, by using either an auto-increment field, or
+ * a sequence.
  *
  * @property-read ezcTreeDbDataStore $store
  *                The data store that is used for retrieving/storing data.
@@ -366,6 +369,22 @@
     }
 
     /**
+     * Creates the query to insert an empty node into the database, so that 
the last-inserted ID can be obtained.
+     *
+     * @return ezcQueryInsert
+     */
+    protected function createAddEmptyNodeQuery()
+    {
+        $db = $this->dbh;
+
+        $q = $db->createInsertQuery();
+        $q->insertInto( $db->quoteIdentifier( $this->indexTableName ) )
+          ->set( 'parent_id', $q->bindValue( null ) );
+
+        return $q;
+    }
+
+    /**
      * Adds the node $childNode as child of the node with ID $parentId.
      *
      * @param string $parentId
@@ -379,11 +398,8 @@
             return;
         }
 
-        $db = $this->dbh;
-
-        $q = $db->createInsertQuery();
-        $q->insertInto( $db->quoteIdentifier( $this->indexTableName ) )
-          ->set( 'parent_id', $q->bindValue( $parentId ) )
+        $q = $this->createAddNodeQuery( $childNode->id );
+        $q->set( 'parent_id', $q->bindValue( $parentId ) )
           ->set( 'id', $q->bindValue( $childNode->id ) );
         $s = $q->prepare();
         $s->execute();

Added: trunk/TreeDatabaseTiein/src/exceptions/invalid_schema.php
==============================================================================
--- trunk/TreeDatabaseTiein/src/exceptions/invalid_schema.php (added)
+++ trunk/TreeDatabaseTiein/src/exceptions/invalid_schema.php [iso-8859-1] Mon 
Jan  7 16:58:04 2008
@@ -1,0 +1,32 @@
+<?php
+/**
+ * File containing the ezcTreeDbInvalidSchemaException
+ *
+ * @copyright Copyright (C) 2005-2008 eZ systems as. All rights reserved.
+ * @license http://ez.no/licenses/new_bsd New BSD License
+ * @version //autogentag//
+ * @filesource
+ * @package Tree
+ */
+
+/**
+ * Exception that is thrown when an incompatible schema is detected with
+ * one of the Tree operations.
+ *
+ * @package Tree
+ * @version //autogentag//
+ */
+class ezcTreeDbInvalidSchemaException extends ezcTreeException
+{
+    /**
+     * Constructs a new ezcTreeDbInvalidSchemaException
+     *
+     * @param string $operation
+     * @param string $message
+     */
+    public function __construct( $operation, $message )
+    {
+        parent::__construct( "While {$operation}, an incompatible schema was 
found: {$message}." );
+    }
+}
+?>

Propchange: trunk/TreeDatabaseTiein/src/exceptions/invalid_schema.php
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: trunk/TreeDatabaseTiein/src/tree_db_autoload.php
==============================================================================
--- trunk/TreeDatabaseTiein/src/tree_db_autoload.php [iso-8859-1] (original)
+++ trunk/TreeDatabaseTiein/src/tree_db_autoload.php [iso-8859-1] Mon Jan  7 
16:58:04 2008
@@ -10,6 +10,7 @@
  */
 
 return array(
+    'ezcTreeDbInvalidSchemaException' => 
'TreeDatabaseTiein/exceptions/invalid_schema.php',
     'ezcTreeDb'                       => 'TreeDatabaseTiein/backends/db.php',
     'ezcTreeDbDataStore'              => 'TreeDatabaseTiein/stores/db.php',
     'ezcTreeDbParentChild'            => 
'TreeDatabaseTiein/backends/db_parent_child.php',

Modified: trunk/TreeDatabaseTiein/tests/db_materialized_path_tree.php
==============================================================================
--- trunk/TreeDatabaseTiein/tests/db_materialized_path_tree.php [iso-8859-1] 
(original)
+++ trunk/TreeDatabaseTiein/tests/db_materialized_path_tree.php [iso-8859-1] 
Mon Jan  7 16:58:04 2008
@@ -50,24 +50,24 @@
         }
     }
 
-    protected function setUpEmptyTestTree( $dataTable = 'data', $dataField = 
'data' )
+    protected function setUpEmptyTestTree( $dataTable = 'data', $dataField = 
'data', $indexTableSuffix = '' )
     {
         $store = new ezcTreeDbExternalTableDataStore( $this->dbh, $dataTable, 
'id', $dataField );
         $tree = ezcTreeDbMaterializedPath::create(
             $this->dbh,
-            'materialized_path',
+            'materialized_path' . $indexTableSuffix,
             $store
         );
         $this->emptyTables();
         return $tree;
     }
 
-    protected function setUpTestTree( $dataTable = 'data', $dataField = 'data' 
)
+    protected function setUpTestTree( $dataTable = 'data', $dataField = 
'data', $indexTableSuffix = '' )
     {
         $store = new ezcTreeDbExternalTableDataStore( $this->dbh, $dataTable, 
'id', $dataField );
         $tree = new ezcTreeDbMaterializedPath(
             $this->dbh,
-            'materialized_path',
+            'materialized_path' . $indexTableSuffix,
             $store
         );
         return $tree;

Modified: 
trunk/TreeDatabaseTiein/tests/db_materialized_path_tree_diff_separator.php
==============================================================================
--- trunk/TreeDatabaseTiein/tests/db_materialized_path_tree_diff_separator.php 
[iso-8859-1] (original)
+++ trunk/TreeDatabaseTiein/tests/db_materialized_path_tree_diff_separator.php 
[iso-8859-1] Mon Jan  7 16:58:04 2008
@@ -48,12 +48,12 @@
         }
     }
 
-    protected function setUpEmptyTestTree( $dataTable = 'data', $dataField = 
'data' )
+    protected function setUpEmptyTestTree( $dataTable = 'data', $dataField = 
'data', $indexTableSuffix = '' )
     {
         $store = new ezcTreeDbExternalTableDataStore( $this->dbh, $dataTable, 
'id', $dataField );
         $tree = ezcTreeDbMaterializedPath::create(
             $this->dbh,
-            'materialized_path',
+            'materialized_path' . $indexTableSuffix,
             $store,
             '@'
         );
@@ -61,12 +61,12 @@
         return $tree;
     }
 
-    protected function setUpTestTree( $dataTable = 'data', $dataField = 'data' 
)
+    protected function setUpTestTree( $dataTable = 'data', $dataField = 
'data', $indexTableSuffix = '' )
     {
         $store = new ezcTreeDbExternalTableDataStore( $this->dbh, $dataTable, 
'id', $dataField );
         $tree = new ezcTreeDbMaterializedPath(
             $this->dbh,
-            'materialized_path',
+            'materialized_path' . $indexTableSuffix,
             $store,
             '@'
         );

Modified: trunk/TreeDatabaseTiein/tests/db_nested_set_tree.php
==============================================================================
--- trunk/TreeDatabaseTiein/tests/db_nested_set_tree.php [iso-8859-1] (original)
+++ trunk/TreeDatabaseTiein/tests/db_nested_set_tree.php [iso-8859-1] Mon Jan  
7 16:58:04 2008
@@ -50,24 +50,24 @@
         }
     }
 
-    protected function setUpEmptyTestTree( $dataTable = 'data', $dataField = 
'data' )
+    protected function setUpEmptyTestTree( $dataTable = 'data', $dataField = 
'data', $indexTableSuffix = '' )
     {
         $store = new ezcTreeDbExternalTableDataStore( $this->dbh, $dataTable, 
'id', $dataField );
         $tree = ezcTreeDbNestedSet::create(
             $this->dbh,
-            'nested_set',
+            'nested_set' . $indexTableSuffix,
             $store
         );
         $this->emptyTables();
         return $tree;
     }
 
-    protected function setUpTestTree( $dataTable = 'data', $dataField = 'data' 
)
+    protected function setUpTestTree( $dataTable = 'data', $dataField = 
'data', $indexTableSuffix = '' )
     {
         $store = new ezcTreeDbExternalTableDataStore( $this->dbh, $dataTable, 
'id', $dataField );
         $tree = new ezcTreeDbNestedSet(
             $this->dbh,
-            'nested_set',
+            'nested_set' . $indexTableSuffix,
             $store
         );
         return $tree;

Modified: trunk/TreeDatabaseTiein/tests/db_parent_child_tree.php
==============================================================================
--- trunk/TreeDatabaseTiein/tests/db_parent_child_tree.php [iso-8859-1] 
(original)
+++ trunk/TreeDatabaseTiein/tests/db_parent_child_tree.php [iso-8859-1] Mon Jan 
 7 16:58:04 2008
@@ -49,24 +49,24 @@
         }
     }
 
-    protected function setUpEmptyTestTree( $dataTable = 'data', $dataField = 
'data' )
+    protected function setUpEmptyTestTree( $dataTable = 'data', $dataField = 
'data', $indexTableSuffix = '' )
     {
         $store = new ezcTreeDbExternalTableDataStore( $this->dbh, $dataTable, 
'id', $dataField );
         $tree = ezcTreeDbParentChild::create(
             $this->dbh,
-            'parent_child',
+            'parent_child' . $indexTableSuffix,
             $store
         );
         $this->emptyTables();
         return $tree;
     }
 
-    protected function setUpTestTree( $dataTable = 'data', $dataField = 'data' 
)
+    protected function setUpTestTree( $dataTable = 'data', $dataField = 
'data', $indexTableSuffix = '' )
     {
         $store = new ezcTreeDbExternalTableDataStore( $this->dbh, $dataTable, 
'id', $dataField );
         $tree = new ezcTreeDbParentChild(
             $this->dbh,
-            'parent_child',
+            'parent_child' . $indexTableSuffix,
             $store
         );
         return $tree;

Modified: trunk/TreeDatabaseTiein/tests/files/materialized_path.dba
==============================================================================
--- trunk/TreeDatabaseTiein/tests/files/materialized_path.dba [iso-8859-1] 
(original)
+++ trunk/TreeDatabaseTiein/tests/files/materialized_path.dba [iso-8859-1] Mon 
Jan  7 16:58:04 2008
@@ -62,6 +62,66 @@
         )),
       ),
     )),
+    'materialized_path_auto' => 
+    ezcDbSchemaTable::__set_state(array(
+       'fields' => 
+      array (
+        'id' => 
+        ezcDbSchemaField::__set_state(array(
+           'type' => 'integer',
+           'length' => 128,
+           'notNull' => false,
+           'default' => NULL,
+           'autoIncrement' => true,
+           '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_auto' => 
+        ezcDbSchemaIndex::__set_state(array(
+          'indexFields' => 
+          array (
+            'path' => 
+            ezcDbSchemaIndexField::__set_state(array(
+               'sorting' => NULL,
+            )),
+          ),
+          'primary' => false,
+          'unique' => true,
+        )),
+      ),
+    )),
     'data' => 
     ezcDbSchemaTable::__set_state(array(
        'fields' => 

Modified: trunk/TreeDatabaseTiein/tests/files/nested_set.dba
==============================================================================
--- trunk/TreeDatabaseTiein/tests/files/nested_set.dba [iso-8859-1] (original)
+++ trunk/TreeDatabaseTiein/tests/files/nested_set.dba [iso-8859-1] Mon Jan  7 
16:58:04 2008
@@ -83,6 +83,87 @@
         )),
       ),
     )),
+    'nested_set_auto' => 
+    ezcDbSchemaTable::__set_state(array(
+       'fields' => 
+      array (
+        'id' => 
+        ezcDbSchemaField::__set_state(array(
+           'type' => 'integer',
+           'length' => 128,
+           'notNull' => false,
+           'default' => NULL,
+           'autoIncrement' => true,
+           '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_auto' => 
+        ezcDbSchemaIndex::__set_state(array(
+          'indexFields' => 
+          array (
+            'lft' => 
+            ezcDbSchemaIndexField::__set_state(array(
+               'sorting' => NULL,
+            )),
+          ),
+          'primary' => false,
+          'unique' => false,
+        )),
+        'rgt_auto' => 
+        ezcDbSchemaIndex::__set_state(array(
+          'indexFields' => 
+          array (
+            'rgt' => 
+            ezcDbSchemaIndexField::__set_state(array(
+               'sorting' => NULL,
+            )),
+          ),
+          'primary' => false,
+          'unique' => false,
+        )),
+      ),
+    )),
     'data' => 
     ezcDbSchemaTable::__set_state(array(
        'fields' => 

Modified: trunk/TreeDatabaseTiein/tests/files/parent_child.dba
==============================================================================
--- trunk/TreeDatabaseTiein/tests/files/parent_child.dba [iso-8859-1] (original)
+++ trunk/TreeDatabaseTiein/tests/files/parent_child.dba [iso-8859-1] Mon Jan  
7 16:58:04 2008
@@ -13,6 +13,45 @@
            '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,
+        )),
+      ),
+    )),
+    'parent_child_auto' => 
+    ezcDbSchemaTable::__set_state(array(
+       'fields' => 
+      array (
+        'id' => 
+        ezcDbSchemaField::__set_state(array(
+           'type' => 'integer',
+           'length' => 128,
+           'notNull' => false,
+           'default' => NULL,
+           'autoIncrement' => true,
            'unsigned' => false,
         )),
         'parent_id' => 


-- 
svn-components mailing list
[EMAIL PROTECTED]
http://lists.ez.no/mailman/listinfo/svn-components

Reply via email to