Continued:
[core.git] / framework / main / classes / iterator / registry / class_RegistryIterator.php
1 <?php
2 // Own namespace
3 namespace Org\Mxchange\CoreFramework\Iterator\Registry;
4
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;
14
15 // Import SPL stuff
16 use \BadMethodCallException;
17 use \LogicException;
18 use \UnexpectedValueException;
19
20 /**
21  * A registry iterator
22  *
23  * @author              Roland Haeder <webmaster@ship-simu.org>
24  * @version             0.0.0
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
28  *
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.
33  *
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.
38  *
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/>.
41  */
42 class RegistryIterator extends BaseIterator implements IteratableRegistry {
43         // Load traits
44         use RegisterTrait;
45
46         /**
47          * All found registry keys
48          */
49         private $registryKeys = [];
50
51         /**
52          * An array containing keys ob sub-registries which keys should only be
53          * included in the iterator.
54          */
55         private $onlyRegistries = [];
56
57         /**
58          * Current array key
59          */
60         private $key = NULL;
61
62         /**
63          * Protected constructor
64          *
65          * @return      void
66          */
67         private function __construct () {
68                 // Call parent constructor
69                 parent::__construct(__CLASS__);
70
71                 // Init registry keys array
72                 $this->registryKeys = [
73                         // Generic registry
74                         'generic' => [],
75                         // Instance registry
76                         'instance' => [],
77                 ];
78         }
79
80         /**
81          * Creates an instance of this class
82          *
83          * @param       $registryInstance       An instance of a Register class
84          * @return      $iteratorInstance       An instance of a Iterator class
85          */
86         public final static function createRegistryIterator (Register $registryInstance) {
87                 // Get new instance
88                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('REGISTRY-ITERATOR: registryInstance=%s - CALLED!', $registryInstance->__toString()));
89                 $iteratorInstance = new RegistryIterator();
90
91                 // Set registry here
92                 $iteratorInstance->setRegistryInstance($registryInstance);
93
94                 // Return the prepared instance
95                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('REGISTRY-ITERATOR: iteratorInstance=%s - EXIT!', $iteratorInstance->__toString()));
96                 return $iteratorInstance;
97         }
98
99         /**
100          * Setter for only-registries array
101          *
102          * @param       $onlyRegistries         Array with keys only being iterated over
103          * @return      void
104          */
105         private function setOnlyRegistries (array $onlyRegistries) {
106                 $this->onlyRegistries = $onlyRegistries;
107         }
108
109         /**
110          * Initializes this iterator by scanning over the registry for all keys.
111          *
112          * @param       $onlyRegistries         Only iterate on these sub-registry keys, default is all
113          * @return      void
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
116          */
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);
121
122                 // Get generic registry entries from it
123                 $entries = $this->getRegistryInstance()->getGenericRegistry();
124
125                 // Anything in there?
126                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR: entries()=%d', count($entries)));
127                 if (count($entries) > 0) {
128                         // Debugging:
129                         /* DEBUG-DIE: */ ApplicationEntryPoint::exitApplication(sprintf('[%s:%d]: UNFINISHED: entries=%s', __METHOD__, __LINE__, print_r($entries, TRUE)));
130                 }
131
132                 // Get instance registry entries from it
133                 $entries = $this->getRegistryInstance()->getInstanceRegistry();
134
135                 // Anything in there?
136                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR: entries()=%d', count($entries)));
137                 if (count($entries) > 0) {
138                         // Then run over all
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') {
143                                         // Skip this!
144                                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR: key=%s is a registry key, skipping ...', $key));
145                                         continue;
146                                 }
147
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));
152                                         continue;
153                                 } elseif ($entry instanceof ObjectRegistry) {
154                                         // Get iterator from this instance
155                                         $objectRegistryInstances = $entry->getInstanceRegistry();
156
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) {
161                                                 // Add it
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);
164
165                                                 // Is the current key set?
166                                                 if (is_null($this->key)) {
167                                                         // Init 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;
170                                                 }
171                                         }
172
173                                         // Skip below code
174                                         continue;
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);
178                                 }
179
180                                 // Is the current key set?
181                                 if (is_null($this->key)) {
182                                         // Init key
183                                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR: Setting this->key=%s as first key (key) ...', $key));
184                                         $this->key = $key;
185                                 }
186
187                                 // Add key to array
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);
191                         }
192                 }
193
194                 // Trace message
195                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('REGISTRY-ITERATOR: EXIT!');
196         }
197
198         /**
199          * Getter for all registry keys (array)
200          *
201          * @return      $registryKeys   Registry keys
202          */
203         public final function getRegistryKeys () {
204                 // Return it
205                 return $this->registryKeys;
206         }
207
208         /**
209          * Getter for current value from group or generic
210          *
211          * @return      $current        Current value in iteration
212          * @throws      NullPointerException    If current key points to a non-existing entry in searched registries
213          */
214         public function current () {
215                 // Default is null
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)));
218                 $current = NULL;
219                 $entries = [];
220
221                 // Get all registries
222                 $allRegistries = $this->getRegistryInstance()->getInstanceRegistry();
223
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();
233
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()])) {
237                                         // Not found
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()));
239                                         continue;
240                                 }
241
242                                 // Set as current
243                                 $current = $instances[$this->key()];
244                                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR[%s]: current=%s', $this->key(), $current->__toString()));
245                                 break;
246                         }
247                 }
248
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);
254                 }
255
256                 // Return it
257                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('REGISTRY-ITERATOR[%s]: current[%s]=%s - EXIT!', $this->key(), gettype($current), $current));
258                 return $current;
259         }
260
261         /**
262          * Getter for key from group or generic
263          *
264          * @return      $key    Current key in iteration
265          */
266         public function key () {
267                 // Return it
268                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('REGISTRY-ITERATOR: this->key=%s EXIT!', $this->key));
269                 return $this->key;
270         }
271
272         /**
273          * Advances to the next entry
274          *
275          * @return      void
276          * @throws      BadMethodCallException  If $this->valid() returns FALSE
277          * @throws      UnexpectedValueException        If $registryType is not changed
278          */
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()) {
284                         // Bad method call!
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);
289                 }
290
291                 // Default is not valid
292                 $nextIndex = -1;
293                 $isNextValid = FALSE;
294                 $registryType = 'invalid';
295
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';
306                 }
307
308                 // Is it still valid?
309                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('REGISTRY-ITERATOR[%s]: isNextValid=%d', $this->key(), intval($isNextValid)));
310                 if (!$isNextValid) {
311                         // Throw exception
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') {
314                         // Not changed!
315                         throw new UnexpectedValueException('registryType has not been changed.', FrameworkInterface::EXCEPTION_UNEXPECTED_VALUE);
316                 }
317
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];
321
322                 // Trace message
323                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('REGISTRY-ITERATOR[%s]: EXIT!', $this->key()));
324         }
325
326         /**
327          * Rewinds to the beginning of the iteration
328          *
329          * @return      void
330          * @throws      BadMethodCallException  If $this->key is already the first element
331          */
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);
342                 }
343
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) {
350                         // Second instance
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];
353                 }
354
355                 // Trace message
356                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('REGISTRY-ITERATOR[%s]: EXIT!', $this->key()));
357         }
358
359         /**
360          * Checks wether the current entry is valid (not at the end of the list)
361          *
362          * @return      $valid  Whether the current key is still valid
363          */
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']));
369
370                 // Return flag
371                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('REGISTRY-ITERATOR[%s]: valid=%d - EXIT!', $this->key(), intval($valid)));
372                 return $valid;
373         }
374
375 }