NodeIterator.php
1 <?php
2 /**
3  * wCMF - wemove Content Management Framework
4  * Copyright (C) 2005-2020 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=[]) {
52  $this->end = false;
53  $this->nodeList = [];
54  $this->processedOidList = [];
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 = [];
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 : [$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 = [];
129  $this->processedOidList = [];
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 ?>
valid()
Checks if current position is valid.
key()
Return the key of the current element.
NodeIterator is used to iterate over a tree/list built of Nodes using a Depth-First-Algorithm.
current()
Return the current element.
addToQueue($nodeList)
Add nodes to the processing queue.
rewind()
Rewind the Iterator to the first element.
Node adds the concept of relations to PersistentObject.
Definition: Node.php:34
Node related interfaces and classes.
Definition: namespaces.php:26
next()
Move forward to next element.
__construct($node, $aggregationKinds=[])
Constructor.