3 namespace Org\Mxchange\CoreFramework\Iterator\Registry;
5 // Import framework stuff
6 use Org\Mxchange\CoreFramework\EntryPoint\ApplicationEntryPoint;
7 use Org\Mxchange\CoreFramework\Generic\FrameworkInterface;
8 use Org\Mxchange\CoreFramework\Generic\NullPointerException;
9 use Org\Mxchange\CoreFramework\Iterator\BaseIterator;
10 use Org\Mxchange\CoreFramework\Registry\Object\ObjectRegistry;
11 use Org\Mxchange\CoreFramework\Registry\Register;
12 use Org\Mxchange\CoreFramework\Registry\Registerable;
13 use Org\Mxchange\CoreFramework\Traits\Registry\RegisterTrait;
16 use \BadMethodCallException;
18 use \UnexpectedValueException;
23 * @author Roland Haeder <webmaster@ship-simu.org>
25 * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2023 Core Developer Team
26 * @license GNU GPL 3.0 or any newer version
27 * @link http://www.ship-simu.org
29 * This program is free software: you can redistribute it and/or modify
30 * it under the terms of the GNU General Public License as published by
31 * the Free Software Foundation, either version 3 of the License, or
32 * (at your option) any later version.
34 * This program is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 * GNU General Public License for more details.
39 * You should have received a copy of the GNU General Public License
40 * along with this program. If not, see <http://www.gnu.org/licenses/>.
42 class RegistryIterator extends BaseIterator implements IteratableRegistry {
47 * All found registry keys
49 private $registryKeys = [];
52 * An array containing keys ob sub-registries which keys should only be
53 * included in the iterator.
55 private $onlyRegistries = [];
63 * Protected constructor
67 private function __construct () {
68 // Call parent constructor
69 parent::__construct(__CLASS__);
71 // Init registry keys array
72 $this->registryKeys = [
81 * Creates an instance of this class
83 * @param $registryInstance An instance of a Register class
84 * @return $iteratorInstance An instance of a Iterator class
86 public final static function createRegistryIterator (Register $registryInstance) {
88 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('REGISTRY-ITERATOR: registryInstance=%s - CALLED!', $registryInstance->__toString()));
89 $iteratorInstance = new RegistryIterator();
92 $iteratorInstance->setRegistryInstance($registryInstance);
94 // Return the prepared instance
95 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('REGISTRY-ITERATOR: iteratorInstance=%s - EXIT!', $iteratorInstance->__toString()));
96 return $iteratorInstance;
100 * Setter for only-registries array
102 * @param $onlyRegistries Array with keys only being iterated over
105 private function setOnlyRegistries (array $onlyRegistries) {
106 $this->onlyRegistries = $onlyRegistries;
110 * Initializes this iterator by scanning over the registry for all keys.
112 * @param $onlyRegistries Only iterate on these sub-registry keys, default is all
114 * @throws LogicException If a registry entry does not implement Registerable
115 * @throws NullPointerException If criteriaKey or criteriaMethod is not set but a call-back instance is set
117 public function initIterator (array $onlyRegistries = []) {
118 // Set it in this registry
119 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('REGISTRY-ITERATOR: onlyRegistries()=%d - CALLED!', count($onlyRegistries)));
120 $this->setOnlyRegistries($onlyRegistries);
122 // Get generic registry entries from it
123 $entries = $this->getRegistryInstance()->getGenericRegistry();
125 // Anything in there?
126 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR: entries()=%d', count($entries)));
127 if (count($entries) > 0) {
129 /* DEBUG-DIE: */ ApplicationEntryPoint::exitApplication(sprintf('[%s:%d]: UNFINISHED: entries=%s', __METHOD__, __LINE__, print_r($entries, TRUE)));
132 // Get instance registry entries from it
133 $entries = $this->getRegistryInstance()->getInstanceRegistry();
135 // Anything in there?
136 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR: entries()=%d', count($entries)));
137 if (count($entries) > 0) {
139 foreach ($entries as $key => $entry) {
140 // Is an unwanted registry found?
141 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR: key=%s,entry[%s]=%s', $key, gettype($entry), $entry->__toString()));
142 if (substr($key, -8, 8) == 'registry') {
144 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR: key=%s is a registry key, skipping ...', $key));
148 // Is it an instance of a sub-registry?
149 if (count($onlyRegistries) > 0 && !in_array($key, $onlyRegistries, TRUE)) {
150 // Not in requested registries
151 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR: key=%s is not wanted, skipping ...', $key));
153 } elseif ($entry instanceof ObjectRegistry) {
154 // Get iterator from this instance
155 $objectRegistryInstances = $entry->getInstanceRegistry();
157 // Add all sub-registry keys to this registry keys array
158 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR: objectRegistryInstances()=%d', count($objectRegistryInstances)));
159 //* DEBUG-DIE: */ ApplicationEntryPoint::exitApplication(sprintf('[%s:%d]: key=%s,objectRegistryInstances=%s', __METHOD__, __LINE__, $key, print_r($objectRegistryInstances, TRUE)));
160 foreach (array_keys($objectRegistryInstances) as $subKey) {
162 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR: Adding key=%s,subKey=%s ...', $key, $subKey));
163 array_push($this->registryKeys['instance'], $subKey);
165 // Is the current key set?
166 if (is_null($this->key)) {
168 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR: Setting this->key=%s as first key (subKey) ...', $subKey));
169 $this->key = $subKey;
175 } elseif (!($entry instanceof Registerable)) {
176 // Not registerable?!
177 throw new LogicException(sprintf('entry[]=%s does not implement Registerable.', gettype($entry)), FrameworkInterface::EXCEPTION_LOGIC_EXCEPTION);
180 // Is the current key set?
181 if (is_null($this->key)) {
183 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR: Setting this->key=%s as first key (key) ...', $key));
188 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR: key=%s - Adding ...', $key));
189 //* DEBUG-DIE: */ ApplicationEntryPoint::exitApplication(sprintf('[%s:%d]: key=%s,entry=%s', __METHOD__, __LINE__, $key, print_r($entry, TRUE)));
190 array_push($this->registryKeys['instance'], $key);
195 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('REGISTRY-ITERATOR: EXIT!');
199 * Getter for all registry keys (array)
201 * @return $registryKeys Registry keys
203 public final function getRegistryKeys () {
205 return $this->registryKeys;
209 * Getter for current value from group or generic
211 * @return $current Current value in iteration
212 * @throws NullPointerException If current key points to a non-existing entry in searched registries
214 public function current () {
216 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('REGISTRY-ITERATOR[%s]: CALLED!', $this->key()));
217 //* DEBUG-DIE: */ ApplicationEntryPoint::exitApplication(sprintf('[%s:%d]: this->key(%d)[%s]=%s,this->valid=%d,this->registryKeys=%s', __METHOD__, __LINE__, strlen($this->key()), gettype($this->key()), $this->key(), intval($this->valid()), print_r($this->registryKeys, TRUE)));
221 // Get all registries
222 $allRegistries = $this->getRegistryInstance()->getInstanceRegistry();
224 // Loop through all sub-sets
225 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR[%s]: allRegistries()=%d', $this->key(), count($allRegistries)));
226 foreach ($allRegistries as $registryKey => $registryInstance) {
227 // Is this key wanted?
228 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR[%s]: registryKey=%s', $this->key(), $registryKey));
229 if (count($this->onlyRegistries) == 0 || in_array($registryKey, $this->onlyRegistries)) {
230 // Yes, then loop through them only
231 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR[%s]: registryKey=%s,this->onlyRegistries()=%d', $this->key(), $registryKey, count($this->onlyRegistries)));
232 $instances = $registryInstance->getInstanceRegistry();
234 // The key should be there
235 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR[%s]: Handling instances()=%d,registryKey=%s ...', $this->key(), count($instances), $registryKey));
236 if (!isset($instances[$this->key()])) {
238 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->warningMessage(sprintf('REGISTRY-ITERATOR[%s]: registryKey=%s has no this->key=%s - CONTINUE!', $this->key(), $registryKey, $this->key()));
243 $current = $instances[$this->key()];
244 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR[%s]: current=%s', $this->key(), $current->__toString()));
249 // Is current still NULL?
250 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR[%s]: registryKey=%s,current[]=%s', $this->key(), $registryKey, gettype($current)));
251 if (is_null($current)) {
252 // This cannot happen and indicates a logic error
253 throw new NullPointerException($this, FrameworkInterface::EXCEPTION_IS_NULL_POINTER);
257 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('REGISTRY-ITERATOR[%s]: current[%s]=%s - EXIT!', $this->key(), gettype($current), $current));
262 * Getter for key from group or generic
264 * @return $key Current key in iteration
266 public function key () {
268 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('REGISTRY-ITERATOR: this->key=%s EXIT!', $this->key));
273 * Advances to the next entry
276 * @throws BadMethodCallException If $this->valid() returns FALSE
277 * @throws UnexpectedValueException If $registryType is not changed
279 public function next () {
280 // Is valid() still TRUE?
281 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('REGISTRY-ITERATOR[%s]: CALLED!', $this->key()));
282 //* DEBUG-DIE: */ ApplicationEntryPoint::exitApplication(sprintf('[%s:%d]: this->key(%d)[%s]=%s,this->valid=%d,this->registryKeys=%s', __METHOD__, __LINE__, strlen($this->key()), gettype($this->key()), $this->key(), intval($this->valid()), print_r($this->registryKeys, TRUE)));
283 if (!$this->valid()) {
285 throw new BadMethodCallException(sprintf('this->key[%s]=%s is no longer valid, but method was called.', gettype($this->key()), $this->key()), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
286 } elseif ((count($this->registryKeys['generic']) == 0) && (count($this->registryKeys['instance']) == 0)) {
287 // Both arrays are empty
288 throw new BadMethodCallException('No array elements in "generic" and "instance" found but method called.', FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
291 // Default is not valid
293 $isNextValid = FALSE;
294 $registryType = 'invalid';
296 // Get first array element ...
297 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR[%s]: this->registryKeys[generic]()=%d,this->registryKeys[instance]()=%d', $this->key(), count($this->registryKeys['generic']), count($this->registryKeys['instance'])));
298 if (count($this->registryKeys['generic']) > 0) {
299 // First generic array
300 /* UNFINISHED */ ApplicationEntryPoint::exitApplication(sprintf('[%s:%d]: this->key(%d)[%s]=%s,this->valid=%d,this->registryKeys=%s', __METHOD__, __LINE__, strlen($this->key()), gettype($this->key()), $this->key(), intval($this->valid()), print_r($this->registryKeys, TRUE)));
301 } elseif (count($this->registryKeys['instance']) > 0) {
302 // Second instance, current key's index + 1
303 $nextIndex = array_search($this->key(), $this->registryKeys['instance']) + 1;
304 $isNextValid = isset($this->registryKeys['instance'][$nextIndex]);
305 $registryType = 'instance';
308 // Is it still valid?
309 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR[%s]: isNextValid=%d', $this->key(), intval($isNextValid)));
312 throw new BadMethodCallException(sprintf('this->key=%s is last key in this iteration. Forgot to invoke valid() before?', $this->key()), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
313 } elseif ($registryType == 'invalid') {
315 throw new UnexpectedValueException('registryType has not been changed.', FrameworkInterface::EXCEPTION_UNEXPECTED_VALUE);
318 // Yes, then advance to that entry
319 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR: Setting this->key from this->registryKeys[%s][%d] ...', $registryType, $nextIndex));
320 $this->key = $this->registryKeys[$registryType][$nextIndex];
323 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('REGISTRY-ITERATOR[%s]: EXIT!', $this->key()));
327 * Rewinds to the beginning of the iteration
330 * @throws BadMethodCallException If $this->key is already the first element
332 public function rewind () {
333 // Is current key first key?
334 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('REGISTRY-ITERATOR[%s]: CALLED!', $this->key()));
335 //* DEBUG-DIE: */ ApplicationEntryPoint::exitApplication(sprintf('[%s:%d]: this->key(%d)[%s]=%s,this->valid=%d,this->registryKeys=%s', __METHOD__, __LINE__, strlen($this->key()), gettype($this->key()), $this->key(), intval($this->valid()), print_r($this->registryKeys, TRUE)));
336 if (array_search($this->key(), $this->getRegistryKeys()) === 0) {
337 // rewind() cannot rewind first entry!
338 throw new BadMethodCallException(sprintf('this->key=%s is already first element, but method was called.', $this->key()), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
339 } elseif ((count($this->registryKeys['generic']) == 0) && (count($this->registryKeys['instance']) == 0)) {
340 // Both arrays are empty
341 throw new BadMethodCallException('No array elements in "generic" and "instance" found but method called.', FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
344 // Get first array element ...
345 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR[%s]: this->registryKeys[generic]()=%d,this->registryKeys[instance]()=%d', $this->key(), count($this->registryKeys['generic']), count($this->registryKeys['instance'])));
346 if (count($this->registryKeys['generic']) > 0) {
347 // First generic array
348 /* UNFINISHED */ ApplicationEntryPoint::exitApplication(sprintf('[%s:%d]: this->key(%d)[%s]=%s,this->valid=%d,this->registryKeys=%s', __METHOD__, __LINE__, strlen($this->key()), gettype($this->key()), $this->key(), intval($this->valid()), print_r($this->registryKeys, TRUE)));
349 } elseif (count($this->registryKeys['instance']) > 0) {
351 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage('REGISTRY-ITERATOR: Setting this->key from this->registryKeys[instance][0] ...');
352 $this->key = $this->registryKeys['instance'][0];
356 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('REGISTRY-ITERATOR[%s]: EXIT!', $this->key()));
360 * Checks wether the current entry is valid (not at the end of the list)
362 * @return $valid Whether the current key is still valid
364 public function valid () {
365 // Is the element there?
366 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('REGISTRY-ITERATOR[%s]: CALLED!', $this->key()));
367 //* DEBUG-DIE: */ ApplicationEntryPoint::exitApplication(sprintf('[%s:%d]: this->key(%d)[%s]=%s,this->registryKeys=%s', __METHOD__, __LINE__, strlen($this->key()), gettype($this->key()), $this->key(), print_r($this->registryKeys, TRUE)));
368 $valid = (in_array($this->key(), $this->registryKeys['instance']) || in_array($this->key(), $this->registryKeys['generic']));
371 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('REGISTRY-ITERATOR[%s]: valid=%d - EXIT!', $this->key(), intval($valid)));