NodeIterator.php
1 <?php
2 /**
3  * wCMF - wemove Content Management Framework
4  * Copyright (C) 2005-2015 wemove digital solutions GmbH
5  *
6  * Licensed under the terms of the MIT License.
7  *
8  * See the LICENSE file distributed with this work for
9  * additional information.
10  */
11 namespace wcmf\lib\model;
12 
14 
15 /**
16  * NodeIterator is used to iterate over a tree/list built of Nodes
17  * using a Depth-First-Algorithm. Classes used with the NodeIterator must
18  * implement the getChildren() and getOID() methods.
19  *
20  * The following example shows the usage:
21  *
22  * @code
23  * // load the node with depth 10
24  * $node = ObjectFactory::getInstance('persistenceFacade')->load(new ObjectId('Page', 300), 10);
25  *
26  * // iterate over all children
27  * $it = new NodeIterator($node);
28  * foreach($it as $oid => $obj) {
29  * echo("current object id: ".$oid);
30  * echo("current object: ".$obj);
31  * }
32  * @endcode
33  *
34  * @author ingo herwig <ingo@wemove.com>
35  */
36 class NodeIterator implements \Iterator {
37 
38  protected $_end; // indicates if the iteration is ended
39  protected $_nodeList; // the list of seen nodes
40  protected $_processedOidList; // the list of processed object ids
41  protected $_currentNode; // the node the iterator points to
42  protected $_startNode; // the start node
43  protected $_aggregationKinds; // array of aggregation kind values to follow (empty: all)
44 
45  /**
46  * Constructor.
47  * @param $node The node to start from.
48  * @param $aggregationKinds Array of aggregation kind values of relations to follow
49  * possible values: 'none', 'shared', 'composite'. Empty array means all (default: empty)
50  */
51  public function __construct($node, $aggregationKinds=array()) {
52  $this->_end = false;
53  $this->_nodeList = array();
54  $this->_processedOidList = array();
55  $this->_currentNode = $node;
56  $this->_startNode = $node;
57  $this->_aggregationKinds = $aggregationKinds;
58  }
59 
60  /**
61  * Return the current element
62  * @return Node instance
63  */
64  public function current() {
65  return $this->_currentNode;
66  }
67 
68  /**
69  * Return the key of the current element
70  * @return String, the serialized object id
71  */
72  public function key() {
73  return $this->_currentNode->getOID()->__toString();
74  }
75 
76  /**
77  * Move forward to next element
78  */
79  public function next() {
80  // the current node was processed
81  $this->_processedOidList[] = $this->_currentNode->getOID()->__toString();
82 
83  // collect navigable children for the given aggregation kinds
84  $childrenArray = array();
85  $mapper = $this->_currentNode->getMapper();
86  $relations = $mapper->getRelations('child');
87  $followAll = sizeof($this->_aggregationKinds) == 0;
88  foreach ($relations as $relation) {
89  $aggregationKind = $relation->getOtherAggregationKind();
90  if ($relation->getOtherNavigability() && ($followAll || in_array($aggregationKind, $this->_aggregationKinds))) {
91  $childValue = $this->_currentNode->getValue($relation->getOtherRole());
92  if ($childValue != null) {
93  $children = $relation->isMultiValued() ? $childValue : array($childValue);
94  foreach ($children as $child) {
95  $childrenArray[] = $child;
96  }
97  }
98  }
99  }
100  $this->addToQueue($childrenArray);
101 
102  // set current node
103  if (sizeof($this->_nodeList) != 0) {
104  $node = array_pop($this->_nodeList);
105  $oidStr = $node->getOID()->__toString();
106  // not the last node -> search for unprocessed nodes
107  while (sizeof($this->_nodeList) > 0 && in_array($oidStr, $this->_processedOidList)) {
108  $node = array_pop($this->_nodeList);
109  $oidStr = $node->getOID()->__toString();
110  }
111  // last node found, but it was processed already
112  if (sizeof($this->_nodeList) == 0 && in_array($oidStr, $this->_processedOidList)) {
113  $this->_end = true;
114  }
115  $this->_currentNode = $node;
116  }
117  else {
118  $this->_end = true;
119  }
120  return $this;
121  }
122 
123  /**
124  * Rewind the Iterator to the first element
125  */
126  public function rewind() {
127  $this->_end = false;
128  $this->_nodeList = array();
129  $this->_processedOidList = array();
130  $this->_currentNode = $this->_startNode;
131  }
132 
133  /**
134  * Checks if current position is valid
135  */
136  public function valid() {
137  return !$this->_end;
138  }
139 
140  /**
141  * Add nodes to the processing queue.
142  * @param $nodeList An array of nodes.
143  */
144  protected function addToQueue($nodeList) {
145  for ($i=sizeof($nodeList)-1; $i>=0; $i--) {
146  if ($nodeList[$i] instanceof Node) {
147  $this->_nodeList[] = $nodeList[$i];
148  }
149  }
150  }
151 }
152 ?>
next()
Move forward to next element.
Node related interfaces and classes.
Definition: namespaces.php:26
current()
Return the current element.
NodeIterator is used to iterate over a tree/list built of Nodes using a Depth-First-Algorithm.
valid()
Checks if current position is valid.
rewind()
Rewind the Iterator to the first element.
__construct($node, $aggregationKinds=array())
Constructor.
addToQueue($nodeList)
Add nodes to the processing queue.
key()
Return the key of the current element.
Node adds the concept of relations to PersistentObject.
Definition: Node.php:34