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\Register;
11 use Org\Mxchange\CoreFramework\Registry\Registerable;
12 use Org\Mxchange\CoreFramework\Registry\Sub\SubRegistry;
13 use Org\Mxchange\CoreFramework\Traits\Registry\RegisterTrait;
16 use \BadMethodCallException;
22 * @author Roland Haeder <webmaster@ship-simu.org>
24 * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2023 Core Developer Team
25 * @license GNU GPL 3.0 or any newer version
26 * @link http://www.ship-simu.org
28 * This program is free software: you can redistribute it and/or modify
29 * it under the terms of the GNU General Public License as published by
30 * the Free Software Foundation, either version 3 of the License, or
31 * (at your option) any later version.
33 * This program is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36 * GNU General Public License for more details.
38 * You should have received a copy of the GNU General Public License
39 * along with this program. If not, see <http://www.gnu.org/licenses/>.
41 class RegistryIterator extends BaseIterator implements IteratableRegistry {
46 * All found registry keys
48 private $registryKeys = [];
51 * An array containing keys ob sub-registries which keys should only be
52 * included in the iterator.
54 private $onlyRegistries = [];
62 * Protected constructor
66 private function __construct () {
67 // Call parent constructor
68 parent::__construct(__CLASS__);
70 // Init registry keys array
71 $this->registryKeys = [
80 * Creates an instance of this class
82 * @param $registryInstance An instance of a Register class
83 * @return $iteratorInstance An instance of a Iterator class
85 public final static function createRegistryIterator (Register $registryInstance) {
87 $iteratorInstance = new RegistryIterator();
90 $iteratorInstance->setRegistryInstance($registryInstance);
92 // Return the prepared instance
93 return $iteratorInstance;
97 * Setter for only-registries array
99 * @param $onlyRegistries Array with keys only being iterated over
102 private function setOnlyRegistries (array $onlyRegistries) {
103 $this->onlyRegistries = $onlyRegistries;
107 * Initializes this iterator by scanning over the registry for all keys.
109 * @param $onlyRegistries Only iterate on these sub-registry keys, default is all
111 * @throws LogicException If a registry entry does not implement Registerable
112 * @throws NullPointerException If criteriaKey or criteriaMethod is not set but a call-back instance is set
114 public function initIterator (array $onlyRegistries = []) {
115 // Set it in this registry
116 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR: onlyRegistries()=%d - CALLED!', count($onlyRegistries)));
117 $this->setOnlyRegistries($onlyRegistries);
119 // Get generic registry entries from it
120 $entries = $this->getRegistryInstance()->getGenericRegistry();
122 // Anything in there?
123 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[generic]: entries()=%d', count($entries)));
124 if (count($entries) > 0) {
126 /* DEBUG-DIE: */ ApplicationEntryPoint::exitApplication(sprintf('[%s:%d]: UNFINISHED: entries=%s', __METHOD__, __LINE__, print_r($entries, TRUE)));
129 // Get instance registry entries from it
130 $entries = $this->getRegistryInstance()->getInstanceRegistry();
132 // Anything in there?
133 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[instance]: entries()=%d', count($entries)));
134 if (count($entries) > 0) {
136 foreach ($entries as $key => $entry) {
137 // Is an unwanted registry found?
138 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[instance]: key=%s,entry[]=%s', $key, gettype($entry)));
139 if (substr($key, -8, 8) == 'registry') {
141 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[instance]: key=%s is a registry key, skipping ...', $key));
145 // Is it an instance of a sub-registry?
146 if (count($onlyRegistries) > 0 && !in_array($key, $onlyRegistries, TRUE)) {
147 // Not in requested registries
148 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[instance]: key=%s is not wanted, skipping ...', $key));
150 } elseif ($entry instanceof SubRegistry) {
151 // Get iterator from this instance
152 $subRegistryInstances = $entry->getInstanceRegistry();
154 // Add all sub-registry keys to this registry keys array
155 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[instance]: subRegistryInstances()=%d', count($subRegistryInstances)));
156 //* DEBUG-DIE: */ ApplicationEntryPoint::exitApplication(sprintf('[%s:%d]: key=%s,subRegistryInstances=%s', __METHOD__, __LINE__, $key, print_r($subRegistryInstances, TRUE)));
157 foreach (array_keys($subRegistryInstances) as $subKey) {
159 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[instance]: Adding key=%s,subKey=%s ...', $key, $subKey));
160 array_push($this->registryKeys['instance'], $subKey);
162 // Is the current key set?
163 if (is_null($this->key)) {
165 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[instance]: Setting subKey=%s as first key ...', $subKey));
166 $this->key = $subKey;
172 } elseif (!($entry instanceof Registerable)) {
173 // Not registerable?!
174 throw new LogicException(sprintf('entry[]=%s does not implement Registerable.', gettype($entry)), FrameworkInterface::EXCEPTION_LOGIC_EXCEPTION);
177 // Is the current key set?
178 if (is_null($this->key)) {
180 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[instance]: Setting key=%s as first key ...', $key));
185 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[instance]: key=%s - Adding ...', $key));
186 //* DEBUG-DIE: */ ApplicationEntryPoint::exitApplication(sprintf('[%s:%d]: key=%s,entry=%s', __METHOD__, __LINE__, $key, print_r($entry, TRUE)));
187 array_push($this->registryKeys['instance'], $key);
192 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('REGISTRY-ITERATOR: EXIT!');
196 * Getter for all registry keys (array)
198 * @return $registryKeys Registry keys
200 public final function getRegistryKeys () {
202 return $this->registryKeys;
206 * Getter for current value from group or generic
208 * @return $current Current value in iteration
209 * @throws NullPointerException If current key points to a non-existing entry in searched registries
211 public function current () {
213 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: CALLED!', $this->key()));
214 //* 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)));
218 // Get all registries
219 $allRegistries = $this->getRegistryInstance()->getInstanceRegistry();
221 // Loop through all sub-sets
222 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: allRegistries()=%d', $this->key(), count($allRegistries)));
223 foreach ($allRegistries as $registryKey => $registryInstance) {
224 // Is this key wanted?
225 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: registryKey=%s', $this->key(), $registryKey));
226 if (count($this->onlyRegistries) == 0 || in_array($registryKey, $this->onlyRegistries)) {
227 // Yes, then loop through them only
228 $instances = $registryInstance->getInstanceRegistry();
230 // The key should be there
231 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: Handling registryKey=%s ...', $this->key(), $registryKey));
232 //* DEBUG-DIE: */ ApplicationEntryPoint::exitApplication(sprintf('[%s:%d]: instances=%s', __METHOD__, __LINE__, print_r($instances, TRUE)));
233 if (!isset($instances[$this->key()])) {
235 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: registryKey=%s has no this->key=%s, skipping ...', $this->key(), $registryKey));
239 // Set as current element and leave loop
240 $current = $instances[$this->key()];
241 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: registryKey=%s,current=%s found. - BREAK!', $this->key(), $registryKey, $current->__toString()));
246 // Is current still NULL?
247 if (is_null($current)) {
248 // This cannot happen and indicates a logic error
249 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
253 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: current[%s]=%s - EXIT!', $this->key(), gettype($current), $current));
258 * Getter for key from group or generic
260 * @return $key Current key in iteration
262 public function key () {
264 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: EXIT!', $this->key));
269 * Advances to the next entry
272 * @throws BadMethodCallException If $this->valid() returns FALSE
273 * @throws UnexpectedValueException If $registryType is not changed
275 public function next () {
276 // Is valid() still TRUE?
277 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: CALLED!', $this->key()));
278 //* 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)));
279 if (!$this->valid()) {
281 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);
282 } elseif ((count($this->registryKeys['generic']) == 0) && (count($this->registryKeys['instance']) == 0)) {
283 // Both arrays are empty
284 throw new BadMethodCallException('No array elements in "generic" and "instance" found but method called.', FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
287 // Default is not valid
289 $isNextValid = FALSE;
290 $registryType = 'invalid';
292 // Get first array element ...
293 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: this->registryKeys[generic]()=%d,this->registryKeys[instance]()=%d', $this->key(), count($this->registryKeys['generic']), count($this->registryKeys['instance'])));
294 if (count($this->registryKeys['generic']) > 0) {
295 // First generic array
296 /* 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)));
297 } elseif (count($this->registryKeys['instance']) > 0) {
298 // Second instance, current key's index + 1
299 $nextIndex = array_search($this->key(), $this->registryKeys['instance']) + 1;
300 $isNextValid = isset($this->registryKeys['instance'][$nextIndex]);
301 $registryType = 'instance';
304 // Is it still valid?
305 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: isNextValid=%d', $this->key(), intval($isNextValid)));
308 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);
309 } elseif ($registryType == 'invalid') {
311 throw new UnexpectedValueException('registryType has not been changed.');
314 // Yes, then advance to that entry
315 $this->key = $this->registryKeys[$registryType][$nextIndex];
318 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: EXIT!', $this->key()));
322 * Rewinds to the beginning of the iteration
325 * @throws BadMethodCallException If $this->key is already the first element
327 public function rewind () {
328 // Is current key first key?
329 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: CALLED!', $this->key()));
330 //* 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)));
331 if (array_search($this->key(), $this->getRegistryKeys()) === 0) {
332 // rewind() cannot rewind first entry!
333 throw new BadMethodCallException(sprintf('this->key=%s is already first element, but method was called.', $this->key()), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
334 } elseif ((count($this->registryKeys['generic']) == 0) && (count($this->registryKeys['instance']) == 0)) {
335 // Both arrays are empty
336 throw new BadMethodCallException('No array elements in "generic" and "instance" found but method called.', FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
339 // Get first array element ...
340 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: this->registryKeys[generic]()=%d,this->registryKeys[instance]()=%d', $this->key(), count($this->registryKeys['generic']), count($this->registryKeys['instance'])));
341 if (count($this->registryKeys['generic']) > 0) {
342 // First generic array
343 /* 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)));
344 } elseif (count($this->registryKeys['instance']) > 0) {
346 $this->key = $this->registryKeys['instance'][0];
350 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: EXIT!', $this->key()));
354 * Checks wether the current entry is valid (not at the end of the list)
356 * @return $valid Whether the current key is still valid
358 public function valid () {
359 // Is the element there?
360 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: CALLED!', $this->key()));
361 //* 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)));
362 $valid = (in_array($this->key(), $this->registryKeys['instance']) || in_array($this->key(), $this->registryKeys['generic']));
365 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: valid=%d - EXIT!', $this->key(), intval($valid)));