Apache Zeta Components Manual :: File Source for tree.php
Source for file tree.php
Documentation is available at tree.php
* File containing the ezcTree class.
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @version //autogentag//
* ezcTree is an abstract class from which all the tree implementations
* // Instantiating an existing tree, and creating a new tree is done through
* // the inherited classes
* // Creating a new in-memory tree
* $tree = ezcTreeMemory::create( new ezcTreeMemoryDataStore() );
* // Opening an existing tree in an XML file
* $tree = new ezcTreeXml( 'test.xml', new ezcTreeXmlInternalDataStore() );
* // Opening an existing tree from a database, using a nested set backend
* // - This retrieves data from the ezcTreeDbExternalTableDataStore store
* // using $this->dbh as database handle, $dataTable as table where to fetch
* // data from using 'id' as ID field.
* $store = new ezcTreeDbExternalTableDataStore( $this->dbh, $dataTable, 'id' );
* // - It uses the 'nested_set' table for keeping the tree structure
* $tree = new ezcTreeDbNestedSet( $this->dbh, 'nested_set', $store );
* // Fetching nodes and subtrees
* $node = $tree->fetchNodeById( 'He' );
* $nodeList = $tree->fetchSubtree( 'Pantherinae' );
* // Checking for relations between nodes
* $tree->isDescendantOf( 'Tiger', 'Panthera' );
* $tree->isSiblingOf( 'Lion', 'Leopard' );
* @property-read ezcTreeXmlDataStore $store
* The data store that is used for retrieving/storing data.
* @property string $nodeClassName
* Which class is used as tree node - this class *must* inherit
* @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.
* @version //autogentag//
abstract class ezcTree implements ezcTreeVisitable
* Holds the properties of this class.
* @var array(string=>mixed)
protected $properties =
array( 'nodeClassName' =>
'ezcTreeNode' );
* Contains whether a transaction has been started.
* Contains whether we are in a transaction commit stage.
* Contains a list of transaction items.
* @var array(ezcTreeTransactionItem)
private $transactionList =
array();
* Returns the value of the property $name.
* @throws ezcBasePropertyNotFoundException if the property does not exist.
public function __get( $name )
* Sets the property $name to $value.
* @throws ezcBasePropertyNotFoundException if the property does not exist.
* @throws ezcBasePropertyPermissionException if a read-only property is
* @throws ezcBaseValueException if trying to assign a wrong value to the
* @throws ezcBaseInvalidParentClassException
* if the class name passed as replacement for the ezcTreeNode
* classs does not inherit from the ezcTreeNode class.
public function __set( $name, $value )
// Check if the passed classname actually implements the
if ( 'ezcTreeNode' !==
$value &&
* Returns true if the property $name is set, otherwise false.
public function __isset( $name )
* This method checks whether a node ID is valid to be used in a backend.
* @throws ezcTreeInvalidNodeIDException if the node is not valid.
/* The default implementation does not check anything */
* This method generates the next node ID.
* Creates a new tree node with node ID $nodeId and $data.
* This method returns by default an object of the ezcTreeNode class,
* however if a replacement is configured through the nodeClassName property
* an object of that class is returned instead. This object is guaranteed
* to inherit from ezcTreeNode.
$this->checkNodeID( $nodeId );
return new $className( $this, $nodeId, $data );
* Implements the accept method for visiting.
* @param ezcTreeVisitor $visitor
public function accept( ezcTreeVisitor $visitor )
$visitor->visit( $this );
$root->accept( $visitor );
* Returns whether the node with ID $nodeId exists.
* Returns the node identified by the ID $nodeId.
* @throws ezcTreeUnknownIdException if there is no node with ID $nodeId
$node =
new $className( $this, $nodeId );
* Returns all the children of the node with ID $nodeId.
* @return ezcTreeNodeList
* Returns the parent node of the node with ID $nodeId.
* Returns all the nodes in the path from the root node to the node with ID
* $nodeId, including those two nodes.
* @return ezcTreeNodeList
abstract public function fetchPath( $nodeId );
* Alias for fetchSubtreeDepthFirst().
* @return ezcTreeNodeList
* Returns the node with ID $nodeId and all its children, sorted according to
* the {@link http://en.wikipedia.org/wiki/Breadth-first_search Breadth-first sorting}
* @return ezcTreeNodeList
* Returns the node with ID $nodeId and all its children, sorted according to
* the {@link http://en.wikipedia.org/wiki/Depth-first_search Depth-first sorting}
* @return ezcTreeNodeList
* Returns the number of direct children of the node with ID $nodeId.
* Returns the number of children of the node with ID $nodeId, recursively.
* Returns the distance from the root node to the node with ID $nodeId.
* Returns whether the node with ID $nodeId has children.
* Returns whether the node with ID $childId is a direct child of the node
* @param string $parentId
abstract public function isChildOf( $childId, $parentId );
* Returns whether the node with ID $childId is a direct or indirect child
* of the node with ID $parentId.
* @param string $parentId
* Returns whether the nodes with IDs $child1Id and $child2Id are siblings
* (ie, they share the same parent).
* @param string $child1Id
* @param string $child2Id
abstract public function isSiblingOf( $child1Id, $child2Id );
* Sets a new node as root node, this also wipes out the whole tree.
* @param ezcTreeNode $node
abstract public function setRootNode( ezcTreeNode $node );
* Adds the node $childNode as child of the node with ID $parentId.
* @param string $parentId
* @param ezcTreeNode $childNode
abstract public function addChild( $parentId, ezcTreeNode $childNode );
* Deletes the node with ID $nodeId from the tree, including all its children.
abstract public function delete( $nodeId );
* Moves the node with ID $nodeId as child to the node with ID $targetParentId.
* @param string $targetParentId
abstract public function move( $nodeId, $targetParentId );
* Copies all the children of node $fromNode to node $toNode recursively.
* This method copies all children recursively from $fromNode to $toNode.
* The $fromNode belongs to the $from tree and the $toNode to the $to tree.
* Data associated with the nodes is copied as well from the store
* associated with the $from tree to the $to tree.
* @param ezcTreeNode $fromNode
* @param ezcTreeNode $toNode
private static function copyChildren( ezcTree $from, ezcTree $to, ezcTreeNode $fromNode, ezcTreeNode $toNode )
$children =
$fromNode->fetchChildren();
$fromChildNode =
$from->fetchNodeById( $childNodeKey );
$toChildNode =
new ezcTreeNode( $to, $childNodeKey, $childNodeData );
$toNode->addChild( $toChildNode );
self::copyChildren( $from, $to, $fromChildNode, $toChildNode );
* Copies the tree in $from to the empty tree in $to.
* This method copies all the nodes, including associated data from the
* used data store, from the tree $from to the tree $to. Because this
* function uses internally setRootNode() the target tree will be cleared
* out automatically. The method will not check whether the $from and $to
* trees share the same database table or data store, so make sure they are
* different to prevent unexpected behavior.
public static function copy( ezcTree $from, ezcTree $to )
$fromRootNode =
$from->getRootNode();
$to->setRootNode( new ezcTreeNode( $to, $fromRootNode->id, $fromRootNode->data ) );
$toRootNode =
$to->getRootNode();
self::copyChildren( $from, $to, $fromRootNode, $toRootNode );
* Returns whether we are currently in a transaction or not
* Returns whether we are currently in a transaction commit state or not
* Starts an transaction in which all tree modifications are queued until
* the transaction is committed with the commit() method.
$this->transactionList =
array();
* Commits the transaction by running the stored instructions to modify
foreach ( $this->transactionList as $transactionItem )
switch ( $transactionItem->type )
case ezcTreeTransactionItem::ADD:
$this->addChild( $transactionItem->parentId, $transactionItem->node );
case ezcTreeTransactionItem::DELETE:
$this->delete( $transactionItem->nodeId );
case ezcTreeTransactionItem::MOVE:
$this->move( $transactionItem->nodeId, $transactionItem->parentId );
$this->fixateTransaction();
* Adds a new transaction item to the list.
* @param ezcTreeTransactionItem $item
$this->transactionList[] =
$item;
* Rolls back the transaction by clearing all stored instructions.
$this->transactionList =
array();