blob: 8cb19f6f064c57e51bc7ed7863b99734c0a8e8a4 [file] [log] [blame]
<?php
/**
* File containing the ezcTreeNode 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
* under the License.
*
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @version //autogentag//
* @filesource
* @package Tree
*/
/**
* ezcTreeNode represents a node in a tree.
*
* The methods that operate on nodes (fetchChildren, fetchPath, ...,
* isSiblingOf) are all marshalled to calls on the tree (that is stored in the
* $tree private variable) itself.
*
* Example:
* <code>
* <?php
* // Creates a new node with ID 'O' and as data 'Oxygen'
* $node = new ezcTreeNode( $this->tree, 'O', 'Oxygen' );
*
* // Adds a node as child element to another already create node in a tree
* $parentNode->addChild( $node );
* ?>
* </code>
*
* To use your own implementation of tree nodes, you can override the class
* that is used by the tree by setting the nodeClassName property of the
* ezcTree class. The class must inherit from this class though.
*
* @property-read string $id The ID that uniquely identifies a node
* @property-read ezcTree $tree The tree object that this node belongs to
* @property mixed $data The data belonging to a node
* @property bool $dataFetched Whether the data for this node has been
* fetched. Should *only* be modified by
* data store implementations.
* @property bool $dataStored Whether the data for this node has been
* stored. Should *only* be modified by
* data store implementations.
*
* @package Tree
* @version //autogentag//
* @mainclass
*/
class ezcTreeNode implements ezcTreeVisitable
{
/**
* Holds the properties of this class.
*
* @var array(string=>mixed)
*/
private $properties = array();
/**
* Constructs a new ezcTreeNode object with ID $nodeId on tree $tree.
*
* If a third argument is specified it is used as data for the new node.
*
* @param ezcTree $tree
* @param string $nodeId
* @param mixed $data
*/
public function __construct( ezcTree $tree, $nodeId )
{
$this->properties['id'] = (string) $nodeId;
$this->properties['tree'] = $tree;
if ( func_num_args() === 2 )
{
$this->properties['data'] = null;
$this->properties['dataFetched'] = false;
$this->properties['dataStored'] = true;
}
else
{
$this->properties['data'] = func_get_arg( 2 );
$this->properties['dataFetched'] = true;
$this->properties['dataStored'] = false;
}
}
/**
* Returns the value of the property $name.
*
* @throws ezcBasePropertyNotFoundException if the property does not exist.
* @param string $name
* @return mixed
* @ignore
*/
public function __get( $name )
{
switch ( $name )
{
case 'data':
if ( $this->properties['dataFetched'] === false )
{
// fetch the data on the fly
$this->tree->store->fetchDataForNode( $this );
}
// break intentionally missing
case 'id':
case 'dataFetched':
case 'dataStored':
case 'tree':
return $this->properties[$name];
}
throw new ezcBasePropertyNotFoundException( $name );
}
/**
* Sets the property $name to $value.
*
* @throws ezcBasePropertyNotFoundException if the property does not exist.
* @throws ezcBasePropertyPermissionException if a read-only property is
* tried to be modified.
* @throws ezcBaseValueException if trying to assign a wrong value to
* the property
* @param string $name
* @param mixed $value
* @ignore
*/
public function __set( $name, $value )
{
switch ( $name )
{
case 'id':
case 'tree':
throw new ezcBasePropertyPermissionException( $name, ezcBasePropertyPermissionException::READ );
case 'data':
if ( !$this->properties['dataFetched'] )
{
$this->tree->store->fetchDataForNode( $this );
$this->properties['dataFetched'] = true;
}
$this->properties[$name] = $value;
$this->properties['dataStored'] = false;
$this->tree->store->storeDataForNode( $this );
return;
case 'dataFetched':
case 'dataStored':
if ( !is_bool( $value ) )
{
throw new ezcBaseValueException( $name, $value, 'boolean' );
}
$this->properties[$name] = $value;
break;
default:
throw new ezcBasePropertyNotFoundException( $name );
}
}
/**
* Returns true if the property $name is set, otherwise false.
*
* @param string $name
* @return bool
* @ignore
*/
public function __isset( $name )
{
switch ( $name )
{
case 'id':
case 'tree':
case 'data':
case 'dataFetched':
case 'dataStored':
return isset( $this->properties[$name] );
default:
return false;
}
}
/**
* Inject data.
*
* Used to set the data from a data loader. Should not be used for
* interfacing with the tree node, since the node will not be flagged as
* modified by this method.
*
* @access private
* @param string $data
* @return void
*/
public function injectData( $data )
{
$this->properties['data'] = $data;
}
/**
* Implements the accept method for visiting.
*
* @param ezcTreeVisitor $visitor
*/
public function accept( ezcTreeVisitor $visitor )
{
$visitor->visit( $this );
foreach ( $this->fetchChildren()->nodes as $childNode )
{
$childNode->accept( $visitor );
}
}
/**
* Adds the node $node as child of the current node to the tree.
*
* @param ezcTreeNode $node
*/
public function addChild( ezcTreeNode $node )
{
$this->tree->addChild( $this->id, $node );
}
/**
* Returns all the children of this node.
*
* @return ezcTreeNodeList
*/
public function fetchChildren()
{
return $this->tree->fetchChildren( $this->id );
}
/**
* Returns all the nodes in the path from the root node to this node.
*
* @return ezcTreeNodeList
*/
public function fetchPath()
{
return $this->tree->fetchPath( $this->id );
}
/**
* Returns the parent node of this node.
*
* @return ezcTreeNode
*/
public function fetchParent()
{
return $this->tree->fetchParent( $this->id );
}
/**
* Returns this node and all its children, sorted according to the
* {@link http://en.wikipedia.org/wiki/Depth-first_search Depth-first sorting}
* algorithm.
*
* @return ezcTreeNodeList
*/
public function fetchSubtreeDepthFirst()
{
return $this->tree->fetchSubtreeDepthFirst( $this->id );
}
/**
* Alias for fetchSubtreeDepthFirst().
*
* @see fetchSubtreeDepthFirst
* @return ezcTreeNodeList
*/
public function fetchSubtree()
{
return $this->fetchSubtreeDepthFirst();
}
/**
* Returns this node and all its children, sorted accoring to the
* {@link http://en.wikipedia.org/wiki/Breadth-first_search Breadth-first sorting}
* algorithm.
*
* @return ezcTreeNodeList
*/
public function fetchSubtreeBreadthFirst()
{
return $this->tree->fetchSubtreeBreadthFirst( $this->id );
}
/**
* Returns the number of direct children of this node.
*
* @return int
*/
public function getChildCount()
{
return $this->tree->getChildCount( $this->id );
}
/**
* Returns the number of children of this node, recursively iterating over
* the children.
*
* @return int
*/
public function getChildCountRecursive()
{
return $this->tree->getChildCountRecursive( $this->id );
}
/**
* Returns the distance from the root node to this node.
*
* @return int
*/
public function getPathLength()
{
return $this->tree->getPathlength( $this->id );
}
/**
* Returns whether this node has children.
*
* @return bool
*/
public function hasChildNodes()
{
return $this->tree->hasChildNodes( $this->id );
}
/**
* Returns whether this node is a direct child of the $parentNode node.
*
* @param ezcTreeNode $parentNode
*
* @return bool
*/
public function isChildOf( ezcTreeNode $parentNode )
{
return $this->tree->isChildOf( $this->id, $parentNode->id );
}
/**
* Returns whether this node is a direct or indirect child of the
* $parentNode node.
*
* @param ezcTreeNode $parentNode
*
* @return bool
*/
public function isDescendantOf( ezcTreeNode $parentNode )
{
return $this->tree->isDescendantOf( $this->id, $parentNode->id );
}
/**
* Returns whether this node, and the $child2Node node are are siblings
* (ie, they share the same parent).
*
* @param ezcTreeNode $child2Node
*
* @return bool
*/
public function isSiblingOf( ezcTreeNode $child2Node )
{
return $this->tree->isSiblingOf( $this->id, $child2Node->id );
}
/**
* Returns the text representation of a node (its ID).
*
* @return string
* @ignore
*/
public function __toString()
{
return $this->id;
}
}
?>