]> git.mxchange.org Git - core.git/blob - framework/main/classes/database/result/class_CachedDatabaseResult.php
c79eabfdb90077856adf610c06f29e7c38febb67
[core.git] / framework / main / classes / database / result / class_CachedDatabaseResult.php
1 <?php
2 // Own namespace
3 namespace Org\Mxchange\CoreFramework\Result\Database;
4
5 // Import framework stuff
6 use Org\Mxchange\CoreFramework\Criteria\Local\LocalSearchCriteria;
7 use Org\Mxchange\CoreFramework\Criteria\Local\LocalUpdateCriteria;
8 use Org\Mxchange\CoreFramework\Criteria\Storing\StoreableCriteria;
9 use Org\Mxchange\CoreFramework\Database\Frontend\DatabaseFrontend;
10 use Org\Mxchange\CoreFramework\Database\Backend\BaseDatabaseBackend;
11 use Org\Mxchange\CoreFramework\Result\Database\BaseDatabaseResult;
12 use Org\Mxchange\CoreFramework\Result\Search\SearchableResult;
13 use Org\Mxchange\CoreFramework\Result\Update\UpdateableResult;
14
15 // Import SPL stuff
16 use \InvalidArgumentException;
17 use \OutOfBoundsException;
18 use \SeekableIterator;
19
20 /**
21  * A database result class
22  *
23  * @author              Roland Haeder <webmaster@shipsimu.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.shipsimu.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 CachedDatabaseResult extends BaseDatabaseResult implements SearchableResult, UpdateableResult, SeekableIterator {
43         // Exception constants
44         const EXCEPTION_INVALID_DATABASE_RESULT = 0x1c0;
45         const EXCEPTION_RESULT_UPDATE_FAILED    = 0x1c1;
46
47         /**
48          * Current position in array
49          */
50         private $currentPos = -1;
51
52         /**
53          * Current row
54          */
55         private $currentRow = NULL;
56
57         /**
58          * Result array
59          */
60         private $resultArray = [];
61
62         /**
63          * Array of out-dated entries
64          */
65         private $outDated = [];
66
67         /**
68          * Affected rows
69          */
70         private $affectedRows = 0;
71
72         /**
73          * Found value
74          */
75         private $foundValue = '';
76
77         /**
78          * Protected constructor
79          *
80          * @return      void
81          */
82         private function __construct () {
83                 // Call parent constructor
84                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('CACHED-DATABASE-RESULT: CONSTRUCTED!');
85                 parent::__construct(__CLASS__);
86
87                 // Trace message
88                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('CACHED-DATABASE-RESULT: EXIT!');
89         }
90
91         /**
92          * Creates an instance of this result by a provided result array
93          *
94          * @param       $resultArray            The array holding the result from query
95          * @return      $resultInstance         An instance of this class
96          * @throws      InvalidArgumentException        If a parameter is invalid
97          */
98         public static final function createCachedDatabaseResult (array $resultArray) {
99                 // Misses an element?
100                 //* DEBUG-DIE: */ die(sprintf('[%s:%d]: resultArray=%s', __METHOD__, __LINE__, print_r($resultArray, true)));
101                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: resultArray()=%d - CALLED!', count($resultArray)));
102                 if (count($resultArray) == 0) {
103                         // Cannot be empty
104                         throw new InvalidArgumentException('Array "resultArray" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
105                 } elseif (!array_key_exists(BaseDatabaseResult::RESULT_NAME_ROWS, $resultArray)) {
106                         // Yes, then abort here
107                         throw new InvalidArgumentException(sprintf('resultArray(%d)=%s has no element "%s".', count($resultArray), print_r($resultArray, TRUE), BaseDatabaseResult::RESULT_NAME_ROWS));
108                 } elseif (!array_key_exists(BaseDatabaseResult::RESULT_NAME_STATUS, $resultArray)) {
109                         // Yes, then abort here
110                         throw new InvalidArgumentException(sprintf('resultArray(%d)=%s has no element "%s".', count($resultArray), print_r($resultArray, TRUE), BaseDatabaseResult::RESULT_NAME_STATUS));
111                 }
112
113                 // Get a new instance
114                 $resultInstance = new CachedDatabaseResult();
115
116                 // Set the result array
117                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('CACHED-DATABASE-RESULT: Setting resultArray()=%d ...', count($resultArray)));
118                 $resultInstance->setResultArray($resultArray);
119
120                 // Reset current position
121                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('CACHED-DATABASE-RESULT: Invoking resultInstance->resetCurrentPosition() ...');
122                 $resultInstance->resetCurrentPosition();
123
124                 // Set affected rows
125                 $resultInstance->setAffectedRows(count($resultArray[BaseDatabaseResult::RESULT_NAME_ROWS]));
126
127                 // Return the instance
128                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: resultInstance=%s - EXIT!', $resultInstance->__toString()));
129                 return $resultInstance;
130         }
131
132         /**
133          * Setter for result array
134          *
135          * @param       $resultArray    The array holding the result from query
136          * @return      void
137          */
138         protected final function setResultArray (array $resultArray) {
139                 $this->resultArray = $resultArray;
140         }
141
142         /**
143          * Updates the current entry by given update criteria
144          *
145          * @param       $updateInstance         An instance of an Updateable criteria
146          * @return      void
147          */
148         private function updateCurrentEntryByCriteria (LocalUpdateCriteria $updateInstance) {
149                 // Get the current entry key
150                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: updateInstance=%s - CALLED!', $updateInstance->__toString()));
151                 $entryKey = $this->key();
152
153                 // Now get the update criteria array and update all entries
154                 foreach ($updateInstance->getUpdateCriteria() as $criteriaKey => $criteriaValue) {
155                         // Update data
156                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('CACHED-DATABASE-RESULT: criteriaKey=%s,criteriaValue[%s]=%s', $criteriaKey, gettype($criteriaValue), $criteriaValue));
157                         $this->resultArray[BaseDatabaseResult::RESULT_NAME_ROWS][$entryKey][$criteriaKey] = $criteriaValue;
158
159                         // Mark it as out-dated
160                         $this->outDated[$criteriaKey] = 1;
161                 }
162
163                 // Trace message
164                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('CACHED-DATABASE-RESULT: EXIT!');
165         }
166
167         /**
168          * "Iterator" method next() to advance to the next valid entry. This method
169          * does also check if result is invalid
170          *
171          * @return      $nextValid      Whether the next entry is valid
172          */
173         public function next () {
174                 // Default is not valid
175                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('CACHED-DATABASE-RESULT: CALLED!');
176                 $nextValid = false;
177
178                 // Increase position
179                 $this->currentPos++;
180
181                 // Is the result valid?
182                 if ($this->valid()) {
183                         // Next entry found, so cache it
184                         $this->currentRow = $this->resultArray[BaseDatabaseResult::RESULT_NAME_ROWS][$this->currentPos];
185                         $nextValid = true;
186                 }
187
188                 // Return the result
189                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: nextValid=%d - EXIT!', intval($nextValid)));
190                 return $nextValid;
191         }
192
193         /**
194          * Seeks for to a specified position
195          *
196          * @param       $seekPosition   Position to seek to
197          * @return      void
198          * @throws      OutOfBoundsException    If the position is not seekable
199          */
200         public function seek (int $seekPosition) {
201                 // Validate parameter
202                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: seekPosition=%d - CALLED!', $seekPosition));
203                 if ($seekPosition < 0) {
204                         // Throw exception
205                         throw new OutOfBoundsException(sprintf('seekPositon=%d is not seekable', $seekPosition));
206                 }
207
208                 // Rewind to beginning
209                 $this->rewind();
210
211                 // Search for the entry
212                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('CACHED-DATABASE-RESULT: this->currentPos=%d,seekPosition=%d', $this->currentPos, $seekPosition));
213                 while (($this->currentPos < $seekPosition) && ($this->valid())) {
214                         // Continue on
215                         $this->next();
216                 }
217
218                 // Trace message
219                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('CACHED-DATABASE-RESULT: EXIT!');
220         }
221
222         /**
223          * Gives back the current position or null if not found
224          *
225          * @return      $current        Current element to give back
226          */
227         public function current () {
228                 // Default is not found
229                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('CACHED-DATABASE-RESULT: CALLED!');
230                 $current = NULL;
231
232                 // Does the current enty exist?
233                 if (isset($this->resultArray[BaseDatabaseResult::RESULT_NAME_ROWS][$this->currentPos])) {
234                         // Then get it
235                         $current = $this->resultArray[BaseDatabaseResult::RESULT_NAME_ROWS][$this->currentPos];
236                 }
237
238                 // Return the result
239                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: current[]=%s - EXIT!', gettype($current)));
240                 return $current;
241         }
242
243         /**
244          * Checks if next() and rewind will give a valid result
245          *
246          * @return      $isValid Whether the next/rewind entry is valid
247          */
248         public function valid () {
249                 // Check if all is fine ...
250                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: this->currentPos=%d - CALLED!', $this->currentPos));
251                 $isValid = ($this->ifStatusIsOkay() && isset($this->resultArray[BaseDatabaseResult::RESULT_NAME_ROWS][$this->currentPos]) && isset($this->resultArray[BaseDatabaseResult::RESULT_NAME_ROWS][0]));
252
253                 // Return the result
254                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: isValid=%d - EXIT!', intval($isValid)));
255                 return $isValid;
256         }
257
258         /**
259          * Returns count of entries
260          *
261          * @return      $isValid Whether the next/rewind entry is valid
262          */
263         public function count () {
264                 // Count rows
265                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('CACHED-DATABASE-RESULT: CALLED!');
266                 $count = count($this->resultArray[BaseDatabaseResult::RESULT_NAME_ROWS]);
267
268                 // Return it
269                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: count=%d - EXIT!', $count));
270                 return $count;
271         }
272
273         /**
274          * Determines whether the status of the query was fine (BaseDatabaseBackend::RESULT_OKAY)
275          *
276          * @return      $ifStatusOkay   Whether the status of the query was okay
277          */
278         public function ifStatusIsOkay () {
279                 // Check all conditions
280                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: this->currentPos=%d - CALLED!', $this->currentPos));
281                 $ifStatusOkay = (isset($this->resultArray[BaseDatabaseResult::RESULT_NAME_STATUS]) && $this->resultArray[BaseDatabaseResult::RESULT_NAME_STATUS] === BaseDatabaseBackend::RESULT_OKAY);
282
283                 // Return status
284                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: ifStatusOkay=%s - EXIT!', intval($ifStatusOkay)));
285                 return $ifStatusOkay;
286         }
287
288         /**
289          * Gets the current key of iteration
290          *
291          * @return      $currentPos     Key from iterator
292          */
293         public function key () {
294                 // Return current array position
295                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: this->currentPos=%d - CALLED!', $this->currentPos));
296                 return $this->currentPos;
297         }
298
299         /**
300          * Rewind to the beginning and clear array $currentRow
301          *
302          * @return      void
303          */
304         public function rewind () {
305                 // Reset both current array position and current row
306                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: this->currentPos=%d - CALLED!', $this->currentPos));
307                 $this->resetCurrentPosition();
308                 $this->currentRow = [];
309
310                 // Trace message
311                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('CACHED-DATABASE-RESULT: EXIT!');
312         }
313
314         /**
315          * Resets current array position to 0 if at least one record is there or -1
316          * if no record is there.
317          *
318          * @return      void
319          */
320         private function resetCurrentPosition () {
321                 // Reset position
322                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('CACHED-DATABASE-RESULT: CALLED!');
323                 $this->currentPos = ($this->count() > 0 ? 0 : -1);
324
325                 // Trace message
326                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: this->currentPos=%d - EXIT!', $this->currentPos));
327         }
328
329         /**
330          * Searches for an entry in data result and returns it
331          *
332          * @param       $criteriaInstance       The criteria to look inside the data set
333          * @return      $result                         Found result entry
334          * @todo        0% done
335          */
336         public function searchEntry (LocalSearchCriteria $criteriaInstance) {
337                 // Unfinished code
338                 $this->debugBackTrace(sprintf('[%s:%d]: criteriaInstance=%s', __METHOD__, __LINE__, print_r($criteriaInstance, TRUE)));
339         }
340
341         /**
342          * Adds an update request to the database result for writing it to the
343          * database layer
344          *
345          * @param       $updateInstance An instance of a updateable criteria
346          * @return      void
347          * @throws      ResultUpdateException   If no result was updated
348          */
349         public function add2UpdateQueue (LocalUpdateCriteria $updateInstance) {
350                 // Rewind the pointer
351                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: updateInstance=%s - CALLED!', $updateInstance->__toString()));
352                 $this->rewind();
353
354                 // Get search criteria
355                 $searchInstance = $updateInstance->getSearchInstance();
356
357                 // Get affected rows
358                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('CACHED-DATABASE-RESULT: searchInstance=%s', $searchInstance->__toString()));
359                 $foundEntries = $this->getAffectedRows();
360
361                 // And start looking for the result
362                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('CACHED-DATABASE-RESULT: foundEntries=%d,searchInstance->limit=%d', $foundEntries, $searchInstance->getLimit()));
363                 while (($this->valid()) && ($foundEntries < $searchInstance->getLimit())) {
364                         // Get next entry
365                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('CACHED-DATABASE-RESULT: Invoking this->next() ...');
366                         $this->next();
367
368                         // Get current entry
369                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('CACHED-DATABASE-RESULT: Invoking this->current() ...');
370                         $currentEntry = $this->current();
371
372                         // Is this entry found?
373                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: currentEntry[]=%s - EXIT!', gettype($currentEntry)));
374                         if ($searchInstance->ifEntryMatches($currentEntry)) {
375                                 // Update this entry
376                                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: Invoking this->updateCurrentEntryByCriteria(%s) ...', $updateInstance->__toString()));
377                                 $this->updateCurrentEntryByCriteria($updateInstance);
378
379                                 // Count one up
380                                 $foundEntries++;
381                                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('CACHED-DATABASE-RESULT: foundEntries=%d', $foundEntries));
382                         }
383                 }
384
385                 // If no entry is found/updated throw an exception
386                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('CACHED-DATABASE-RESULT: foundEntries=%d', $foundEntries));
387                 if ($foundEntries == 0) {
388                         // Throw an exception here
389                         throw new ResultUpdateException($this, self::EXCEPTION_RESULT_UPDATE_FAILED);
390                 }
391
392                 // Set affected rows
393                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: Invoking this->setAffectedRows(%d) ...', $foundEntries));
394                 $this->setAffectedRows($foundEntries);
395
396                 // Set update instance
397                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: Invoking this->setUpdateInstance(%s) ...', $updateInstance->__toString()));
398                 $this->setUpdateInstance($updateInstance);
399
400                 // Trace message
401                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('CACHED-DATABASE-RESULT: EXIT!');
402         }
403
404         /**
405          * Setter for affected rows
406          *
407          * @param       $rows   Number of affected rows
408          * @return      void
409          */
410         public final function setAffectedRows (int $rows) {
411                 $this->affectedRows = $rows;
412         }
413
414         /**
415          * Getter for affected rows
416          *
417          * @return      $rows   Number of affected rows
418          */
419         public final function getAffectedRows () {
420                 return $this->affectedRows;
421         }
422
423         /**
424          * Getter for found value of previous found() call
425          *
426          * @return      $foundValue             Found value of previous found() call
427          */
428         public final function getFoundValue () {
429                 return $this->foundValue;
430         }
431
432         /**
433          * Checks whether we have out-dated entries or not
434          *
435          * @return      $needsUpdate    Whether we have out-dated entries
436          */
437         public function ifDataNeedsFlush () {
438                 // Check if records are out-dated
439                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('CACHED-DATABASE-RESULT: CALLED!');
440                 $needsUpdate = (count($this->outDated) > 0);
441
442                 // Return it
443                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: needsUpdate=%d - EXIT!', intval($needsUpdate)));
444                 return $needsUpdate;
445         }
446
447         /**
448          * Adds registration elements to a given dataset instance
449          *
450          * @param       $criteriaInstance       An instance of a StoreableCriteria class
451          * @return      void
452          */
453         public function addElementsToDataSet (StoreableCriteria $criteriaInstance) {
454                 // Walk only through out-dated columns
455                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: criteriaInstance=%s - CALLED!', $criteriaInstance->__toString()));
456                 foreach ($this->outDated as $key => $dummy) {
457                         // Does this key exist?
458                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('CACHED-DATABASE-RESULT: key=%s,dummy[]=%s', $key, gettype($dummy)));
459                         if ($this->find($key)) {
460                                 // Then update it
461                                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: Invoking criteriaInstance->addCriteria(%s,foundValue[]=%s) ...', $key, gettype($this->getFoundValue())));
462                                 $criteriaInstance->addCriteria($key, $this->getFoundValue());
463                         }
464                 }
465
466                 // Trace message
467                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('CACHED-DATABASE-RESULT: EXIT!');
468         }
469
470         /**
471          * Find a key inside the result array
472          *
473          * @param       $key    The key we shall find
474          * @return      $found  Whether the key was found or not
475          * @throws      InvalidArgumentException        If a parameter is invalid
476          */
477         public function find (string $key) {
478                 // Check parameter
479                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: key=%s - CALLED!', $key));
480                 if (empty($key)) {
481                         // Throw IAE
482                         throw new InvalidArgumentException('Parameter "key" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
483                 }
484
485                 // By default nothing is found
486                 $found = false;
487
488                 // Rewind the pointer
489                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('CACHED-DATABASE-RESULT: Invoking this->rewind() ...');
490                 $this->rewind();
491
492                 // Walk through all entries
493                 while ($this->valid()) {
494                         // Advance to next entry
495                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('CACHED-DATABASE-RESULT: Invoking this->next() ...');
496                         $this->next();
497
498                         // Get the whole array
499                         $currentEntry = $this->current();
500
501                         // Is the element there?
502                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: currentEntry[]=%s - EXIT!', gettype($currentEntry)));
503                         if (isset($currentEntry[$key])) {
504                                 // Okay, found!
505                                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('CACHED-DATABASE-RESULT: key=%s is found in currentEntry', $key));
506                                 $found = true;
507
508                                 // So "cache" it
509                                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('CACHED-DATABASE-RESULT: Setting this->foundValue to currentEntry[%s][]=%s is found in currentEntry', $key, gettype($currentEntry[$key])));
510                                 $this->foundValue = $currentEntry[$key];
511
512                                 // And stop searching
513                                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage('CACHED-DATABASE-RESULT: BREAK!');
514                                 break;
515                         }
516                 }
517
518                 // Return the result
519                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: found=%d - EXIT!', intval($found)));
520                 return $found;
521         }
522
523         /**
524          * Solver for result index value with call-back method
525          *
526          * @param       $databaseColumn         Database column where the index might be found
527          * @param       $frontendInstance       The frontend instance to ask for array element
528          * @para        $callback                       Call-back object for setting the index;
529          *                                                              0=object instance,1=method name
530          * @return      void
531          * @throws      InvalidArgumentException        If a parameter is invalid
532          * @todo        Find a caching way without modifying the result array
533          */
534         public function solveResultIndex (string $databaseColumn, DatabaseFrontend $frontendInstance, array $callback) {
535                 // Check parameter
536                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: databaseColumn=%s,frontendInstance=%s,callback()=%d - CALLED!', $databaseColumn, $frontendInstance->__toString(), count($callback)));
537                 if (empty($key)) {
538                         // Throw IAE
539                         throw new InvalidArgumentException('Parameter "key" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
540                 } elseif (count($callback) != 2) {
541                         // Throw it again
542                         throw new InvalidArgumentException(sprintf('callback()=%d must be exactly 2', count($callback)), FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
543                 } elseif (!is_callable($callback)) {
544                         // Throw it again
545                         throw new InvalidArgumentException(sprintf('%s:%s() is not callable', $callback[0], $callback[1]), FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
546                 }
547
548                 // By default nothing is found
549                 $indexValue = 0;
550
551                 // Is the element in result itself found?
552                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: Invoking this->find(%s),frontendInstance->indexKey=%s ...', $databaseColumn, $frontendInstance->getIndexKey()));
553                 if ($this->find($databaseColumn)) {
554                         // Use this value
555                         $indexValue = $this->getFoundValue();
556                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('CACHED-DATABASE-RESULT: indexValue[]=%s from this->find(%s) - databaseColumn', gettype($indexValue), $databaseColumn));
557                 } elseif ($this->find($frontendInstance->getIndexKey())) {
558                         // Use this value
559                         $indexValue = $this->getFoundValue();
560                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('CACHED-DATABASE-RESULT: indexValue[]=%s from this->find(%s) - frontendInstance->indexKey', gettype($indexValue), $frontendInstance->getIndexKey()));
561                 }
562
563                 // Set the index
564                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('CACHED-DATABASE-RESULT: Invoking %s:%s(indexValue[]=%s) ...', $callback[0], $callback[1], gettype($indexValue)));
565                 call_user_func_array($callback, [$indexValue]);
566
567                 // Trace message
568                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('CACHED-DATABASE-RESULT: EXIT!');
569         }
570
571 }