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