<?php
// Template for creating base node class on tree table.
//
// $Id: Node.tpl,v 1.6 2005/04/04 10:48:33 dlawson_mi Exp $
require_once 'propel/engine/builder/om/ClassTools.php';
$db = $table->getDatabase();
if($table->getPackage()) {
$package = $table->getPackage();
} else {
$package = $targetPackage;
}
echo '<' . '?' . 'php';
?>
require_once '<?php echo ClassTools::getFilePath($package, $table->getPhpName() . 'NodePeer') ?>';
/**
* Base tree node class for manipulating a tree of <?php echo $table->getPhpName() ?> objects.
* This class will wrap these objects within a "node" interface. It provides a
* method overload mechanism which allows you to use a <?php echo $table->getPhpName() ?>Node
* object just like a <?php $table->getPhpName() ?> object.
*
* To avoid tree corruption, you should always use this class to make changes to
* the tree and objects within it rather than using the <?php echo $table->getPhpName() ?>
* class directly.
*
<?php if (isset($addTimeStamp)) { ?>
* This class was autogenerated by Propel on:
*
* [<?php echo $now ?>]
*
<?php } ?>
* @package <?php echo $package ?>
*
*/
class <?php echo $basePrefix . $table->getPhpName() ?>Node implements IteratorAggregate
{
/**
* @var <?php echo $table->getPhpName() ?> Object wrapped by this node.
*/
protected $obj = null;
/**
* The parent node for this node.
* @var <?php echo $table->getPhpName() ?>Node
*/
protected $parentNode = null;
/**
* Array of child nodes for this node. Nodes indexes are one-based.
* @var array
*/
protected $childNodes = array();
/**
* Constructor.
*
* @param <?php echo $table->getPhpName() ?> Object wrapped by this node.
*/
public function __construct($obj = null)
{
if ($obj !== null)
{
$this->obj = $obj;
}
else
{
$setNodePath = "set" . <?php echo $table->getPhpName() ?>NodePeer::NPATH_PHPNAME;
$this->obj = new <?php echo $table->getPhpName() ?>();
$this->obj->$setNodePath('0');
}
}
/**
* Convenience overload for wrapped object methods.
*
* @param string Method name to call on wrapped object.
* @param mixed Parameter accepted by wrapped object set method.
* @return mixed Return value of wrapped object method.
* @throws PropelException Fails if method is not defined for wrapped object.
*/
public function __call($name, $parms)
{
if (method_exists($this->obj, $name))
return call_user_func_array(array($this->obj, $name), $parms);
else
throw new PropelException("get method not defined: $name");
}
/**
* Sets the default options for iterators created from this object.
* The options are specified in map format. The following options
* are supported by all iterators. Some iterators may support other
* options:
*
* "querydb" - True if nodes should be retrieved from database.
* "con" - Connection to use if retrieving from database.
*
* @param string Type of iterator to use ("pre", "post", "level").
* @param array Map of option name => value.
* @return void
* @todo Implement other iterator types (i.e. post-order, level, etc.)
*/
public function setIteratorOptions($type, $opts)
{
$this->itType = $type;
$this->itOpts = $opts;
}
/**
* Returns a pre-order iterator for this node and its children.
*
* @param string Type of iterator to use ("pre", "post", "level")
* @param array Map of option name => value.
* @return NodeIterator
*/
public function getIterator($type = null, $opts = null)
{
if ($type === null)
$type = (isset($this->itType) ? $this->itType : 'Pre');
if ($opts === null)
$opts = (isset($this->itOpts) ? $this->itOpts : array());
$itclass = ucfirst(strtolower($type)) . 'OrderNodeIterator';
require_once('propel/om/' . $itclass . '.php');
return new $itclass($this, $opts);
}
/**
* Returns the object wrapped by this class.
* @return <?php echo $table->getPhpName() . "\n" ?>
*/
public function getNodeObj()
{
return $this->obj;
}
/**
* Convenience method for retrieving nodepath.
* @return string
*/
public function getNodePath()
{
$getNodePath = 'get' . <?php echo $table->getPhpName() ?>NodePeer::NPATH_PHPNAME;
return $this->obj->$getNodePath();
}
/**
* Returns one-based node index among siblings.
* @return int
*/
public function getNodeIndex()
{
$npath =& $this->getNodePath();
$sep = strrpos($npath, <?php echo $table->getPhpName() ?>NodePeer::NPATH_SEP);
return (int) ($sep !== false ? substr($npath, $sep+1) : $npath);
}
/**
* Returns one-based node level within tree (root node is level 1).
* @return int
*/
public function getNodeLevel()
{
return (substr_count($this->getNodePath(), <?php echo $table->getPhpName() ?>NodePeer::NPATH_SEP) + 1);
}
/**
* Returns true if specified node is a child of this node. If recurse is
* true, checks if specified node is a descendant of this node.
*
* @param <?php echo $table->getPhpName() ?>Node Node to look for.
* @param boolean True if strict comparison should be used.
* @param boolean True if all descendants should be checked.
* @return boolean
*/
public function hasChildNode($node, $strict = false, $recurse = false)
{
foreach ($this->childNodes as $childNode)
{
if ($childNode->equals($node, $strict))
return true;
if ($recurse && $childNode->hasChildNode($node, $recurse))
return true;
}
return false;
}
/**
* Returns child node at one-based index. Retrieves from database if not
* loaded yet.
*
* @param int One-based child node index.
* @param boolean True if child should be retrieved from database.
* @param Connection Connection to use if retrieving from database.
* @return <?php echo $table->getPhpName() ?>Node
*/
public function getChildNodeAt($i, $querydb = false, $con = null)
{
if ($querydb &&
!$this->obj->isNew() &&
!$this->obj->isDeleted() &&
!isset($this->childNodes[$i]))
{
$criteria = new Criteria(<?php echo $table->getPhpName() ?>Peer::DATABASE_NAME);
$criteria->add(<?php echo $table->getPhpName() ?>NodePeer::NPATH_COLNAME, $this->getNodePath() . <?php echo $table->getPhpName() ?>NodePeer::NPATH_SEP . $i, Criteria::EQUAL);
if ($childObj = <?php echo $table->getPhpName() ?>Peer::doSelectOne($criteria, $con))
$this->attachChildNode(new <?php echo $table->getPhpName() ?>Node($childObj));
}
return (isset($this->childNodes[$i]) ? $this->childNodes[$i] : null);
}
/**
* Returns first child node (if any). Retrieves from database if not loaded yet.
*
* @param boolean True if child should be retrieved from database.
* @param Connection Connection to use if retrieving from database.
* @return <?php echo $table->getPhpName() ?>Node
*/
public function getFirstChildNode($querydb = false, $con = null)
{
return $this->getChildNodeAt(1, $querydb, $con);
}
/**
* Returns last child node (if any).
*
* @param boolean True if child should be retrieved from database.
* @param Connection Connection to use if retrieving from database.
*/
public function getLastChildNode($querydb = false, $con = null)
{
$lastNode = null;
if ($this->obj->isNew() || $this->obj->isDeleted())
{
end($this->childNodes);
$lastNode = (count($this->childNodes) ? current($this->childNodes) : null);
}
else if ($querydb)
{
$db = Propel::getDb(<?php echo $table->getPhpName() ?>Peer::DATABASE_NAME);
$criteria = new Criteria(<?php echo $table->getPhpName() ?>Peer::DATABASE_NAME);
$criteria->add(<?php echo $table->getPhpName() ?>NodePeer::NPATH_COLNAME, $this->getNodePath() . <?php echo $table->getPhpName() ?>NodePeer::NPATH_SEP . '%', Criteria::LIKE);
$criteria->addAnd(<?php echo $table->getPhpName() ?>NodePeer::NPATH_COLNAME, $this->getNodePath() . <?php echo $table->getPhpName() ?>NodePeer::NPATH_SEP . '%' . <?php echo $table->getPhpName() ?>NodePeer::NPATH_SEP . '%', Criteria::NOT_LIKE);
$criteria->addAsColumn('npathlen', $db->strLength(<?php echo $table->getPhpName() ?>NodePeer::NPATH_COLNAME));
$criteria->addDescendingOrderByColumn('npathlen');
$criteria->addDescendingOrderByColumn(<?php echo $table->getPhpName() ?>NodePeer::NPATH_COLNAME);
$lastObj = <?php echo $table->getPhpName() ?>Peer::doSelectOne($criteria, $con);
if ($lastObj !== null)
{
$lastNode = new <?php echo $table->getPhpName() ?>Node($lastObj);
end($this->childNodes);
$endNode = (count($this->childNodes) ? current($this->childNodes) : null);
if ($endNode)
{
if ($endNode->getNodePath() > $lastNode->getNodePath())
throw new PropelException('Cached child node inconsistent with database.');
else if ($endNode->getNodePath() == $lastNode->getNodePath())
$lastNode = $endNode;
else
$this->attachChildNode($lastNode);
}
else
{
$this->attachChildNode($lastNode);
}
}
}
return $lastNode;
}
/**
* Returns next (or previous) sibling node or null. Retrieves from database if
* not loaded yet.
*
* @param boolean True if previous sibling should be returned.
* @param boolean True if sibling should be retrieved from database.
* @param Connection Connection to use if retrieving from database.
* @return <?php echo $table->getPhpName() ?>Node
*/
public function getSiblingNode($prev = false, $querydb = false, $con = null)
{
$nidx = $this->getNodeIndex();
if ($this->isRootNode())
{
return null;
}
else if ($prev)
{
if ($nidx > 1 && ($parentNode = $this->getParentNode($querydb, $con)))
return $parentNode->getChildNodeAt($nidx-1, $querydb, $con);
else
return null;
}
else
{
if ($parentNode = $this->getParentNode($querydb, $con))
return $parentNode->getChildNodeAt($nidx+1, $querydb, $con);
else
return null;
}
}
/**
* Returns parent node. Loads from database if not cached yet.
*
* @param boolean True if parent should be retrieved from database.
* @param Connection Connection to use if retrieving from database.
* @return <?php echo $table->getPhpName() ?>Node
*/
public function getParentNode($querydb = true, $con = null)
{
if ($querydb &&
$this->parentNode === null &&
!$this->isRootNode() &&
!$this->obj->isNew() &&
!$this->obj->isDeleted())
{
$npath =& $this->getNodePath();
$sep = strrpos($npath, <?php echo $table->getPhpName() ?>NodePeer::NPATH_SEP);
$ppath = substr($npath, 0, $sep);
$criteria = new Criteria(<?php echo $table->getPhpName() ?>Peer::DATABASE_NAME);
$criteria->add(<?php echo $table->getPhpName() ?>NodePeer::NPATH_COLNAME, $ppath, Criteria::EQUAL);
if ($parentObj = <?php echo $table->getPhpName() ?>Peer::doSelectOne($criteria, $con))
{
$parentNode = new <?php echo $table->getPhpName() ?>Node($parentObj);
$parentNode->attachChildNode($this);
}
}
return $this->parentNode;
}
/**
* Returns an array of all ancestor nodes, starting with the root node
* first.
*
* @param boolean True if ancestors should be retrieved from database.
* @param Connection Connection to use if retrieving from database.
* @return array
*/
public function getAncestors($querydb = false, $con = null)
{
$ancestors = array();
$parentNode = $this;
while ($parentNode = $parentNode->getParentNode($querydb, $con))
array_unshift($ancestors, $parentNode);
return $ancestors;
}
/**
* Returns true if node is the root node of the tree.
* @return boolean
*/
public function isRootNode()
{
return ($this->getNodePath() === '1');
}
/**
* Changes the state of the object and its descendants to 'new'.
* Also changes the node path to '0' to indicate that it is not a
* stored node.
*
* @param boolean
* @return void
*/
public function setNew($b)
{
$this->adjustStatus('new', $b);
$this->adjustNodePath($this->getNodePath(), '0');
}
/**
* Changes the state of the object and its descendants to 'deleted'.
*
* @param boolean
* @return void
*/
public function setDeleted($b)
{
$this->adjustStatus('deleted', $b);
}
/**
* Adds the specified node (and its children) as a child to this node. If a
* valid $beforeNode is specified, the node will be inserted in front of
* $beforeNode. If $beforeNode is not specified the node will be appended to
* the end of the child nodes.
*
* @param <?php echo $table->getPhpName() ?>Node Node to add.
* @param <?php echo $table->getPhpName() ?>Node Node to insert before.
* @param Connection Connection to use.
*/
public function addChildNode($node, $beforeNode = null, $con = null)
{
if ($this->obj->isNew() && !$node->obj->isNew())
throw new PropelException('Cannot add stored nodes to a new node.');
if ($this->obj->isDeleted() || $node->obj->isDeleted())
throw new PropelException('Cannot add children in a deleted state.');
if ($this->hasChildNode($node))
throw new PropelException('Node is already a child of this node.');
if ($beforeNode && !$this->hasChildNode($beforeNode))
throw new PropelException('Invalid beforeNode.');
if ($con === null)
$con = Propel::getConnection(<?php echo $table->getPhpName() ?>Peer::DATABASE_NAME);
try {
if (!$this->obj->isNew()) $con->begin();
if ($beforeNode)
{
// Inserting before a node.
$childIdx = $beforeNode->getNodeIndex();
$this->shiftChildNodes(1, $beforeNode->getNodeIndex(), $con);
}
else
{
// Appending child node.
if ($lastNode = $this->getLastChildNode(true, $con))
$childIdx = $lastNode->getNodeIndex()+1;
else
$childIdx = 1;
}
// Add the child (and its children) at the specified index.
if (!$this->obj->isNew() && $node->obj->isNew())
{
$this->insertNewChildNode($node, $childIdx, $con);
}
else
{
// $this->isNew() && $node->isNew() ||
// !$this->isNew() && !node->isNew()
$srcPath = $node->getNodePath();
$dstPath = $this->getNodePath() . <?php echo $table->getPhpName() ?>NodePeer::NPATH_SEP . $childIdx;
if (!$node->obj->isNew())
{
<?php echo $table->getPhpName() ?>NodePeer::moveNodeSubTree($srcPath, $dstPath, $con);
$parentNode = $node->getParentNode(true, $con);
}
else
{
$parentNode = $node->getParentNode();
}
if ($parentNode)
{
$parentNode->detachChildNode($node);
$parentNode->shiftChildNodes(-1, $node->getNodeIndex()+1, $con);
}
$node->adjustNodePath($srcPath, $dstPath);
}
if (!$this->obj->isNew()) $con->commit();
$this->attachChildNode($node);
} catch (SQLException $e) {
if (!$this->obj->isNew()) $con->rollback();
throw new PropelException($e);
}
}
/**
* Moves the specified child node in the specified direction.
*
* @param <?php $table->getPhpName() ?>Node Node to move.
* @param int Number of spaces to move among siblings (may be negative).
* @param Connection Connection to use.
* @throws PropelException
*/
public function moveChildNode($node, $direction, $con = null)
{
throw new PropelException('moveChildNode() not implemented yet.');
}
/**
* Saves modified object data to the datastore.
*
* @param boolean If true, descendants will be saved as well.
* @param Connection Connection to use.
*/
public function save($recurse = false, $con = null)
{
if ($this->obj->isDeleted())
throw new PropelException('Cannot save deleted node.');
if (substr($this->getNodePath(), 0, 1) == '0')
throw new PropelException('Cannot save unattached node.');
if ($this->obj->isColumnModified(<?php echo $table->getPhpName() ?>NodePeer::NPATH_COLNAME))
throw new PropelException('Cannot save manually modified node path.');
$this->obj->save($con);
if ($recurse)
{
foreach ($this->childNodes as $childNode)
$childNode->save($recurse, $con);
}
}
/**
* Removes this object and all descendants from datastore.
*
* @param Connection Connection to use.
* @return void
* @throws PropelException
*/
public function delete($con = null)
{
if ($this->obj->isDeleted())
throw new PropelException('This node has already been deleted.');
if (!$this->obj->isNew())
{
<?php echo $table->getPhpName() ?>NodePeer::deleteNodeSubTree($this->getNodePath(), $con);
}
if ($parentNode = $this->getParentNode(true, $con))
{
$parentNode->detachChildNode($this);
$parentNode->shiftChildNodes(-1, $this->getNodeIndex()+1, $con);
}
$this->setDeleted(true);
}
/**
* Compares the object wrapped by this node with that of another node. Use
* this instead of equality operators to prevent recursive dependency
* errors.
*
* @param <?php echo $table->getPhpName() ?>Node Node to compare.
* @param boolean True if strict comparison should be used.
* @return boolean
*/
public function equals($node, $strict = false)
{
if ($strict)
return ($this->obj === $node->obj);
else
return ($this->obj == $node->obj);
}
/**
* This method is used internally when constructing the tree structure
* from the database. To set the parent of a node, you should call
* addChildNode() on the parent.
*
* @param <?php echo $table->getPhpName() ?>Node Parent node to attach.
* @return void
* @throws PropelException
*/
public function attachParentNode($node)
{
if (!$node->hasChildNode($this, true))
throw new PropelException('Failed to attach parent node for non-child.');
$this->parentNode = $node;
}
/**
* This method is used internally when constructing the tree structure
* from the database. To add a child to a node you should call the
* addChildNode() method instead.
*
* @param <?php echo $table->getPhpName() ?>Node Child node to attach.
* @return void
* @throws PropelException
*/
public function attachChildNode($node)
{
if ($this->hasChildNode($node))
throw new PropelException('Failed to attach child node. Node already exists.');
if ($this->obj->isDeleted() || $node->obj->isDeleted())
throw new PropelException('Failed to attach node in deleted state.');
if ($this->obj->isNew() && !$node->obj->isNew())
throw new PropelException('Failed to attach non-new child to new node.');
if (!$this->obj->isNew() && $node->obj->isNew())
throw new PropelException('Failed to attach new child to non-new node.');
if ($this->getNodePath() . <?php echo $table->getPhpName() ?>NodePeer::NPATH_SEP . $node->getNodeIndex() != $node->getNodePath())
throw new PropelException('Failed to attach child node. Node path mismatch.');
$this->childNodes[$node->getNodeIndex()] = $node;
ksort($this->childNodes);
$node->attachParentNode($this);
}
/**
* This method is used internally when deleting nodes. It is used to break
* the link to this node's parent.
* @param <?php echo $table->getPhpName() ?>Node Parent node to detach from.
* @return void
* @throws PropelException
*/
public function detachParentNode($node)
{
if (!$node->hasChildNode($this, true))
throw new PropelException('Failed to detach parent node from non-child.');
unset($node->childNodes[$this->getNodeIndex()]);
$this->parentNode = null;
}
/**
* This method is used internally when deleting nodes. It is used to break
* the link to this between this node and the specified child.
* @param <?php echo $table->getPhpName() ?>Node Child node to detach.
* @return void
* @throws PropelException
*/
public function detachChildNode($node)
{
if (!$this->hasChildNode($node, true))
throw new PropelException('Failed to detach non-existent child node.');
unset($this->childNodes[$node->getNodeIndex()]);
$node->parentNode = null;
}
/**
* Shifts child nodes in the specified direction and offset index. This
* method assumes that there is already space available in the
* direction/offset indicated.
*
* @param int Direction/# spaces to shift. 1=leftshift, 1=rightshift
* @param int Node index to start shift at.
* @param Connection The connection to be used.
* @return void
* @throws PropelException
*/
protected function shiftChildNodes($direction, $offsetIdx, $con)
{
if ($this->obj->isDeleted())
throw new PropelException('Cannot shift nodes for deleted object');
$lastNode = $this->getLastChildNode(true, $con);
$lastIdx = ($lastNode !== null ? $lastNode->getNodeIndex() : 0);
if ($lastNode === null || $offsetIdx > $lastIdx)
return;
if ($con === null)
$con = Propel::getConnection(<?php echo $table->getPhpName() ?>Peer::DATABASE_NAME);
if (!$this->obj->isNew())
{
// Shift nodes in database.
try {
$con->begin();
$n = $lastIdx - $offsetIdx + 1;
$i = $direction < 1 ? $offsetIdx : $lastIdx;
while ($n--)
{
$srcPath = $this->getNodePath() . <?php echo $table->getPhpName() ?>NodePeer::NPATH_SEP . $i; // 1.2.2
$dstPath = $this->getNodePath() . <?php echo $table->getPhpName() ?>NodePeer::NPATH_SEP . ($i+$direction); // 1.2.3
<?php echo $table->getPhpName() ?>NodePeer::moveNodeSubTree($srcPath, $dstPath, $con);
$i -= $direction;
}
$con->commit();
} catch (SQLException $e) {
$con->rollback();
throw new PropelException($e);
}
}
// Shift the in-memory objects.
$n = $lastIdx - $offsetIdx + 1;
$i = $direction < 1 ? $offsetIdx : $lastIdx;
while ($n--)
{
if (isset($this->childNodes[$i]))
{
$srcPath = $this->getNodePath() . <?php echo $table->getPhpName() ?>NodePeer::NPATH_SEP . $i; // 1.2.2
$dstPath = $this->getNodePath() . <?php echo $table->getPhpName() ?>NodePeer::NPATH_SEP . ($i+$direction); // 1.2.3
$this->childNodes[$i+$direction] = $this->childNodes[$i];
$this->childNodes[$i+$direction]->adjustNodePath($srcPath, $dstPath);
unset($this->childNodes[$i]);
}
$i -= $direction;
}
ksort($this->childNodes);
}
/**
* Inserts the node and its children at the specified childIdx.
*
* @param <?php echo $table->getPhpName() ?>Node Node to insert.
* @param int One-based child index to insert at.
* @param Connection Connection to use.
* @param void
*/
protected function insertNewChildNode($node, $childIdx, $con)
{
if (!$node->obj->isNew())
throw new PropelException('Failed to insert non-new node.');
$setNodePath = "set" . <?php echo $table->getPhpName() ?>NodePeer::NPATH_PHPNAME;
$node->obj->$setNodePath($this->getNodePath() . <?php echo $table->getPhpName() ?>NodePeer::NPATH_SEP . $childIdx);
$node->obj->save($con);
$i = 1;
foreach ($node->childNodes as $childNode)
$node->insertNewChildNode($childNode, $i++, $con);
}
/**
* Adjust new/deleted status of node and all children.
*
* @param string Status to change ('New' or 'Deleted')
* @param boolean Value for status.
* @return void
*/
protected function adjustStatus($status, $b)
{
$setStatus = 'set' . $status;
$this->obj->$setStatus($b);
foreach ($this->childNodes as $childNode)
$childNode->obj->$setStatus($b);
}
/**
* Adjust path of node and all children. This is used internally when
* inserting/moving nodes.
*
* @param string Section of old path to change.
* @param string New section to replace old path with.
* @return void
*/
protected function adjustNodePath($oldBasePath, $newBasePath)
{
$setNodePath = "set" . <?php echo $table->getPhpName() ?>NodePeer::NPATH_PHPNAME;
$this->obj->$setNodePath($newBasePath .
substr($this->getNodePath(), strlen($oldBasePath)));
$this->obj->resetModified(<?php echo $table->getPhpName() ?>NodePeer::NPATH_COLNAME);
foreach ($this->childNodes as $childNode)
$childNode->adjustNodePath($oldBasePath, $newBasePath);
}
}
?>