| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327 |
- <?php
- /**
- * Tree data structure, used for rendering purposes.
- *
- * @author Taddeus Kroes
- * @date 13-07-2012
- */
- namespace WebBasics;
- require_once 'base.php';
- /**
- * Tree node.
- *
- * Each tree node has a (non-unique) name, a list of variables, and zero or
- * more children.
- *
- * @package WebBasics
- */
- class Node extends Base {
- /**
- * The number of Node instances, used to create unique node id's.
- *
- * @var int
- */
- private static $count = 0;
-
- /**
- * The unique id of this Bloc.
- *
- * @var int
- */
- private $id;
-
- /**
- * The node's name.
- *
- * @var string
- */
- private $name;
-
- /**
- * An optional parent node.
- *
- * If NULL, this node is the root of the data tree.
- *
- * @var Node
- */
- private $parent_node;
-
- /**
- * Child nodes.
- *
- * @var array
- */
- private $children = array();
-
- /**
- * Variables in this node.
- *
- * All variables in a node are also available in its descendants through
- * {@link get()}.
- *
- * @var array
- */
- private $variables = array();
-
- /**
- * Constructor.
- *
- * The id of the node is determined by the node counter.
- *
- * @param string $name The node's name.
- * @param Node|null &$parent_node A parent node (optional).
- * @param int|null $id An id to assign. If none is specified, a new unique
- * id is generated.
- * @uses $count
- */
- function __construct($name='', Node &$parent_node=null, $id=null) {
- $this->id = $id ? $id : ++self::$count;
- $this->name = $name;
- $this->parent_node = $parent_node;
- }
-
- /**
- * Get the node's unique id.
- *
- * @return int The node's id.
- */
- function get_id() {
- return $this->id;
- }
-
- /**
- * Get the node's name.
- *
- * @return string The node's name.
- */
- function get_name() {
- return $this->name;
- }
-
- /**
- * Get the node's parent.
- *
- * @return Node|null The parent node if any, NULL otherwise.
- */
- function get_parent() {
- return $this->parent_node;
- }
-
- /**
- * Get the node's children.
- *
- * @return array A list of child nodes.
- */
- function get_children() {
- return $this->children;
- }
-
- /**
- * Check if a node is the same instance or a copy of this node.
- *
- * @param Node $node The node to compare this node to.
- * @return bool Whether the nodes have the same unique id.
- */
- function is(Node $node) {
- return $node->get_id() == $this->id;
- }
-
- /**
- * Check if this node is the root node of the tree.
- *
- * A node is the root node if it has no parent.
- *
- * @return bool Whether this node is the root node.
- */
- function is_root() {
- return $this->parent_node === null;
- }
-
- /**
- * Check if this node is a leaf node of the tree.
- *
- * A node is a leaf if it has no children.
- *
- * @return bool Whether this node is a leaf node.
- */
- function is_leaf() {
- return !count($this->children);
- }
-
- /**
- * Add a child node.
- *
- * @param Node &$node The child node to add.
- * @param bool $set_parent Whether to set this node as the child's parent
- * (defaults to TRUE).
- */
- function add_child(Node &$node, $set_parent=true) {
- $this->children[] = $node;
- $set_parent && $node->set_parent($this);
- }
-
- /**
- * Add a child node.
- *
- * @param string $name The name of the node to add.
- * @param array $data Data to set in the created node (optional).
- * @return Node The created node.
- */
- function add($name, array $data=array()) {
- $node = new self($name, $this);
- $this->add_child($node, false);
-
- return $node->set($data);
- }
-
- /**
- * Remove a child node.
- *
- * @param Node &$child The node to remove.
- */
- function remove_child(Node &$child) {
- foreach ($this->children as $i => $node)
- $node->is($child) && array_splice($this->children, $i, 1);
- }
-
- /**
- * Remove this node from its parent.
- *
- * @throws \RuntimeException If the node has no parent.
- * @return Node This node.
- */
- function remove() {
- if ($this->is_root())
- throw new \RuntimeException('Cannot remove the root node of a tree.');
-
- $this->parent_node->remove_child($this);
-
- foreach ($this->children as $child)
- $child->set_parent(null);
-
- return $this;
- }
-
- /**
- * Set the node's parent.
- *
- * Removes this node as child of the original parent, if a parent was
- * already set.
- *
- * @param Node|null $parent The parent node to set.
- * @return Node This node.
- */
- function set_parent($parent) {
- if ($this->parent_node !== null)
- $this->parent_node->remove_child($this);
-
- $this->parent_node = &$parent;
-
- return $this;
- }
-
- /**
- * Set the value of one or more variables in the node.
- *
- * @param string|array $name Either a single variable name, or a set of name/value pairs.
- * @param mixed $value The value of a single variable to set.
- * @return Node This node.
- */
- function set($name, $value=null) {
- if (is_array($name)) {
- foreach ($name as $var => $val)
- $this->variables[$var] = $val;
- } else {
- $this->variables[$name] = $value;
- }
-
- return $this;
- }
-
- /**
- * Get the value of a variable.
- *
- * @param string $name The name of the variable to get the value of.
- * @return mixed The value of the variable if it exists, NULL otherwise.
- */
- function get($name) {
- // Variable inside this node?
- if (isset($this->variables[$name]))
- return $this->variables[$name];
-
- // Variable in one of ancestors?
- if( $this->parent_node !== null )
- return $this->parent_node->get($name);
-
- // All nodes up to the tree's root node do not contain the variable
- return null;
- }
-
- /**
- * Set the value of a variable.
- *
- * This method provides a shortcut for {@link set()}.
- *
- * @param string $name The name of the variable to set the value of.
- * @param mixed $value The value to set.
- */
- function __set($name, $value) {
- $this->set($name, $value);
- }
-
- /**
- * Get the value of a variable.
- *
- * This method provides a shortcut for {@link get()}.
- *
- * @param string $name The name of the variable to get the value of.
- * @return mixed The value of the variable if it exists, NULL otherwise.
- */
- function __get($name) {
- return $this->get($name);
- }
-
- /**
- * Find all child nodes that have the specified name.
- *
- * @param string $name The name of the nodes to find.
- * @return array The positively matched nodes.
- */
- function find($name) {
- $has_name = function($child) use ($name) {
- return $child->get_name() == $name;
- };
-
- return array_values(array_filter($this->children, $has_name));
- }
-
- /**
- * Create a copy of this node.
- *
- * The copy will have the same list of children and variables. In case of
- * a 'deep copy', the list of children is also cloned recursively.
- *
- * @param bool $deep Whether to create a deep copy.
- * @return Node A copy of this node.
- */
- function copy($deep=false) {
- $copy = new self($this->name, $this->parent_node, $this->id);
- $copy->set($this->variables);
-
- foreach ($this->children as $child) {
- if ($deep) {
- $child_copy = $child->copy(true);
- $copy->add_child($child_copy);
- } else {
- $copy->add_child($child, false);
- }
- }
-
- return $copy;
- }
- }
- ?>
|