]> git.mxchange.org Git - core.git/blob - framework/main/classes/iterator/registry/class_RegistryIterator.php
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\Generic\FrameworkInterface;
7 use Org\Mxchange\CoreFramework\Generic\NullPointerException;
8 use Org\Mxchange\CoreFramework\Iterator\BaseIterator;
9 use Org\Mxchange\CoreFramework\Registry\Register;
10 use Org\Mxchange\CoreFramework\Registry\Registerable;
11 use Org\Mxchange\CoreFramework\Registry\Sub\SubRegistry;
12 use Org\Mxchange\CoreFramework\Traits\Registry\RegisterTrait;
13
14 // Import SPL stuff
15 use \BadMethodCallException;
16 use \LogicException;
17
18 /**
19  * A registry iterator
20  *
21  * @author              Roland Haeder <webmaster@ship-simu.org>
22  * @version             0.0.0
23  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2020 Core Developer Team
24  * @license             GNU GPL 3.0 or any newer version
25  * @link                http://www.ship-simu.org
26  *
27  * This program is free software: you can redistribute it and/or modify
28  * it under the terms of the GNU General Public License as published by
29  * the Free Software Foundation, either version 3 of the License, or
30  * (at your option) any later version.
31  *
32  * This program is distributed in the hope that it will be useful,
33  * but WITHOUT ANY WARRANTY; without even the implied warranty of
34  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
35  * GNU General Public License for more details.
36  *
37  * You should have received a copy of the GNU General Public License
38  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
39  */
40 class RegistryIterator extends BaseIterator implements IteratableRegistry {
41         // Load traits
42         use RegisterTrait;
43
44         /**
45          * All found registry keys
46          */
47         private $registryKeys = [];
48
49         /**
50          * An array containing keys ob sub-registries which keys should only be
51          * included in the iterator.
52          */
53         private $onlyRegistries = [];
54
55         /**
56          * Current array key
57          */
58         private $key = NULL;
59
60         /**
61          * Protected constructor
62          *
63          * @return      void
64          */
65         protected function __construct () {
66                 // Call parent constructor
67                 parent::__construct(__CLASS__);
68
69                 // Init registry keys array
70                 $this->registryKeys = [
71                         // Generic registry
72                         'generic' => [],
73                         // Instance registry
74                         'instance' => [],
75                 ];
76         }
77
78         /**
79          * Creates an instance of this class
80          *
81          * @param       $registryInstance       An instance of a Register class
82          * @return      $iteratorInstance       An instance of a Iterator class
83          */
84         public final static function createRegistryIterator (Register $registryInstance) {
85                 // Get new instance
86                 $iteratorInstance = new RegistryIterator();
87
88                 // Set registry here
89                 $iteratorInstance->setRegistryInstance($registryInstance);
90
91                 // Return the prepared instance
92                 return $iteratorInstance;
93         }
94
95         /**
96          * Setter for only-registries array
97          *
98          * @param       $onlyRegistries         Array with keys only being iterated over
99          * @return      void
100          */
101         private function setOnlyRegistries (array $onlyRegistries) {
102                 $this->onlyRegistries = $onlyRegistries;
103         }
104
105         /**
106          * Initializes this iterator by scanning over the registry for all keys.
107          *
108          * @param       $onlyRegistries         Only iterate on these sub-registry keys, default is all
109          * @return      void
110          * @throws      LogicException  If a registry entry does not implement Registerable
111          * @throws      NullPointerException    If criteriaKey or criteriaMethod is not set but a call-back instance is set
112          */
113         public function initIterator (array $onlyRegistries = []) {
114                 // Set it in this registry
115                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR: onlyRegistries()=%d - CALLED!', count($onlyRegistries)));
116                 $this->setOnlyRegistries($onlyRegistries);
117
118                 // Get generic registry entries from it
119                 $entries = $this->getRegistryInstance()->getGenericRegistry();
120
121                 // Anything in there?
122                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[generic]: entries()=%d', count($entries)));
123                 if (count($entries) > 0) {
124                         // Debugging:
125                         /* DEBUG-DIE: */ ApplicationEntryPoint::exitApplication(sprintf('[%s:%d]: UNFINISHED: entries=%s', __METHOD__, __LINE__, print_r($entries, TRUE)));
126                 } // END - if
127
128                 // Get instance registry entries from it
129                 $entries = $this->getRegistryInstance()->getInstanceRegistry();
130
131                 // Anything in there?
132                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[instance]: entries()=%d', count($entries)));
133                 if (count($entries) > 0) {
134                         // Then run over all
135                         foreach ($entries as $key => $entry) {
136                                 // Is an unwanted registry found?
137                                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[instance]: key=%s,entry[]=%s', $key, gettype($entry)));
138                                 if (substr($key, -8, 8) == 'registry') {
139                                         // Skip this!
140                                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[instance]: key=%s is a registry key, skipping ...', $key));
141                                         continue;
142                                 }
143
144                                 // Is it an instance of a sub-registry?
145                                 if (count($onlyRegistries) > 0 && !in_array($key, $onlyRegistries, TRUE)) {
146                                         // Not in requested registries
147                                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[instance]: key=%s is not wanted, skipping ...', $key));
148                                         continue;
149                                 } elseif ($entry instanceof SubRegistry) {
150                                         // Get iterator from this instance
151                                         $subRegistryInstances = $entry->getInstanceRegistry();
152
153                                         // Add all sub-registry keys to this registry keys array
154                                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[instance]: subRegistryInstances()=%d', count($subRegistryInstances)));
155                                         //* DEBUG-DIE: */ ApplicationEntryPoint::exitApplication(sprintf('[%s:%d]: key=%s,subRegistryInstances=%s', __METHOD__, __LINE__, $key, print_r($subRegistryInstances, TRUE)));
156                                         foreach (array_keys($subRegistryInstances) as $subKey) {
157                                                 // Add it
158                                                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[instance]: Adding key=%s,subKey=%s ...', $key, $subKey));
159                                                 array_push($this->registryKeys['instance'], $subKey);
160
161                                                 // Is the current key set?
162                                                 if (is_null($this->key)) {
163                                                         // Init key
164                                                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[instance]: Setting subKey=%s as first key ...', $subKey));
165                                                         $this->key = $subKey;
166                                                 }
167                                         }
168
169                                         // Skip below code
170                                         continue;
171                                 } elseif (!($entry instanceof Registerable)) {
172                                         // Not registerable?!
173                                         throw new LogicException(sprintf('entry[]=%s does not implement Registerable.', gettype($entry)));
174                                 }
175
176                                 // Is the current key set?
177                                 if (is_null($this->key)) {
178                                         // Init key
179                                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[instance]: Setting key=%s as first key ...', $key));
180                                         $this->key = $key;
181                                 }
182
183                                 // Add key to array
184                                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[instance]: key=%s - Adding ...', $key));
185                                 //* DEBUG-DIE: */ ApplicationEntryPoint::exitApplication(sprintf('[%s:%d]: key=%s,entry=%s', __METHOD__, __LINE__, $key, print_r($entry, TRUE)));
186                                 array_push($this->registryKeys['instance'], $key);
187                         } // END - foreach
188                 } // END - if
189
190                 // Trace message
191                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('REGISTRY-ITERATOR: EXIT!');
192         }
193
194         /**
195          * Getter for all registry keys (array)
196          *
197          * @return      $registryKeys   Registry keys
198          */
199         public final function getRegistryKeys () {
200                 // Return it
201                 return $this->registryKeys;
202         }
203
204         /**
205          * Getter for current value from group or generic
206          *
207          * @return      $current        Current value in iteration
208          * @throws      NullPointerException    If current key points to a non-existing entry in searched registries
209          */
210         public function current () {
211                 // Default is null
212                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: CALLED!', $this->key()));
213                 //* 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)));
214                 $current = NULL;
215                 $entries = [];
216
217                 // Get all registries
218                 $allRegistries = $this->getRegistryInstance()->getInstanceRegistry();
219
220                 // Loop through all sub-sets
221                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: allRegistries()=%d', $this->key(), count($allRegistries)));
222                 foreach ($allRegistries as $registryKey => $registryInstance) {
223                         // Is this key wanted?
224                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: registryKey=%s', $this->key(), $registryKey));
225                         if (count($this->onlyRegistries) == 0 || in_array($registryKey, $this->onlyRegistries)) {
226                                 // Yes, then loop through them only
227                                 $instances = $registryInstance->getInstanceRegistry();
228
229                                 // The key should be there
230                                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: Handling registryKey=%s ...', $this->key(), $registryKey));
231                                 //* DEBUG-DIE: */ ApplicationEntryPoint::exitApplication(sprintf('[%s:%d]: instances=%s', __METHOD__, __LINE__, print_r($instances, TRUE)));
232                                 if (!isset($instances[$this->key()])) {
233                                         // Skip below code
234                                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: registryKey=%s has no this->key=%s, skipping ...', $this->key(), $registryKey));
235                                         continue;
236                                 }
237
238                                 // Set as current element and leave loop
239                                 $current = $instances[$this->key()];
240                                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: registryKey=%s,current=%s found. - BREAK!', $this->key(), $registryKey, $current->__toString()));
241                                 break;
242                         }
243                 }
244
245                 // Is current still NULL?
246                 if (is_null($current)) {
247                         // This cannot happen and indicates a logic error
248                         throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
249                 }
250
251                 // Return it
252                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: current[%s]=%s - EXIT!', $this->key(), gettype($current), $current));
253                 return $current;
254         }
255
256         /**
257          * Getter for key from group or generic
258          *
259          * @return      $key    Current key in iteration
260          */
261         public function key () {
262                 // Return it
263                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: EXIT!', $this->key));
264                 return $this->key;
265         }
266
267         /**
268          * Advances to the next entry
269          *
270          * @return      void
271          * @throws      BadMethodCallException  If $this->valid() returns FALSE
272          * @throws      UnexpectedValueException        If $registryType is not changed
273          */
274         public function next () {
275                 // Is valid() still TRUE?
276                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: CALLED!', $this->key()));
277                 //* 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)));
278                 if (!$this->valid()) {
279                         // Bad method call!
280                         throw new BadMethodCallException(sprintf('this->key[%s]=%s is no longer valid, but method was called.', gettype($this->key()), $this->key()));
281                 } elseif ((count($this->registryKeys['generic']) == 0) && (count($this->registryKeys['instance']) == 0)) {
282                         // Both arrays are empty
283                         throw new BadMethodCallException('No array elements in "generic" and "instance" found but method called.');
284                 }
285
286                 // Default is not valid
287                 $nextIndex = -1;
288                 $isNextValid = FALSE;
289                 $registryType = 'invalid';
290
291                 // Get first array element ...
292                 //* 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'])));
293                 if (count($this->registryKeys['generic']) > 0) {
294                         // First generic array
295                         /* 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)));
296                 } elseif (count($this->registryKeys['instance']) > 0) {
297                         // Second instance, current key's index + 1
298                         $nextIndex = array_search($this->key(), $this->registryKeys['instance']) + 1;
299                         $isNextValid = isset($this->registryKeys['instance'][$nextIndex]);
300                         $registryType = 'instance';
301                 }
302
303                 // Is it still valid?
304                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: isNextValid=%d', $this->key(), intval($isNextValid)));
305                 if (!$isNextValid) {
306                         // Throw exception
307                         throw new BadMethodCallException(sprintf('this->key=%s is last key in this iteration. Forgot to invoke valid() before?', $this->key()));
308                 } elseif ($registryType == 'invalid') {
309                         // Not changed!
310                         throw new UnexpectedValueException('registryType has not been changed.');
311                 }
312
313                 // Yes, then advance to that entry
314                 $this->key = $this->registryKeys[$registryType][$nextIndex];
315
316                 // Trace message
317                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: EXIT!', $this->key()));
318         }
319
320         /**
321          * Rewinds to the beginning of the iteration
322          *
323          * @return      void
324          * @throws      BadMethodCallException  If $this->key is already the first element
325          */
326         public function rewind () {
327                 // Is current key first key?
328                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: CALLED!', $this->key()));
329                 //* 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)));
330                 if (array_search($this->key(), $this->getRegistryKeys()) === 0) {
331                         // rewind() cannot rewind first entry!
332                         throw new BadMethodCallException(sprintf('this->key=%s is already first element, but method was called.', $this->key()));
333                 } elseif ((count($this->registryKeys['generic']) == 0) && (count($this->registryKeys['instance']) == 0)) {
334                         // Both arrays are empty
335                         throw new BadMethodCallException('No array elements in "generic" and "instance" found but method called.');
336                 }
337
338                 // Get first array element ...
339                 //* 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'])));
340                 if (count($this->registryKeys['generic']) > 0) {
341                         // First generic array
342                         /* 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)));
343                 } elseif (count($this->registryKeys['instance']) > 0) {
344                         // Second instance
345                         $this->key = $this->registryKeys['instance'][0];
346                 }
347
348                 // Trace message
349                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: EXIT!', $this->key()));
350         }
351
352         /**
353          * Checks wether the current entry is valid (not at the end of the list)
354          *
355          * @return      $valid  Whether the current key is still valid
356          */
357         public function valid () {
358                 // Is the element there?
359                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: CALLED!', $this->key()));
360                 //* 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)));
361                 $valid = (in_array($this->key(), $this->registryKeys['instance']) || in_array($this->key(), $this->registryKeys['generic']));
362
363                 // Return flag
364                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('REGISTRY-ITERATOR[%s]: valid=%d - EXIT!', $this->key(), intval($valid)));
365                 return $valid;
366         }
367
368 }