Index: generator/classes/propel/engine/builder/om/OMBuilder.php
===================================================================
--- generator/classes/propel/engine/builder/om/OMBuilder.php	(revision 499)
+++ generator/classes/propel/engine/builder/om/OMBuilder.php	(working copy)
@@ -27,7 +27,7 @@
  * 
  * OM-building classes are those that build a PHP (or other) class to service
  * a single table.  This includes Peer classes, Entity classes, Map classes, 
- * Node classes, etc.
+ * Node classes, Nested Set classes, etc.
  * 
  * @author Hans Lellelid <hans@xmpl.org>
  * @package propel.engine.builder.om
@@ -100,8 +100,32 @@
 	 */
 	private $stubNodePeerBuilder;
 	
-	
 	/**
+	 * NestedSet object builder for current table.
+	 * @var DataModelBuilder
+	 */
+	private $nestedSetBuilder;
+
+	/**
+	 * NestedSet peer builder for current table.
+	 * @var DataModelBuilder
+	 */
+	private $nestedSetPeerBuilder;
+
+	/**
+	 * Stub nested set object builder for current table.
+	 * @var DataModelBuilder
+	 */
+	private $stubNestedSetBuilder;
+
+	/**
+	 * Stub nested set peer builder for current table.
+	 * @var DataModelBuilder
+	 */
+	private $stubNestedSetPeerBuilder;
+
+
+	/**
 	 * Returns new or existing Peer builder class for this table.
 	 * @return DataModelBuilder
 	 */
@@ -233,8 +257,56 @@
 		}
 		return $this->stubNodePeerBuilder;	
 	}
-	
+
 	/**
+	 * Returns new or existing nested set Object builder class for this table.
+	 * @return DataModelBuilder
+	 */
+	public function getNestedSetBuilder()
+	{
+		if (!isset($this->nestedSetBuilder)) {
+			$this->nestedSetBuilder = DataModelBuilder::builderFactory($this->getTable(), 'nestedset');
+		}
+		return $this->nestedSetBuilder;
+	}
+
+	/**
+	 * Returns new or existing nested set Peer builder class for this table.
+	 * @return DataModelBuilder
+	 */
+	public function getNestedSetPeerBuilder()
+	{
+		if (!isset($this->nestedSetPeerBuilder)) {
+			$this->nestedSetPeerBuilder = DataModelBuilder::builderFactory($this->getTable(), 'nestedsetpeer');
+		}
+		return $this->nestedSetPeerBuilder;
+	}
+
+	/**
+	 * Returns new or existing stub nested set Object builder class for this table.
+	 * @return DataModelBuilder
+	 */
+	public function getStubNestedSetBuilder()
+	{
+		if (!isset($this->stubNestedSetBuilder)) {
+			$this->stubNestedSetBuilder = DataModelBuilder::builderFactory($this->getTable(), 'nestedsetstub');
+		}
+		return $this->stubNestedSetBuilder;
+	}
+
+	/**
+	 * Returns new or existing stub nested set Peer builder class for this table.
+	 * @return DataModelBuilder
+	 */
+	public function getStubNestedSetPeerBuilder()
+	{
+		if (!isset($this->stubNestedSetPeerBuilder)) {
+			$this->stubNestedSetPeerBuilder = DataModelBuilder::builderFactory($this->getTable(), 'nestedsetpeerstub');
+		}
+		return $this->stubNestedSetPeerBuilder;
+	}
+
+	/**
 	 * Convenience method to return a NEW Peer class builder instance.
 	 * This is used very frequently from the peer and object builders to get
 	 * a peer builder for a RELATED table.
@@ -406,4 +478,4 @@
         return $class;
     }	
 	
-}
\ No newline at end of file
+}
Index: generator/classes/propel/engine/builder/om/php5/PHP5ExtensionNestedSetBuilder.php
===================================================================
--- generator/classes/propel/engine/builder/om/php5/PHP5ExtensionNestedSetBuilder.php	(revision 0)
+++ generator/classes/propel/engine/builder/om/php5/PHP5ExtensionNestedSetBuilder.php	(revision 0)
@@ -0,0 +1,121 @@
+<?php
+
+/*
+ *  $Id: PHP5BasicObjectBuilder.php 120 2005-06-17 02:18:41Z hans $
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the LGPL. For more information please see
+ * <http://propel.phpdb.org>.
+ */
+
+require_once 'propel/engine/builder/om/ObjectBuilder.php';
+
+/**
+ * Generates the empty PHP5 stub nested set object class for user object model (OM).
+ * 
+ * This class produces the empty stub class that can be customized with application
+ * business logic, custom behavior, etc.
+ * 
+ * @author Heltem <heltem@o2php.com>
+ * @package propel.engine.builder.om.php5
+ */
+class PHP5ExtensionNestedSetBuilder extends ObjectBuilder {
+	
+	/**
+	 * Returns the name of the current class being built.
+	 * @return string
+	 */
+	public function getClassname()
+	{
+		return $this->getTable()->getPhpName() . 'NestedSet';
+	}
+	
+	/**
+	 * Adds the include() statements for files that this class depends on or utilizes.
+	 * @param string &$script The script will be modified in this method.
+	 */
+	protected function addIncludes(&$script)
+	{
+	
+		$script .= "
+require_once '".$this->getNestedSetBuilder()->getClassFilePath()."';
+";
+		
+	} // addIncludes()
+	
+	/**
+	 * Adds class phpdoc comment and openning of class.
+	 * @param string &$script The script will be modified in this method.
+	 */
+	protected function addClassOpen(&$script)
+	{
+		
+		$table = $this->getTable();
+		$tableName = $table->getName();
+		$tableDesc = $table->getDescription();
+		
+		$baseClassname = $this->getNestedSetBuilder()->getClassname();
+		
+		$script .= "
+
+/**
+ * Skeleton subclass for representing a nested set from the '$tableName' table.
+ *
+ * $tableDesc
+ *";
+		if ($this->getBuildProperty('addTimeStamp')) {
+			$now = strftime('%c');
+			$script .= "
+ * This class was autogenerated by Propel on:
+ *
+ * $now
+ *";
+		}
+		$script .= "
+ * You should add additional methods to this class to meet the
+ * application requirements.  This class will only be generated as
+ * long as it does not already exist in the output directory.
+ *
+ * @package ".$this->getPackage()."
+ */	
+class ".$this->getClassname()." extends $baseClassname {
+";
+	}
+	
+	/**
+	 * Specifies the methods that are added as part of the stub object class.
+	 * 
+	 * By default there are no methods for the empty stub classes; override this method
+	 * if you want to change that behavior.
+	 * 
+	 * @see ObjectBuilder::addClassBody()
+	 */
+	protected function addClassBody(&$script)
+	{
+		// there is no class body
+	}
+	
+	/**
+	 * Closes class.
+	 * @param string &$script The script will be modified in this method.
+	 */	
+	protected function addClassClose(&$script)
+	{
+		$script .= "
+} // " . $this->getClassname() . "
+";
+	}
+	
+} // PHP5ExtensionObjectBuilder
Index: generator/classes/propel/engine/builder/om/php5/PHP5ExtensionNestedSetPeerBuilder.php
===================================================================
--- generator/classes/propel/engine/builder/om/php5/PHP5ExtensionNestedSetPeerBuilder.php	(revision 0)
+++ generator/classes/propel/engine/builder/om/php5/PHP5ExtensionNestedSetPeerBuilder.php	(revision 0)
@@ -0,0 +1,124 @@
+<?php
+
+/*
+ *  $Id: PHP5BasicObjectBuilder.php 120 2005-06-17 02:18:41Z hans $
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the LGPL. For more information please see
+ * <http://propel.phpdb.org>.
+ */
+
+require_once 'propel/engine/builder/om/PeerBuilder.php';
+
+/**
+ * Generates the empty PHP5 stub nested set peer class for user object model (OM).
+ * 
+ * This class produces the empty stub class that can be customized with application
+ * business logic, custom behavior, etc.
+ * 
+ * @author Heltem <heltem@o2php.com>
+ * @package propel.engine.builder.om.php5
+ */
+class PHP5ExtensionNestedSetPeerBuilder extends PeerBuilder {
+	
+	/**
+	 * Returns the name of the current class being built.
+	 * @return string
+	 */
+	public function getClassname()
+	{
+		return $this->getStubNestedSetBuilder()->getClassname() . 'Peer';
+	}
+
+	/**
+	 * Adds the include() statements for files that this class depends on or utilizes.
+	 * @param string &$script The script will be modified in this method.
+	 */
+	protected function addIncludes(&$script)
+	{
+		$script .= "
+  // include base nested set peer class
+  require_once '".$this->getNestedSetPeerBuilder()->getClassFilePath()."';
+  
+  // include nested set class
+  include_once '".$this->getStubNestedSetBuilder()->getClassFilePath()."';
+";
+	} // addIncludes()
+	
+	/**
+	 * Adds class phpdoc comment and openning of class.
+	 * @param string &$script The script will be modified in this method.
+	 */
+	protected function addClassOpen(&$script)
+	{
+		
+		$table = $this->getTable();
+		$tableName = $table->getName();
+		$tableDesc = $table->getDescription();
+		
+		$baseClassname = $this->getNestedSetPeerBuilder()->getClassname();
+		
+		$script .= "
+
+/**
+ * Skeleton subclass for performing query and update operations on nested set of the '$tableName' table.
+ *
+ * $tableDesc
+ *";
+		if ($this->getBuildProperty('addTimeStamp')) {
+			$now = strftime('%c');
+			$script .= "
+ * This class was autogenerated by Propel on:
+ *
+ * $now
+ *";
+		}
+		$script .= "
+ * You should add additional methods to this class to meet the
+ * application requirements.  This class will only be generated as
+ * long as it does not already exist in the output directory.
+ *
+ * @package ".$this->getPackage()."
+ */	
+class ".$this->getClassname()." extends $baseClassname {
+";
+	}
+	
+		/**
+	 * Specifies the methods that are added as part of the stub peer class.
+	 * 
+	 * By default there are no methods for the empty stub classes; override this method
+	 * if you want to change that behavior.
+	 * 
+	 * @see ObjectBuilder::addClassBody()
+	 */
+
+	protected function addClassBody(&$script)
+	{
+		// there is no class body
+	}
+	
+	/**
+	 * Closes class.
+	 * @param string &$script The script will be modified in this method.
+	 */	
+	protected function addClassClose(&$script)
+	{
+		$script .= "
+} // " . $this->getClassname() . "
+";
+	}
+	
+} // PHP5ExtensionPeerBuilder
Index: generator/classes/propel/engine/builder/om/php5/PHP5NestedSetBuilder.php
===================================================================
--- generator/classes/propel/engine/builder/om/php5/PHP5NestedSetBuilder.php	(revision 0)
+++ generator/classes/propel/engine/builder/om/php5/PHP5NestedSetBuilder.php	(revision 0)
@@ -0,0 +1,561 @@
+<?php
+
+/*
+ *  $Id: PHP5BasicObjectBuilder.php 157 2005-08-10 19:16:22Z hans $
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the LGPL. For more information please see
+ * <http://propel.phpdb.org>.
+ */
+
+require_once 'propel/engine/builder/om/ObjectBuilder.php';
+
+/**
+ * Generates a PHP5 tree nested set Object class for user object model (OM).
+ * 
+ * This class produces the base tree nested set object class (e.g. BaseMyTable) which contains all
+ * the custom-built accessor and setter methods.
+ * 
+ * @author Heltem <heltem@o2php.com>
+ * @package propel.engine.builder.om.php5
+ */
+class PHP5NestedSetBuilder extends ObjectBuilder {
+	
+	/**
+	 * Gets the package for the [base] object classes.
+	 * @return string
+	 */
+	public function getPackage()
+	{
+		return parent::getPackage() . ".om";
+	}
+	
+	/**
+	 * Returns the name of the current class being built.
+	 * @return string
+	 */
+	public function getClassname()
+	{
+		return $this->getBuildProperty('basePrefix') . $this->getStubNestedSetBuilder()->getClassname();
+	}
+	
+	/**
+	 * Adds the include() statements for files that this class depends on or utilizes.
+	 * @param string &$script The script will be modified in this method.
+	 */
+	protected function addIncludes(&$script)
+	{
+		$script .= "
+require_once '".$this->getStubNestedSetPeerBuilder()->getClassFilePath()."';
+require_once '".$this->getStubObjectBuilder()->getClassFilePath()."';
+";
+	} // addIncludes()
+	
+	/**
+	 * Adds class phpdoc comment and openning of class.
+	 * @param string &$script The script will be modified in this method.
+	 */
+	protected function addClassOpen(&$script)
+	{
+		
+		$table = $this->getTable();
+		$tableName = $table->getName();
+		$tableDesc = $table->getDescription();
+		
+		$script .= "
+/**
+ * Base class that represents a row from the '$tableName' table.
+ *
+ * $tableDesc
+ *";
+		if ($this->getBuildProperty('addTimeStamp')) {
+			$now = strftime('%c');
+			$script .= "
+ * This class was autogenerated by Propel on:
+ *
+ * $now
+ *";
+		}
+		$script .= "
+ * @package ".$this->getPackage()."
+ */	
+abstract class ".$this->getClassname()." extends ".$this->getStubObjectBuilder()->getClassname()." {
+";
+	}
+	
+	/**
+	 * Specifies the methods that are added as part of the basic OM class.
+	 * This can be overridden by subclasses that wish to add more methods.
+	 * @see ObjectBuilder::addClassBody()
+	 */
+	protected function addClassBody(&$script)
+	{
+		$table = $this->getTable();
+		
+		$this->addAttributes($script);
+				
+		$this->addSave($script);
+		$this->addDelete($script);
+
+		$this->addLeftGetter($script);
+		$this->addRightGetter($script);
+		
+		$this->addLeftSetter($script);
+		$this->addRightSetter($script);
+
+		$this->addLevelGetter($script);
+		$this->addLevelSetter($script);
+		
+		$this->addPathGetter($script);
+		$this->addNumberOfChildrenGetter($script);
+		$this->addNumberOfDescendantsGetter($script);
+
+		$this->addChildrenGetter($script);
+		$this->addDescendantsGetter($script);
+
+		$this->addIsRoot($script);
+		$this->addIsLeaf($script);
+		$this->addHasChildren($script);
+		$this->addHasPrevSibling($script);
+		$this->addHasNextSibling($script);
+		
+		$this->addInsertAsFirstChildOf($script);
+		$this->addInsertAsLastChildOf($script);
+		
+		$this->addInsertAsPrevSiblingOf($script);
+		$this->addInsertAsNextSiblingOf($script);
+	}
+	
+	/**
+	 * Closes class.
+	 * @param string &$script The script will be modified in this method.
+	 */	
+	protected function addClassClose(&$script)
+	{
+		$script .= "
+} // " . $this->getClassname() . "
+";
+	}
+	
+	
+	/**
+	 * Adds class attributes.
+	 * @param string &$script The script will be modified in this method.
+	 */
+	protected function addAttributes(&$script)
+	{
+		$script .= "
+	/**
+	 * Store level of node
+	 * @var int
+	 */
+	protected \$level = null;
+
+	/**
+	 * Store if node has prev sibling
+	 * @var bool
+	 */
+	protected \$hasPrevSibling = null;
+
+	/**
+	 * Store if node has next sibling
+	 * @var bool
+	 */
+	protected \$hasNextSibling = null;
+
+	/**
+	 * Store children of the node
+	 * @var array
+	 */
+	public \$_children = null;
+";
+	}
+
+	protected function addSave(&$script)
+	{
+	    $nestedSetPeerClassname = $this->getStubNestedSetPeerBuilder()->getClassname();
+	    $script .= "
+	/**
+	 * If object is saved without left/right values, set them as undefined (0)
+	 */
+	public function save(\$con = null)
+	{
+		\$left = \$this->getLeftValue();
+		\$right = \$this->getRightValue();
+		if(empty(\$left) || empty(\$right)) {
+			\$root = $nestedSetPeerClassname::retrieveRoot(\$con);
+      		$nestedSetPeerClassname::insertAsLastChildOf(\$root, \$this, \$con);
+		}
+
+		return parent::save(\$con);
+	}
+";
+	}
+
+	protected function addDelete(&$script)
+	{
+		$nestedSetPeerClassname = $this->getStubNestedSetPeerBuilder()->getClassname();
+		$script .= "
+	/**
+	 * Delete node and descendants
+	 */
+	public function delete(\$deleteDescendants = true, \$con = null)
+	{
+		\$right = \$this->getRightValue();
+		\$left = \$this->getLeftValue();
+
+		// delete node first
+		parent::delete(\$con);
+
+		if (\$deleteDescendants) {
+			// delete descendants and then shift tree
+			$nestedSetPeerClassname::deleteDescendants(\$left, \$right, \$con);
+		}
+	}
+";
+	}
+
+	protected function addLeftGetter(&$script)
+	{
+		$script .= "
+	/**
+	 * Wraps the getter for the left value, used by TreePeer
+	 *
+	 * @return int
+	 */
+	public function getLeftValue()
+	{
+		return \$this->getLft();
+	}
+";
+	}
+
+	protected function addRightGetter(&$script)
+	{
+		$script .= "
+	/**
+	 * Wraps the getter for the right value, used by TreePeer
+	 *
+	 * @return int
+	 */
+	public function getRightValue()
+	{
+		return \$this->getRgt();
+	}
+";
+	}
+
+	protected function addLeftSetter(&$script)
+	{
+		$script .= "
+	/**
+	 * Set the value left column
+	 *
+	 * @param int \$v new value
+	 * @return void
+	 */
+	public function setLeftValue(\$v)
+	{
+		\$this->setLft(\$v);
+	}
+";
+	}
+
+	protected function addRightSetter(&$script)
+	{
+		$script .= "
+	/**
+	 * Set the value of right column
+	 *
+	 * @param int \$v new value
+	 * @return void
+	 */
+	public function setRightValue(\$v)
+	{
+		\$this->setRgt(\$v);
+	}
+";
+	}
+
+	protected function addLevelGetter(&$script)
+	{
+		$nestedSetPeerClassname = $this->getStubNestedSetPeerBuilder()->getClassname();
+		$script .= "
+	/**
+	 * Gets the level if set, otherwise calculates this and returns it
+	 *
+	 * @return int
+	 */
+	public function getLevel(\$con = null)
+	{
+		if(\$this->level === NULL) {
+			\$this->level = $nestedSetPeerClassname::getLevel(\$this, \$con);
+		}
+		return \$this->level;
+	}
+";
+	}
+
+	protected function addLevelSetter(&$script)
+	{
+		$script .= "
+	/**
+	 * Sets the level of the node in the tree
+	 *
+	 * @param int \$v new value
+	 * @return void
+	 */
+	public function setLevel(\$level)
+	{
+		\$this->level = \$level;
+	}
+";
+	}
+
+	protected function addPathGetter(&$script)
+	{
+		$nestedSetPeerClassname = $this->getStubNestedSetPeerBuilder()->getClassname();
+		$script .= "
+	/**
+	 * Get the path to the node in the tree
+	 *
+	 * @return array
+	 */
+	public function getPath(\$con = null)
+	{
+		return $nestedSetPeerClassname::getPath(\$this);
+	}
+";
+	}
+
+	protected function addNumberOfChildrenGetter(&$script)
+	{
+		$nestedSetPeerClassname = $this->getStubNestedSetPeerBuilder()->getClassname();
+		$script .= "
+	/**
+	 * Gets the number of children for the node (direct descendants)
+	 *
+	 * @return int
+	 */
+	public function getNumberOfChildren(\$con = null)
+	{
+		return $nestedSetPeerClassname::getNumberOfChildren(\$this, \$con);
+	}
+";
+	}
+
+	protected function addNumberOfDescendantsGetter(&$script)
+	{
+		$nestedSetPeerClassname = $this->getStubNestedSetPeerBuilder()->getClassname();
+		$script .= "
+	/**
+	 * Gets the total number of desceandants for the node
+	 *
+	 * @return int
+	 */
+	public function getNumberOfDescendants(\$con = null)
+	{
+		return $nestedSetPeerClassname::getNumberOfDescendants(\$node, \$con);
+	}
+";
+	}
+
+	protected function addChildrenGetter(&$script)
+	{
+		$nestedSetPeerClassname = $this->getStubNestedSetPeerBuilder()->getClassname();
+		$script .= "
+	/**
+	 * Gets the children for the node
+	 *
+	 * @return array
+	 */
+	public function getChildren(\$con = null)
+	{
+		return $nestedSetPeerClassname::retrieveChildren(\$this, false, \$con);
+	}
+";
+	}
+
+	protected function addDescendantsGetter(&$script)
+	{
+		$nestedSetPeerClassname = $this->getStubNestedSetPeerBuilder()->getClassname();
+		$script .= "
+	/**
+	 * Gets the descendants for the node
+	 *
+	 * @return array
+	 */
+	public function getDescendants(\$con = null)
+	{
+		return $nestedSetPeerClassname::getDescendants(\$this, false, \$con);
+	}
+";
+	}
+
+	protected function addIsRoot(&$script)
+	{
+		$nestedSetPeerClassname = $this->getStubNestedSetPeerBuilder()->getClassname();
+		$script .= "
+	/**
+	 * Determines if the node is the root node
+	 *
+	 * @return bool
+	 */
+	public function isRoot()
+	{
+		return $nestedSetPeerClassname::isRoot(\$this);
+	}
+";
+	}
+
+	protected function addIsLeaf(&$script)
+	{
+		$nestedSetPeerClassname = $this->getStubNestedSetPeerBuilder()->getClassname();
+		$script .= "
+	/**
+	 * Determines if the node is a leaf node
+	 *
+	 * @return bool
+	 */
+	public function isLeaf()
+	{
+		return $nestedSetPeerClassname::isLeaf(\$this);
+	}
+";
+	}
+
+	protected function addHasChildren(&$script)
+	{
+		$nestedSetPeerClassname = $this->getStubNestedSetPeerBuilder()->getClassname();
+		$script .= "
+	/**
+	 * Determines if the node has children / descendants
+	 *
+	 * @return bool
+	 */
+	public function hasChildren()
+	{
+		return  $nestedSetPeerClassname::hasChildren(\$this);
+	}
+";
+	}
+
+	protected function addHasPrevSibling(&$script)
+	{
+		$nestedSetPeerClassname = $this->getStubNestedSetPeerBuilder()->getClassname();
+		$script .= "
+	/**
+	 * Determines if the node has previous sibling
+	 *
+	 * @return bool
+	 */
+	public function hasPrevSibling(\$con = null)
+	{
+		if(!\$this->hasPrevSibling) {
+			\$this->hasPrevSibling = $nestedSetPeerClassname::hasPrevSibling(\$this, \$con);
+		}
+		return \$this->hasPrevSibling;
+	}
+";
+	}
+
+	protected function addHasNextSibling(&$script)
+	{
+		$nestedSetPeerClassname = $this->getStubNestedSetPeerBuilder()->getClassname();
+		$script .= "
+	/**
+	 * Determines if the node has next sibling
+	 *
+	 * @return bool
+	 */
+	public function hasNextSibling(\$con = null)
+	{
+		if(!\$this->hasNextSibling) {
+			\$this->hasNextSibling = $nestedSetPeerClassname::hasNextSibling(\$this, \$con);
+		}
+		return \$this->hasNextSibling;
+	}
+";
+	}
+	
+	protected function addInsertAsFirstChildOf(&$script)
+	{
+		$nestedSetPeerClassname = $this->getStubNestedSetPeerBuilder()->getClassname();
+		$script .= "
+	/**
+	 * Inserts as first child of destination node \$dest
+	 *
+	 * @param object \$dest	Propel object for destination node
+	 * @return object		Inserted propel object for model
+	 */
+	public function insertAsFirstChildOf(\$dest, \$con = null)
+	{
+	    return $nestedSetPeerClassname::insertAsFirstChildOf(\$dest, \$this, \$con = null);
+	}
+";
+	}
+
+	protected function addInsertAsLastChildOf(&$script)
+	{
+		$nestedSetPeerClassname = $this->getStubNestedSetPeerBuilder()->getClassname();
+		$script .= "
+	/**
+	 * Inserts as last child of destination node \$dest
+	 *
+	 * @param object \$dest	Propel object for destination node
+	 * @return object		Inserted propel object for model
+	 */
+	public function insertAsLastChildOf(\$dest, \$con = null)
+	{
+	    return $nestedSetPeerClassname::insertAsLastChildOf(\$dest, \$this, \$con = null);
+	}
+";
+	}
+
+	protected function addInsertAsPrevSiblingOf(&$script)
+	{
+		$nestedSetPeerClassname = $this->getStubNestedSetPeerBuilder()->getClassname();
+		$script .= "
+	/**
+	 * Inserts \$node as previous sibling to destination node \$dest
+	 *
+	 * @param object \$dest	Propel object for destination node
+	 * @return object		Inserted propel object for model
+	 */
+	public function insertAsPrevSiblingOf(\$dest, \$con = null)
+	{
+	    return $nestedSetPeerClassname::insertAsPrevSiblingOf(\$dest, \$this, \$con = null);
+	}
+";
+	}
+
+	protected function addInsertAsNextSiblingOf(&$script)
+	{
+		$nestedSetPeerClassname = $this->getStubNestedSetPeerBuilder()->getClassname();
+		$script .= "
+	/**
+	 * Inserts \$node as next sibling to destination node \$dest
+	 *
+	 * @param object \$dest	Propel object for destination node
+	 * @return object		Inserted propel object for model
+	 */
+	public function insertAsNextSiblingOf(\$dest, \$con = null)
+	{
+	    return $nestedSetPeerClassname::insertAsNextSiblingOf(\$dest, \$this, \$con = null);
+	}
+";
+	}
+
+} // PHP5NodeObjectBuilder
Index: generator/classes/propel/engine/builder/om/php5/PHP5NestedSetPeerBuilder.php
===================================================================
--- generator/classes/propel/engine/builder/om/php5/PHP5NestedSetPeerBuilder.php	(revision 0)
+++ generator/classes/propel/engine/builder/om/php5/PHP5NestedSetPeerBuilder.php	(revision 0)
@@ -0,0 +1,1259 @@
+<?php
+
+/*
+ *  $Id: PHP5BasicObjectBuilder.php 157 2005-08-10 19:16:22Z hans $
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the LGPL. For more information please see
+ * <http://propel.phpdb.org>.
+ */
+
+require_once 'propel/engine/builder/om/PeerBuilder.php';
+
+/**
+ * Generates a PHP5 tree nested set Peer class for user object model (OM).
+ * 
+ * This class produces the base tree nested set object class (e.g. BaseMyTable) which contains all
+ * the custom-built accessor and setter methods.
+ * 
+ * This class replaces the Node.tpl, with the intent of being easier for users
+ * to customize (through extending & overriding).
+ * 
+ * @author heltem <heltem@o2php.com>
+ * @package propel.engine.builder.om.php5
+ */
+class PHP5NestedSetPeerBuilder extends PeerBuilder {
+	
+	/**
+	 * Gets the package for the [base] object classes.
+	 * @return string
+	 */
+	public function getPackage()
+	{
+		return parent::getPackage() . ".om";
+	}
+	
+	/**
+	 * Returns the name of the current class being built.
+	 * @return string
+	 */
+	public function getClassname()
+	{
+		return $this->getBuildProperty('basePrefix') . $this->getStubNestedSetPeerBuilder()->getClassname();
+	}
+	
+	/**
+	 * Adds the include() statements for files that this class depends on or utilizes.
+	 * @param string &$script The script will be modified in this method.
+	 */
+	protected function addIncludes(&$script)
+	{
+		$script .= "
+require_once '".$this->getStubObjectBuilder()->getClassFilePath()."';
+require_once '".$this->getStubPeerBuilder()->getClassFilePath()."';
+";
+	} // addIncludes()
+	
+	/**
+	 * Adds class phpdoc comment and openning of class.
+	 * @param string &$script The script will be modified in this method.
+	 */
+	protected function addClassOpen(&$script)
+	{
+		
+		$table = $this->getTable();
+		$tableName = $table->getName();
+		$tableDesc = $table->getDescription();
+		
+		$script .= "
+/**
+ * Base  static class for performing query operations on the nested set contained by the '$tableName' table.
+ *
+ * $tableDesc
+ *";
+		if ($this->getBuildProperty('addTimeStamp')) {
+			$now = strftime('%c');
+			$script .= "
+ * This class was autogenerated by Propel on:
+ *
+ * $now
+ *";
+		}
+		$script .= "
+ * @package ".$this->getPackage()."
+ */	
+abstract class ".$this->getClassname()." extends ".$this->getStubPeerBuilder()->getClassName()." {
+";
+	}
+	
+	/**
+	 * Specifies the methods that are added as part of the basic OM class.
+	 * This can be overridden by subclasses that wish to add more methods.
+	 * @see ObjectBuilder::addClassBody()
+	 */
+	protected function addClassBody(&$script)
+	{
+		$table = $this->getTable();
+		
+		// FIXME
+		// - Probably the build needs to be customized for supporting
+		// tables that are "aliases".  -- definitely a fringe usecase, though.
+						
+		$this->addConstants($script);
+		
+		$this->addCreateRoot($script);
+		
+		$this->addRetrieveRoot($script);
+
+		$this->addInsertAsFirstChildOf($script);
+		$this->addInsertAsLastChildOf($script);
+		$this->addInsertAsPrevSiblingOf($script);
+		$this->addInsertAsNextSiblingOf($script);
+
+		$this->addInsertRoot($script);
+		$this->addInsertParent($script);
+
+		$this->addDeleteRoot($script);
+		$this->addDeleteNode($script);
+
+		$this->addMoveToFirstChildOf($script);
+		$this->addMoveToLastChildOf($script);
+		$this->addMoveToPrevSiblingOf($script);
+		$this->addMoveToNextSiblingOf($script);
+		
+		$this->addRetrieveFirstChild($script);
+		$this->addRetrieveLastChild($script);
+		$this->addRetrievePrevSibling($script);
+		$this->addRetrieveNextSibling($script);
+
+		$this->addRetrieveTree($script);
+		$this->addRetrieveBranch($script);
+		$this->addRetrieveChildren($script);
+		$this->addRetrieveDescendants($script);
+		$this->addRetrieveSiblings($script);
+		$this->addRetrieveParent($script);
+		$this->addRetrieveUndefined($script);
+
+		$this->addHydrateDescendants($script);
+		$this->addHydrateChildren($script);
+		
+		$this->addLevelGetter($script);
+		$this->addNumberOfChildrenGetter($script);
+		$this->addNumberOfDescendantsGetter($script);
+		$this->addPathGetter($script);
+
+		$this->addIsValid($script);
+		$this->addIsRoot($script);
+		$this->addIsLeaf($script);
+		$this->addIsChildOf($script);
+		$this->addIsChildOfOrSiblingTo($script);
+		$this->addIsEqualTo($script);
+		
+		$this->addHasParent($script);
+		$this->addHasPrevSibling($script);
+		$this->addHasNextSibling($script);
+		$this->addHasChildren($script);
+
+		$this->addDeleteDescendants($script);
+		
+		$this->addInsertNode($script);
+		$this->addUpdateNode($script);
+		
+		$this->addShiftRLValues($script);
+		$this->addShiftRLRange($script);
+		
+		$this->AddNodeGetter($script);
+	}
+		
+	/**
+	 * Closes class.
+	 * @param string &$script The script will be modified in this method.
+	 */	
+	protected function addClassClose(&$script)
+	{
+		$script .= "
+} // " . $this->getClassname() . "
+";
+	}
+	
+	protected function addConstants(&$script)
+	{
+		$table = $this->getTable();
+		$tableName = $table->getName();
+		$dbName = $this->getDatabase()->getName();
+
+		$left_colname = '';
+		$right_colname = '';
+
+		foreach ($table->getColumns() as $col) {
+			if ($col->isNestedSetLeftKey()) {
+				$left_colname = $tableName . '.' . strtoupper($col->getName());
+			}
+
+			if ($col->isNestedSetRightKey()) {
+				$right_colname = $tableName . '.' . strtoupper($col->getName());
+			}
+
+ 			if(!empty($right_name) && !empty($left_colname)) {
+ 			    break;
+ 			}
+		}
+		$script .= "
+	/** the default database name for this class */
+	const DATABASE_NAME = '$dbName';
+
+	/** the table name for this class */
+	const TABLE_NAME = '$tableName';
+
+	/** the left column for the set */
+	const LEFT_COL = '$left_colname';
+
+	/** the right column for the set */
+	const RIGHT_COL = '$right_colname';
+";
+	}
+	
+	protected function addCreateRoot(&$script)
+	{
+		$script .= "
+	/**
+	 * Creates the supplied node as the root node.
+	 *
+	 * @param string \$node	Propel object for model
+	 * @return object		Inserted propel object for model
+	 */
+	static function createRoot(\$node, \$con = null)
+	{
+		\$newLeft = 1;
+		\$newRight = 2;
+		return self::insertNode(\$node, \$newLeft, \$newRight, \$con);
+	}
+";
+	}
+	
+	protected function addRetrieveRoot(&$script)
+	{
+		$script .= "
+	/**
+	 * Returns the root node for a given root id
+	 *
+	 * @param int \$rootId		Root id to determine which root node to return
+	 * @return object			Propel object for root node
+	 */
+	static function retrieveRoot(\$con = null)
+	{
+		\$c = new Criteria();
+		\$c->add(self::LEFT_COL, 1, Criteria::EQUAL);
+
+		return self::doSelect(\$c, 'doSelectOne', \$con);
+	}
+";
+	}
+
+	protected function addInsertAsFirstChildOf(&$script)
+	{
+		$script .= "
+	/**
+	 * Inserts \$node as first child of destination node \$dest
+	 *
+	 * @param object \$dest	Propel object for destination node
+	 * @param object \$node	Propel object for source node
+	 * @return object		Inserted propel object for model
+	 */
+	static function insertAsFirstChildOf(\$dest, \$node, \$con = null)
+	{
+		\$dest = self::getNode(\$dest, \$con);
+
+		\$newLeft = \$dest->getLeftValue() + 1;
+		\$newRight = \$dest->getLeftValue() + 2;
+		self::shiftRLValues(\$newLeft, 2, \$con);
+		\$dest->setRightValue(\$dest->getRightValue() + 2);
+		return self::insertNode(\$node, \$newLeft, \$newRight, \$con);
+	}
+";
+	}
+
+	protected function addInsertAsLastChildOf(&$script)
+	{
+		$script .= "
+	/**
+	 * Inserts \$node as last child of destination node \$dest
+	 *
+	 * @param object \$dest	Propel object for destination node
+	 * @param object \$node	Propel object for source node
+	 * @return object		Inserted propel object for model
+	 */
+	static function insertAsLastChildOf(\$dest, \$node, \$con = null)
+	{
+		if (!\$dest = self::getNode(\$dest, \$con)) {
+			return false;
+		}
+
+		\$newLeft = \$dest->getRightValue();
+		\$newRight = \$dest->getRightValue() + 1;
+		self::shiftRLValues(\$newLeft, 2, \$con);
+		\$dest->setRightValue(\$dest->getRightValue() + 2);
+		return self::insertNode(\$node, \$newLeft, \$newRight, \$con);
+	}
+";
+	}
+
+	protected function addInsertAsPrevSiblingOf(&$script)
+	{
+		$script .= "
+	/**
+	 * Inserts \$node as previous sibling to destination node \$dest
+	 *
+	 * @param object \$dest	Propel object for destination node
+	 * @param object \$node	Propel object for source node
+	 * @return object		Inserted propel object for model
+	 */
+	static function insertAsPrevSiblingOf(\$dest, \$node, \$con = null)
+	{
+		\$dest = self::getNode(\$dest, \$con);
+
+		\$newLeft = \$dest->getLeftValue();
+		\$newRight = \$dest->getLeftValue() + 1;
+		self::shiftRLValues(\$newLeft, 2, \$con);
+		\$dest->setLeftValue(\$dest->getLeftValue() + 2);
+		\$dest->setRightValue(\$dest->getRightValue() + 2);
+		return self::insertNode(\$node, \$newLeft, \$newRight, \$con);
+	}
+";
+	}
+
+	protected function addInsertAsNextSiblingOf(&$script)
+	{
+		$script .= "
+	/**
+	 * Inserts \$node as next sibling to destination node \$dest
+	 *
+	 * @param object \$dest	Propel object for destination node
+	 * @param object \$node	Propel object for source node
+	 * @return object		Inserted propel object for model
+	 */
+	static function insertAsNextSiblingOf(\$dest, \$node, \$con = null)
+	{
+		\$dest = self::getNode(\$dest, \$con);
+
+		\$newLeft = \$dest->getRightValue() + 1;
+		\$newRight = \$dest->getRightValue() + 2;
+		self::shiftRLValues(\$newLeft, 2, \$con);
+		return self::insertNode(\$node, \$newLeft, \$newRight, \$con);
+	}
+";
+	}
+
+	protected function addInsertRoot(&$script)
+	{
+		$script .= "
+	static function insertRoot(\$node, \$con = null)
+	{
+		return self::insertParent(self::retrieveRoot(\$con), \$node, \$con = null);
+	}
+";
+	}
+
+	protected function addInsertParent(&$script)
+	{
+		$script .= "
+	static function insertParent(\$dest, \$node, \$con = null)
+	{
+		\$dest = self::getNode(\$dest, \$con);
+
+		self::shiftRLValues(\$dest->getLeftValue(), 1, \$con);
+		self::shiftRLValues(\$dest->getRightValue() + 2, 1, \$con);
+
+		\$newLeft = \$dest->getLeftValue();
+		\$newRight = \$dest->getRightValue() + 2;
+		return self::insertNode(\$node, \$newLeft, \$newRight, \$con);
+	}
+";
+	}
+	
+	protected function addDeleteRoot(&$script)
+	{
+		$script .= "
+	static function deleteRoot(\$con = null)
+	{
+		\$root = self::retrieveRoot(\$con);
+		if (self::getNumberOfChildren(\$root) == 1) {
+			return self::deleteNode(\$root, \$con);
+		} else {
+			return false;
+		}
+	}
+";
+	}
+
+	protected function addDeleteNode(&$script)
+	{
+		$script .= "
+	static function deleteNode(\$dest, \$con = null)
+	{
+		if (\$dest->getLeftValue() == 1) {
+			return self::deleteRoot(\$con); // deleting root implies conditions (see deleteRoot() method)
+  		}
+
+		\$dest = self::getNode(\$dest, \$con);
+
+		self::shiftRLRange(\$dest->getLeftValue(), \$dest->getRightValue(), -1, \$con);
+		self::shiftRLValues(\$dest->getRightValue() + 1, -2, \$con);
+		return \$dest->delete(false, \$con);
+	}
+";
+	}
+
+	protected function addMoveToFirstChildOf(&$script)
+	{
+		$script .= "
+	/**
+	 * Moves \$node to be first child of \$destNode
+	 *
+	 * @param object \$destNode	Propel object for destination node
+	 * @param object \$node		Propel object for source node
+	 */
+	static function moveToFirstChildOf(\$dest, \$node, \$con = null)
+	{
+		\$dest = self::getNode(\$dest);
+
+		\$destLeft = \$dest->getLeftValue();
+		\$destLeft = \$destLeft + 1;
+		self::updateNode(\$node, \$destLeft, \$con);
+	}
+";
+	}
+	
+	protected function addMoveToLastChildOf(&$script)
+	{
+		$script .= "
+	/**
+	 * Moves \$node to be last child of \$destNode
+	 *
+	 * @param object \$destNode	Propel object for destination node
+	 * @param object \$node		Propel object for source node
+	 */
+	static function moveToLastChildOf(\$dest, \$node, \$con = null)
+	{
+		\$dest = self::getNode(\$dest, \$con);
+
+		\$destLeft = \$dest->getRightValue();
+		self::updateNode(\$node, \$destLeft, \$con);
+	}
+";
+	}
+
+	protected function addMoveToPrevSiblingOf(&$script)
+	{
+		$script .= "
+	/**
+	 * Moves \$node to be prev sibling to \$destNode
+	 *
+	 * @param object \$destNode	Propel object for destination node
+	 * @param object \$node		Propel object for source node
+	 */
+	static function moveToPrevSiblingOf(\$dest, \$node, \$con = null)
+	{
+		\$dest = self::getNode(\$dest, \$con);
+
+		\$destLeft = \$dest->getLeftValue();
+		self::updateNode(\$node, \$destLeft, \$con);
+	}
+";
+	}
+
+	protected function addMoveToNextSiblingOf(&$script)
+	{
+		$script .= "
+	/**
+	 * Moves \$node to be next sibling to \$destNode
+	 *
+	 * @param object \$destNode	Propel object for destination node
+	 * @param object \$node		Propel object for source node
+	 */
+	static function moveToNextSiblingOf(\$dest, \$node, \$con = null)
+	{
+		\$dest = self::getNode(\$dest, \$con);
+
+		\$destLeft = \$dest->getRightValue();
+		\$destLeft = \$destLeft + 1;
+		self::updateNode(\$node, \$destLeft, \$con);
+	}
+";
+	}
+
+	protected function addRetrieveFirstChild(&$script)
+	{
+		$script .= "
+	/**
+	 * Gets first child for the given node if it exists
+	 *
+	 * @param object \$node	Propel object for src node
+	 * @return mixed 		Propel object if exists else false
+	 */
+	static function retrieveFirstChild(\$node, \$selectMethod = 'doSelectOne', \$con = null)
+	{
+		\$node = self::getNode(\$node, \$con);
+
+		\$c = new Criteria();
+		\$c->add(self::LEFT_COL, \$node->getLeftValue() + 1, Criteria::EQUAL);
+
+		return self::doSelect(\$c, \$selectMethod, \$con);
+	}
+";
+	}
+
+	protected function addRetrieveLastChild(&$script)
+	{
+		$script .= "
+	/**
+	 * Gets last child for the given node if it exists
+	 *
+	 * @param object \$node	Propel object for src node
+	 * @return mixed 		Propel object if exists else false
+	 */
+	static function retrieveLastChild(\$node, \$selectMethod = 'doSelectOne', \$con = null)
+	{
+		\$node = self::getNode(\$node, \$con);
+
+		\$c = new Criteria();
+		\$c->add(self::RIGHT_COL, \$node->getRightValue() - 1, Criteria::EQUAL);
+
+		return self::doSelect(\$c, \$selectMethod, \$con);
+	}
+";
+	}
+
+	protected function addRetrievePrevSibling(&$script)
+	{
+		$script .= "
+	/**
+	 * Gets prev sibling for the given node if it exists
+	 *
+	 * @param object \$node	Propel object for src node
+	 * @return mixed 		Propel object if exists else false
+	 */
+	static function retrievePrevSibling(\$node, \$selectMethod = 'doSelectOne', \$con = null)
+	{
+		\$node = self::getNode(\$node, \$con);
+
+		\$c = new Criteria();
+		\$c->add(self::RIGHT_COL, \$node->getLeftValue() - 1, Criteria::EQUAL);
+
+		\$result = self::doSelect(\$c, \$selectMethod, \$con);
+
+		return \$result;
+	}
+";
+	}
+
+	protected function addRetrieveNextSibling(&$script)
+	{
+		$script .= "
+	/**
+	 * Gets next sibling for the given node if it exists
+	 *
+	 * @param object \$node	Propel object for src node
+	 * @return mixed 		Propel object if exists else false
+	 */
+	static function retrieveNextSibling(\$node, \$selectMethod = 'doSelectOne', \$con = null)
+	{
+		\$node = self::getNode(\$node, \$con);
+
+		\$c = new Criteria();
+		\$c->add(self::LEFT_COL, \$node->getRightValue() + 1, Criteria::EQUAL);
+
+		return self::doSelect(\$c, \$selectMethod, \$con);
+	}
+";
+	}
+
+	protected function addRetrieveTree(&$script)
+	{
+		$objName = $this->getStubObjectBuilder()->getClassname();
+		$script .= "
+	/**
+	 * Retrieves the entire tree from root
+	 *
+	 */
+	static function retrieveTree(\$selectMethod = 'doSelectRS', \$con = null)
+	{
+		\$c = new Criteria();
+		\$c->addAscendingOrderByColumn(self::LEFT_COL);
+		\$rs = self::doSelect(\$c, \$selectMethod, \$con);
+
+		\$root = new $objName();
+		\$rs->next();
+		\$root->hydrate(\$rs);
+		\$root->setLevel(0);
+
+		self::hydrateDescendants(\$root, \$rs);
+
+		return \$root;
+	}
+";
+	}
+
+	protected function addRetrieveBranch(&$script)
+	{
+		$script .= "
+	/**
+	 * Retrieves the entire tree from root
+	 *
+	 */
+	static function retrieveBranch(\$node, \$selectMethod = 'doSelectRS', \$con = null)
+	{
+		return self::retrieveDescendants(\$node, \$selectMethod, \$con);
+	}
+";
+	}
+
+	protected function addRetrieveChildren(&$script)
+	{
+		$script .= "
+	/**
+	 * Gets direct children for the node
+	 *
+	 */
+	static function retrieveChildren(\$node, \$selectMethod = 'doSelectRS', \$con = null)
+	{
+		if (is_array(\$node->_children)) {
+			return \$node->_children;
+		}
+
+		\$c = new Criteria();
+		\$c->addAscendingOrderByColumn(self::LEFT_COL);
+		\$c->add(self::LEFT_COL, \$node->getLeftValue(), Criteria::GREATER_THAN);
+		\$c->addAnd(self::RIGHT_COL, \$node->getRightValue(), Criteria::LESS_THAN);
+		\$rs = self::doSelect(\$c, \$selectMethod, \$con);
+
+		self::hydrateChildren(\$node, \$rs);
+		return \$node->_children;
+	}
+";
+	}
+
+	protected function addRetrieveDescendants(&$script)
+	{
+		$script .= "
+	/**
+	 * Gets all descendants for the node
+	 *
+	 */
+	static function retrieveDescendants(\$node, \$selectMethod = 'doSelectRS', \$con = null)
+	{
+		if (is_array(\$node->_children))
+		return \$node->_children;
+
+		\$c = new Criteria();
+		\$c->addAscendingOrderByColumn(self::LEFT_COL);
+		\$c->add(self::LEFT_COL, \$node->getLeftValue(), Criteria::GREATER_THAN);
+		\$c->addAnd(self::RIGHT_COL, \$node->getRightValue(), Criteria::LESS_THAN);
+		\$rs = self::doSelect(\$c, \$selectMethod, \$con);
+
+		self::hydrateDescendants(\$node, \$rs);
+		return \$node->_children;
+	}
+";
+	}
+
+	protected function addRetrieveSiblings(&$script)
+	{
+		$script .= "
+	/**
+	 * Gets all siblings for the node
+	 *
+	 */
+	static function retrieveSiblings(\$node, \$selectMethod = 'doSelectRS', \$con = null)
+	{
+		\$parent = self::retrieveParent(\$node, \$con);
+		\$siblings = self::retrieveChildren(\$parent, \$con);
+
+		return \$siblings;
+	}
+";
+	}
+
+	protected function addRetrieveParent(&$script)
+	{
+		$script .= "
+	/**
+	 * Gets ancestor for the given node if it exists
+	 *
+	 * @param object \$node	Propel object for src node
+	 * @return mixed 		Propel object if exists else false
+	 */
+	static function retrieveParent(\$node, \$con = null)
+	{
+		\$node = self::getNode(\$node);
+
+		\$c = new Criteria();
+		\$c1 = \$c->getNewCriterion(self::LEFT_COL, \$node->getLeftValue(), Criteria::LESS_THAN);
+		\$c2 = \$c->getNewCriterion(self::RIGHT_COL, \$node->getRightValue(), Criteria::GREATER_THAN);
+
+		\$c1->addAnd(\$c2);
+
+		\$c->add(\$c1);
+		\$c->addAscendingOrderByColumn(self::RIGHT_COL);
+
+		\$results = self::doSelect(\$c, 'doSelect', \$con);
+
+		return array_shift(\$results);
+	}
+";
+	}
+
+	protected function addRetrieveUndefined(&$script)
+	{
+		$script .= "
+	/**
+	 * Gets ancestor for the given node if it exists
+	 *
+	 * @param object \$node	Propel object for src node
+	 * @return mixed 		Propel object if exists else false
+	 */
+	static function retrieveUndefined(\$con = null)
+	{
+		\$c = new Criteria();
+		\$c1 = \$c->getNewCriterion(self::LEFT_COL, 0);
+		\$c2 = \$c->getNewCriterion(self::RIGHT_COL, 0);
+
+		\$c1->addAnd(\$c2);
+
+		\$c->add(\$c1);
+
+		\$results = self::doSelect(\$c, 'doSelect', \$con);
+
+		return \$results;
+	}
+";
+	}
+
+	protected function addHydrateDescendants(&$script)
+	{
+		$objName = $this->getStubObjectBuilder()->getClassname();
+		$script .= "
+	/**
+	 * Hydrate recursively the descendants of the given node
+	 * @param object \$node	Propel object for src node
+	 * @param object \$rs	Propel ResultSet
+	 */
+	static function hydrateDescendants(\$node, \$rs)
+	{
+		\$node->_children = array();
+		while(\$rs->next()) {
+			\$child = new $objName();
+			\$child->hydrate(\$rs);
+			\$child->setLevel(\$node->getLevel() + 1);
+
+			if (\$child->hasChildren()) {
+				self::hydrateDescendants(\$child, \$rs);
+			}
+
+			\$node->_children[] = \$child;
+
+			if (\$child->getRightValue() + 1 == \$node->getRightValue()) {
+				break;
+			}
+		}
+	}
+";
+	}
+
+	protected function addHydrateChildren(&$script)
+	{
+		$objName = $this->getStubObjectBuilder()->getClassname();
+		$script .= "
+	/**
+	 * Hydrate the children of the given node
+	 * @param object \$node Propel object for src node
+	 * @param object \$rs Propel ResultSet
+	 */
+	static function hydrateChildren(\$node, \$rs)
+	{
+		\$node->_children = array();
+		while(\$rs->next()) {
+			\$child = new $objName();
+			\$child->hydrate(\$rs);
+			\$child->setLevel(\$node->getLevel() + 1);
+
+			\$node->_children[] = \$child;
+
+			if (\$child->getRightValue() + 1 == \$node->getRightValue()) {
+				break;
+			}
+		}
+	}
+";
+	}
+
+	protected function addLevelGetter(&$script)
+	{
+		$script .= "
+	/**
+	 * Gets level for the given node
+	 *
+	 * @param object \$node	Propel object for src node
+	 * @return int			Level for the given node
+	 */
+	static function getLevel(\$node, \$con = null)
+	{
+		\$node = self::getNode(\$node, \$con);
+
+		if (\$con === null) {
+			\$con = Propel::getConnection();
+		}
+		\$stmt = \$con->createStatement();
+		\$sql = \"SELECT COUNT(*) AS level FROM \".self::TABLE_NAME .\" WHERE \".self::LEFT_COL.\"<\".\$node->getLeftValue().\" AND \".self::RIGHT_COL.\">\".\$node->getRightValue();
+		\$rs = \$stmt->executeQuery(\$sql);
+		\$rs->next();
+		return \$rs->getInt(\"level\");
+	}
+";
+	}
+
+	protected function addNumberOfChildrenGetter(&$script)
+	{
+		$script .= "
+	/**
+	 * Gets number of direct children for given node
+	 *
+	 * @param object \$node	Propel object for src node
+	 * @return int			Level for the given node
+	 */
+	static function getNumberOfChildren(\$node, \$con = null)
+	{
+		\$children = self::retrieveChildren(\$node);
+		return count(\$children);
+	}
+";
+	}
+
+	protected function addNumberOfDescendantsGetter(&$script)
+	{
+		$script .= "
+	/**
+	 * Gets number of descendants for given node
+	 *
+	 * @param object \$node	Propel object for src node
+	 * @return int			Level for the given node
+	 */
+	static function getNumberOfDescendants(\$node, \$con = null)
+	{
+		\$node = self::getNode(\$node, \$con);
+
+		\$right = \$node->getRightValue(\$node);
+		\$left = \$node->getLeftValue(\$node);
+		\$num = (\$right - \$left - 1) / 2;
+		return \$num;
+	}
+";
+	}
+
+	protected function addPathGetter(&$script)
+	{
+		$script .= "
+ 	/**
+	 * Returns path to a specific node as an array, useful to create breadcrumbs
+	 *
+	 * @param object \$node		Propel object of node to create path to
+	 * @return array			Array in order of heirarchy
+	 */
+	static function getPath(\$node, \$con = null) {
+
+		\$node = self::getNode(\$node, \$con);
+
+		\$path = array();
+		\$path[] = \$node;
+
+		while(\$parent = self::retrieveParent(\$node, \$con))
+		{
+			\$path[] = \$parent;
+			\$node = \$parent;
+		}
+
+		return array_reverse(\$path);
+	}
+";
+	}
+
+	protected function addIsValid(&$script)
+	{
+		$script .= "
+	/**
+	 * Tests if node is valid
+	 *
+	 * @param object \$node	Propel object for src node
+	 * @return bool
+	 */
+	static function isValid(\$node, \$con = null)
+	{
+		\$node = self::getNode(\$node, \$con);
+		if (is_object(\$node) && \$node->getRightValue() > \$node->getLeftValue()) {
+			return true;
+		} else {
+			return false;
+		}
+	}
+";
+	}
+
+	protected function addIsRoot(&$script)
+	{
+		$script .= "
+	/**
+	 * Tests if node is a root
+	 *
+	 * @param object \$node	Propel object for src node
+	 * @return bool
+	 */
+	static function isRoot(\$node, \$con = null)
+	{
+		\$node = self::getNode(\$node, \$con);
+		return (\$node->getLeftValue()==1);
+	}
+";
+	}
+
+	protected function addisLeaf(&$script)
+	{
+		$script .= "
+	/**
+	 * Tests if node is a leaf
+	 *
+	 * @param object \$node	Propel object for src node
+	 * @return bool
+	 */
+	static function isLeaf(\$node, \$con = null)
+	{
+		\$node = self::getNode(\$node, \$con);
+		return ((\$node->getRightValue()-\$node->getLeftValue())==1);
+	}
+";
+	}
+
+	protected function addisChildOf(&$script)
+	{
+		$script .= "
+	/**
+	 * Tests if \$node1 is a child of \$node2
+	 *
+	 * @param object \$node1		Propel object for node
+	 * @param object \$node2		Propel object for node
+	 * @return bool
+	 */
+	static function isChildOf(\$node2, \$node1, \$con = null)
+	{
+		\$node1 = self::getNode(\$node1, \$con);
+		\$node2 = self::getNode(\$node2, \$con);
+
+		return ((\$node1->getLeftValue()>\$node2->getLeftValue()) and (\$node1->getRightValue()<\$node2->getRightValue()));
+	}
+";
+	}
+
+	protected function addIsChildOfOrSiblingTo(&$script)
+	{
+		$script .= "
+	/**
+	 * Tests if \$node1 is a child of or equal to \$node2
+	 *
+	 * @param object \$node1		Propel object for node
+	 * @param object \$node2		Propel object for node
+	 * @return bool
+	 */
+	static function isChildOfOrSiblingTo(\$node2, \$node1, \$con = null)
+	{
+		\$node1 = self::getNode(\$node1, \$con);
+		\$node2 = self::getNode(\$node2, \$con);
+
+		return ((\$node1->getLeftValue()>=\$node2->getLeftValue()) and (\$node1->getRightValue()<=\$node2->getRightValue()));
+	}
+";
+	}
+
+	protected function addIsEqualTo(&$script)
+	{
+		$script .= "
+	/**
+	 * Tests if \$node1 is equal to \$node2
+	 *
+	 * @param object \$node1		Propel object for node
+	 * @param object \$node2		Propel object for node
+	 * @return bool
+	 */
+	static function isEqualTo(\$node1, \$node2, \$con = null)
+	{
+		\$node1 = self::getNode(\$node1, \$con);
+		\$node2 = self::getNode(\$node2, \$con);
+
+		return ((\$node1->getLeftValue() == \$node2->getLeftValue()) and (\$node1->getRightValue() == \$node2->getRightValue()));
+	}
+";
+	}
+
+	protected function addHasParent(&$script)
+	{
+		$script .= "
+	/**
+	 * Tests if \$node has an ancestor
+	 *
+	 * @param object \$node		Propel object for node
+	 * @return bool
+	 */
+	static function hasParent(\$node, \$con = null)
+	{
+		\$node = self::getNode(\$node, \$con);
+		return self::isValid(self::retrieveParent(\$node, \$con), \$con);
+	}
+";
+	}
+
+	protected function addHasPrevSibling(&$script)
+	{
+		$script .= "
+	/**
+	 * Tests if \$node has prev sibling
+	 *
+	 * @param object \$node		Propel object for node
+	 * @return bool
+	 */
+	static function hasPrevSibling(\$node, \$con = null)
+	{
+		\$node = self::getNode(\$node, \$con);
+		return self::isValid(self::retrievePrevSibling(\$node, \$con), \$con);
+	}
+";
+	}
+
+	protected function addHasNextSibling(&$script)
+	{
+		$script .= "
+	/**
+	 * Tests if \$node has next sibling
+	 *
+	 * @param object \$node		Propel object for node
+	 * @return bool
+	 */
+	static function hasNextSibling(\$node, \$con = null)
+	{
+		\$node = self::getNode(\$node, \$con);
+		return self::isValid(self::retrieveNextSibling(\$node, \$con), \$con);
+	}
+";
+	}
+
+	protected function addHasChildren(&$script)
+	{
+		$script .= "
+	/**
+	 * Tests if \$node has children
+	 *
+	 * @param object \$node		Propel object for node
+	 * @return bool
+	 */
+	static function hasChildren(\$node, \$con = null)
+	{
+		\$node = self::getNode(\$node, \$con);
+		return ((\$node->getRightValue()-\$node->getLeftValue())>1);
+	}
+";
+	}
+
+	protected function addDeleteDescendants(&$script)
+	{
+		$script .= "
+	/**
+	 * Deletes \$node and all of its descendants
+	 *
+	 * @param object \$node		Propel object for source node
+	 */
+	static function deleteDescendants(\$left, \$right, \$con = null)
+	{
+		/*\$sql = \"DELETE FROM \" .self::TABLE_NAME. \" WHERE \" .self::LEFT_COL. \">\".\$left.\" AND \".self::RIGHT_COL.\"<\".\$right;
+		\$stmt = Propel::getConnection()->createStatement();
+		\$result = \$stmt->executeQuery(\$sql, ResultSet::FETCHMODE_ASSOC);*/
+
+		\$c = new Criteria();
+		\$c1 = \$c->getNewCriterion(self::LEFT_COL, \$left, Criteria::GREATER_THAN);
+		\$c2 = \$c->getNewCriterion(self::RIGHT_COL, \$right, Criteria::LESS_THAN);
+
+		\$c1->addAnd(\$c2);
+
+		\$c->add(\$c1);
+		\$c->addAscendingOrderByColumn(self::RIGHT_COL);
+
+		\$result = self::doDelete(\$c, \$con);
+
+		self::shiftRLValues(\$right + 1, \$left - \$right -1, \$con);
+
+		return \$result;
+	}
+";
+	}
+
+	protected function addInsertNode(&$script)
+	{
+		$script .= "
+	/**
+	 * Inserts a node with given Left and Right values and to the appropriate root
+	 *
+	 * @param object \$node		Propel object for model
+	 * @param int \$left			Left Value
+	 * @param int \$right		Right Value
+	 * @param int \$right		Root Id
+	 * @return object			Inserted propel object for model
+	 */
+	private static function insertNode(\$node, \$left, \$right, \$con = null)
+	{
+		if (!is_object(\$node)) {
+			return false;
+		}
+
+		\$node->setLeftValue(\$left);
+		\$node->setRightValue(\$right);
+		\$node->save(\$con);
+		return \$node;
+	}
+";
+	}
+
+	protected function addUpdateNode(&$script)
+	{
+		$script .= "
+	/**
+	 * Move \$node and its children to location \$dest and updates rest of tree
+	 *
+	 * @param object Propel object for node to update
+	 * @param int	 Destination left value
+	 */
+	private static function updateNode(\$node, \$destLeft, \$con = null)
+	{
+		if (!is_object(\$node)) {
+			return false;
+		}
+
+		\$left = \$node->getLeftValue();
+		\$right = \$node->getRightValue();
+
+		\$treeSize = \$right - \$left +1;
+
+		self::shiftRLValues(\$destLeft, \$treeSize, \$con);
+
+		if (\$left >= \$destLeft) { // src was shifted too?
+			\$left += \$treeSize;
+			\$right += \$treeSize;
+		}
+
+		// now there's enough room next to target to move the subtree
+		\$newPos = self::shiftRLRange(\$left, \$right, \$destLeft - \$left, \$con);
+		// correct values after source
+
+		self::shiftRLValues(\$right + 1, -\$treeSize, \$con);
+
+		// don't get what this if for?
+		if (\$left <= \$destLeft) { // dst was shifted too?
+			\$newPos['left'] -= \$treeSize;
+			\$newPos['right'] -= \$treeSize;
+		}
+	}
+";
+	}
+
+	protected function addShiftRLValues(&$script)
+	{
+		$script .= "
+	/**
+	 * Adds '\$delta' to all L and R values that are >= '\$first'. '\$delta' can also be negative.
+	 *
+	 * @param int \$first 		First node to be shifted
+	 * @param int \$delta 		Value to be shifted by, can be negative
+	 */
+	private static function shiftRLValues(\$first, \$delta, \$con = null)
+	{
+		if (\$con === null) {
+			\$con = Propel::getConnection();
+		}
+		// do that prepared thing so they must both execute to work
+		// Shift left column values
+		\$sql =	\"UPDATE \" .self::TABLE_NAME. \" SET \" .self::LEFT_COL. \"=\".self::LEFT_COL.\"+\$delta WHERE \".self::LEFT_COL.\">=\$first\";
+		\$stmt = \$con->createStatement();
+		\$result = \$stmt->executeQuery(\$sql);
+
+		// Shift right column values
+		\$sql =	\"UPDATE \" .self::TABLE_NAME. \" SET \" .self::RIGHT_COL. \"=\".self::RIGHT_COL.\"+\$delta WHERE \".self::RIGHT_COL.\">=\$first\";
+		\$stmt = \$con->createStatement();
+		\$result = \$stmt->executeQuery(\$sql);
+
+	}
+";
+	}
+
+	protected function addShiftRLRange(&$script)
+	{
+		$script .= "
+	/**
+	 * Adds '\$delta' to all L and R values that are >= '\$first' and <= '\$last'.
+	 * '\$delta' can also be negative.
+	 *
+	 * @param int \$first 	First node to be shifted (L value)
+	 * @param int \$last 	Last node to be shifted (L value)
+	 * @param int \$delta	 	Value to be shifted by, can be negative
+	 * @return array 		Shifted L and R values
+	 */
+ 	private static function shiftRLRange(\$first, \$last, \$delta, \$con = null)
+	{
+		if (\$con === null) {
+			\$con = Propel::getConnection();
+		}
+		// do that prepared thing so they must both execute to work
+		// Shift left column values
+		\$sql =	\"UPDATE \" .self::TABLE_NAME. \" SET \" .self::LEFT_COL. \"=\".self::LEFT_COL.\"+\$delta WHERE \".self::LEFT_COL.\">=\$first AND \".self::LEFT_COL.\"<=\$last\";
+		\$stmt = \$con->createStatement();
+		\$result = \$stmt->executeQuery(\$sql, ResultSet::FETCHMODE_ASSOC);
+
+		// Shift right column values
+		\$sql =	\"UPDATE \" .self::TABLE_NAME. \" SET \" .self::RIGHT_COL. \"=\".self::RIGHT_COL.\"+\$delta WHERE \".self::RIGHT_COL.\">=\$first AND \".self::RIGHT_COL.\"<=\$last\";
+		\$stmt = \$con->createStatement();
+		\$result = \$stmt->executeQuery(\$sql, ResultSet::FETCHMODE_ASSOC);
+
+		return array('left' => \$first + \$delta, 'right' => \$last + \$delta);
+	}
+";
+	}
+
+	protected function addNodeGetter(&$script)
+	{
+		$script .= "
+	/**
+	 * Returns a node given its primary key or the node itself
+	 *
+	 * @param int \$nodeId	Primary key of required node
+	 * @return object		Propel object for model
+	 */
+	static function getNode(\$node, \$con = null)
+	{
+		if (is_object(\$node)) {
+			return \$node;
+		} else {
+			\$object = self::retrieveByPK(\$node, \$con);
+			\$rtn = is_object(\$object) ? \$object : false;
+			return \$rtn;
+		}
+	}
+";
+	}
+
+} // PHP5NodePeerBuilder
Index: generator/classes/propel/engine/database/model/Column.php
===================================================================
--- generator/classes/propel/engine/database/model/Column.php	(revision 499)
+++ generator/classes/propel/engine/database/model/Column.php	(working copy)
@@ -77,6 +77,8 @@
 	private $isPrimaryKey = false;
 	private $isNodeKey = false;
 	private $nodeKeySep;
+	private $isNestedSetLeftKey = false;
+	private $isNestedSetRightKey = false;
 	private $isUnique = false;
 	private $isAutoIncrement = false;
 	private $isLazyLoad = false;
@@ -163,6 +165,9 @@
 			$this->isNodeKey = $this->booleanValue($this->getAttribute("nodeKey"));
 			$this->nodeKeySep = $this->getAttribute("nodeKeySep", ".");
 
+			$this->isNestedSetLeftKey = $this->booleanValue($this->getAttribute("nestedSetLeftKey"));
+			$this->isNestedSetRightKey = $this->booleanValue($this->getAttribute("nestedSetRightKey"));
+
 			$this->isNotNull = $this->booleanValue($this->getAttribute("required"), false);
 
 			// Regardless of above, if this column is a primary key then it can't be null.
@@ -473,6 +478,38 @@
 	}
 
 	/**
+	 * Set if the column is the nested set left key of a tree
+	 */
+	public function setNestedSetLeftKey($nslk)
+	{
+		$this->isNestedSetLeftKey = (boolean) $nslk;
+	}
+
+	/**
+	 * Return true if the column is a nested set key of a tree
+	 */
+	public function isNestedSetLeftKey()
+	{
+		return $this->isNestedSetLeftKey;
+	}
+
+	/**
+	 * Set if the column is the nested set right key of a tree
+	 */
+	public function setNestedSetRightKey($nsrk)
+	{
+		$this->isNestedSetRightKey = (boolean) $nsrk;
+	}
+
+	/**
+	 * Return true if the column is a nested set right key of a tree
+	 */
+	public function isNestedSetRightKey()
+	{
+		return $this->isNestedSetRightKey;
+	}
+
+	/**
 	 * Set true if the column is UNIQUE
 	 */
 	public function setUnique($u)
Index: generator/classes/propel/engine/database/model/Table.php
===================================================================
--- generator/classes/propel/engine/database/model/Table.php	(revision 499)
+++ generator/classes/propel/engine/database/model/Table.php	(working copy)
@@ -78,7 +78,7 @@
     private $needsTransactionInPostgres;//maybe this can be retrieved from vendorSpecificInfo?
     private $heavyIndexing;
     private $forReferenceOnly;
-    private $isTree;
+    private $treeMode;
 
     /**
      * Constructs a table object with a name
@@ -125,7 +125,7 @@
                 		&& $this->getDatabase()->isHeavyIndexing() ) );
         $this->description = $this->getAttribute("description");
         $this->enterface = $this->getAttribute("interface"); // sic ('interface' is reserved word)
-        $this->isTree = $this->booleanValue($this->getAttribute("isTree"));
+        $this->treeMode = $this->getAttribute("treeMode");
     }
 
     /**
@@ -951,21 +951,21 @@
     }
 
    /**
-     * Flag to determine if tree node class should be generated for this table.
-     * @return valur of isTree
+     * Flag to determine if tree class should be generated for this table.
+     * @return valur of treeMode
     */
-   public function isTree()
+   public function treeMode()
    {
-        return $this->isTree;
+        return $this->treeMode;
    }
 
     /**
-     * Flag to determine if tree node class should be generated for this table.
-     * @param v  Value to assign to isTree.
+     * Flag to determine if tree class should be generated for this table.
+     * @param v  Value to assign to treeMode.
      */
-    public function setIsTree($v)
+    public function setTreeMode($v)
     {
-        $this->isTree = (boolean) $v;
+        $this->treeMode = $v;
     }
 
     /**
@@ -1001,9 +1001,9 @@
                   . '"';
         }
 
-        if ($this->isTree) {
-            $result .= " isTree=\""
-                  . ($this->isTree ? "true" : "false")
+        if ($this->treeMode) {
+            $result .= " treeMode=\""
+                  . $this->treeMode
                   . '"';
         }
 
Index: generator/classes/propel/phing/PropelOMTask.php
===================================================================
--- generator/classes/propel/phing/PropelOMTask.php	(revision 499)
+++ generator/classes/propel/phing/PropelOMTask.php	(working copy)
@@ -184,19 +184,35 @@
 						// Create tree Node classes
 						// -----------------------------------------------------------------------------------------
 						
-						if ($table->isTree()) {
-							
-							foreach(array('nodepeer', 'node') as $target) {							
-								$builder = DataModelBuilder::builderFactory($table, $target);
-								$this->build($builder);							
+						if ($table->treeMode()) {
+						    switch($table->treeMode()) {
+								case "NestedSet":
+									foreach(array('nestedsetpeer', 'nestedset') as $target) {
+										$builder = DataModelBuilder::builderFactory($table, $target);
+										$this->build($builder);
+									}
+
+									foreach(array('nestedsetpeerstub', 'nestedsetstub') as $target) {
+										$builder = DataModelBuilder::builderFactory($table, $target);
+										$this->build($builder, $overwrite=false);
+									}
+								break;
+
+								case "Node":
+								default:
+									foreach(array('nodepeer', 'node') as $target) {
+										$builder = DataModelBuilder::builderFactory($table, $target);
+										$this->build($builder);
+									}
+
+									foreach(array('nodepeerstub', 'nodestub') as $target) {
+										$builder = DataModelBuilder::builderFactory($table, $target);
+										$this->build($builder, $overwrite=false);
+									}
+								break;
 							}
-							
-							foreach(array('nodepeerstub', 'nodestub') as $target) {
-								$builder = DataModelBuilder::builderFactory($table, $target);
-								$this->build($builder, $overwrite=false);							
-							}
-							
-						} // if Table->isTree()
+
+						} // if Table->treeMode()
 						
 						
 					} // if !$table->isForReferenceOnly()										
@@ -209,4 +225,4 @@
 
 	
 	} // main()
-}
\ No newline at end of file
+}
Index: generator/default.properties
===================================================================
--- generator/default.properties	(revision 499)
+++ generator/default.properties	(working copy)
@@ -209,6 +209,11 @@
 propel.builder.nodestub.class = propel.engine.builder.om.php5.PHP5ExtensionNodeBuilder
 propel.builder.nodepeerstub.class = propel.engine.builder.om.php5.PHP5ExtensionNodePeerBuilder
 
+propel.builder.nestedset.class = propel.engine.builder.om.php5.PHP5NestedSetBuilder
+propel.builder.nestedsetpeer.class = propel.engine.builder.om.php5.PHP5NestedSetPeerBuilder
+propel.builder.nestedsetstub.class = propel.engine.builder.om.php5.PHP5ExtensionNestedSetBuilder
+propel.builder.nestedsetpeerstub.class = propel.engine.builder.om.php5.PHP5ExtensionNestedSetPeerBuilder
+
 # SQL builders
 
 propel.builder.ddl.class = propel.engine.builder.sql.${propel.database}.${propel.database}DDLBuilder
@@ -216,4 +221,4 @@
 
 # Platform classes
 
-propel.platform.class = propel.engine.platform.${propel.database}Platform
\ No newline at end of file
+propel.platform.class = propel.engine.platform.${propel.database}Platform
Index: generator/resources/xsd/database.xsd
===================================================================
--- generator/resources/xsd/database.xsd	(revision 499)
+++ generator/resources/xsd/database.xsd	(working copy)
@@ -142,6 +142,13 @@
 		</xs:restriction>
 	</xs:simpleType>
 
+	<xs:simpleType name="treemode">
+		<xs:restriction base="xs:string">
+			<xs:enumeration value="Node"/>
+			<xs:enumeration value="NestedSet"/>
+		</xs:restriction>
+	</xs:simpleType>
+
 	<!-- Restrict column name to letters (upper- and lowercase), numbers and the _ -->
 	<xs:simpleType name="column_name">
 		<xs:restriction base="xs:string">
@@ -284,6 +291,8 @@
 		<xs:attribute name="lazyLoad" type="xs:boolean" default="false"/>
 		<xs:attribute name="nodeKeySep" type="xs:string" use="optional"/> <!-- missing in the old DTD, but required to keep the treetest example working -->
 		<xs:attribute name="nodeKey" type="xs:string" use="optional"/> <!-- missing in the old DTD, but required to keep the treetest example working -->
+		<xs:attribute name="nestedSetLeftKey" type="xs:boolean" default="false"/> <!-- missing in the old DTD, but required to keep the nested set example working -->
+		<xs:attribute name="nestedSetRightKey" type="xs:boolean" default="false"/> <!-- missing in the old DTD, but required to keep the nested set example working -->
 		<xs:attribute name="require" type="xs:string" use="optional"/>
 	</xs:complexType>
 
@@ -326,7 +335,7 @@
 		<xs:attribute name="phpNamingMethod" type="phpnamingmethod" use='optional'/>
 		<xs:attribute name="heavyIndexing" type="xs:boolean" use="optional"/>
 		<xs:attribute name="description" type="xs:string"/>
-		<xs:attribute name="isTree" type="xs:boolean" use="optional"/> <!-- missing in the old DTD, but required to keep the treetest example working -->
+		<xs:attribute name="treeMode" type="treemode" use="optional"/> <!-- missing in the old DTD, but required to keep the treetest example working -->
 	</xs:complexType>
 
 	<xs:complexType name="database">
@@ -343,4 +352,4 @@
 		<xs:attribute name="defaultPhpNamingMethod" type="phpnamingmethod" default="underscore"/>
 		<xs:attribute name="heavyIndexing" type="xs:boolean" default="false"/>
 	</xs:complexType>
-</xs:schema>
\ No newline at end of file
+</xs:schema>
