3 namespace CoreFramework\Database\Result;
5 // Import framework stuff
6 use CoreFramework\Request\Requestable;
9 * A database result class
11 * @author Roland Haeder <webmaster@shipsimu.org>
13 * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2017 Core Developer Team
14 * @license GNU GPL 3.0 or any newer version
15 * @link http://www.shipsimu.org
17 * This program is free software: you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation, either version 3 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30 class CachedDatabaseResult extends BaseDatabaseResult implements SearchableResult, UpdateableResult, SeekableIterator {
31 // Exception constants
32 const EXCEPTION_INVALID_DATABASE_RESULT = 0x1c0;
33 const EXCEPTION_RESULT_UPDATE_FAILED = 0x1c1;
36 * Current position in array
38 private $currentPos = -1;
43 private $currentRow = NULL;
48 private $resultArray = array();
51 * Array of out-dated entries
53 private $outDated = array();
58 private $affectedRows = 0;
63 private $foundValue = '';
66 * Protected constructor
70 protected function __construct () {
71 // Call parent constructor
72 parent::__construct(__CLASS__);
76 * Creates an instance of this result by a provided result array
78 * @param $resultArray The array holding the result from query
79 * @return $resultInstance An instance of this class
81 public static final function createCachedDatabaseResult (array $resultArray) {
83 $resultInstance = new CachedDatabaseResult();
85 // Set the result array
86 $resultInstance->setResultArray($resultArray);
89 $resultInstance->setAffectedRows(count($resultArray[BaseDatabaseBackend::RESULT_INDEX_ROWS]));
91 // Return the instance
92 return $resultInstance;
96 * Setter for result array
98 * @param $resultArray The array holding the result from query
101 protected final function setResultArray (array $resultArray) {
102 $this->resultArray = $resultArray;
106 * Updates the current entry by given update criteria
108 * @param $updateInstance An instance of an Updateable criteria
111 private function updateCurrentEntryByCriteria (LocalUpdateCriteria $updateInstance) {
112 // Get the current entry key
113 $entryKey = $this->key();
115 // Now get the update criteria array and update all entries
116 foreach ($updateInstance->getUpdateCriteria() as $criteriaKey => $criteriaValue) {
118 $this->resultArray[BaseDatabaseBackend::RESULT_INDEX_ROWS][$entryKey][$criteriaKey] = $criteriaValue;
120 // Mark it as out-dated
121 $this->outDated[$criteriaKey] = 1;
126 * "Iterator" method next() to advance to the next valid entry. This method
127 * does also check if result is invalid
129 * @return $nextValid Whether the next entry is valid
131 public function next () {
132 // Default is not valid
135 // Is the result valid?
136 if ($this->valid()) {
137 // Next entry found, so count one up and cache it
139 $this->currentRow = $this->resultArray[BaseDatabaseBackend::RESULT_INDEX_ROWS][$this->currentPos];
148 * Seeks for to a specified position
150 * @param $index Index to seek for
153 public function seek ($index) {
154 // Rewind to beginning
157 // Search for the entry
158 while (($this->currentPos < $index) && ($this->valid())) {
165 * Gives back the current position or null if not found
167 * @return $current Current element to give back
169 public function current () {
170 // Default is not found
173 // Does the current enty exist?
174 if (isset($this->resultArray[BaseDatabaseBackend::RESULT_INDEX_ROWS][$this->currentPos])) {
176 $current = $this->resultArray[BaseDatabaseBackend::RESULT_INDEX_ROWS][$this->currentPos];
184 * Checks if next() and rewind will give a valid result
186 * @return $isValid Whether the next/rewind entry is valid
188 public function valid () {
189 // By default nothing is valid
193 //*NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . '] this->currentPos=' . $this->currentPos);
195 // Check if all is fine ...
196 if (($this->ifStatusIsOkay()) && (isset($this->resultArray[BaseDatabaseBackend::RESULT_INDEX_ROWS][($this->currentPos + 1)])) && (isset($this->resultArray[BaseDatabaseBackend::RESULT_INDEX_ROWS][0]))) {
206 * Returns count of entries
208 * @return $isValid Whether the next/rewind entry is valid
210 public function count () {
212 return count($this->resultArray[BaseDatabaseBackend::RESULT_INDEX_ROWS]);
216 * Determines whether the status of the query was fine (BaseDatabaseBackend::RESULT_OKAY)
218 * @return $ifStatusOkay Whether the status of the query was okay
220 public function ifStatusIsOkay () {
221 $ifStatusOkay = ((isset($this->resultArray[BaseDatabaseBackend::RESULT_INDEX_STATUS])) && ($this->resultArray[BaseDatabaseBackend::RESULT_INDEX_STATUS] === BaseDatabaseBackend::RESULT_OKAY));
222 //*NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . '] ifStatusOkay=' . intval($ifStatusOkay));
223 return $ifStatusOkay;
227 * Gets the current key of iteration
229 * @return $currentPos Key from iterator
231 public function key () {
232 return $this->currentPos;
236 * Rewind to the beginning and clear array $currentRow
240 public function rewind () {
241 $this->currentPos = -1;
242 $this->currentRow = array();
246 * Searches for an entry in data result and returns it
248 * @param $criteriaInstance The criteria to look inside the data set
249 * @return $result Found result entry
252 public function searchEntry (LocalSearchCriteria $criteriaInstance) {
253 $this->debugBackTrace('[' . '[' . __METHOD__ . ':' . __LINE__ . ']: Unfinished!');
257 * Adds an update request to the database result for writing it to the
260 * @param $criteriaInstance An instance of a updateable criteria
262 * @throws ResultUpdateException If no result was updated
264 public function add2UpdateQueue (LocalUpdateCriteria $criteriaInstance) {
265 // Rewind the pointer
268 // Get search criteria
269 $searchInstance = $criteriaInstance->getSearchInstance();
271 // And start looking for the result
273 while (($this->valid()) && ($foundEntries < $searchInstance->getLimit())) {
276 $currentEntry = $this->current();
278 // Is this entry found?
279 if ($searchInstance->ifEntryMatches($currentEntry)) {
281 $this->updateCurrentEntryByCriteria($criteriaInstance);
288 // If no entry is found/updated throw an exception
289 if ($foundEntries == 0) {
290 // Throw an exception here
291 throw new ResultUpdateException($this, self::EXCEPTION_RESULT_UPDATE_FAILED);
295 $this->setAffectedRows($foundEntries);
297 // Set update instance
298 $this->setUpdateInstance($criteriaInstance);
302 * Setter for affected rows
304 * @param $rows Number of affected rows
307 public final function setAffectedRows ($rows) {
308 $this->affectedRows = $rows;
312 * Getter for affected rows
314 * @return $rows Number of affected rows
316 public final function getAffectedRows () {
317 return $this->affectedRows;
321 * Getter for found value of previous found() call
323 * @return $foundValue Found value of previous found() call
325 public final function getFoundValue () {
326 return $this->foundValue;
330 * Checks whether we have out-dated entries or not
332 * @return $needsUpdate Whether we have out-dated entries
334 public function ifDataNeedsFlush () {
335 $needsUpdate = (count($this->outDated) > 0);
340 * Adds registration elements to a given dataset instance
342 * @param $criteriaInstance An instance of a StoreableCriteria class
343 * @param $requestInstance An instance of a Requestable class
346 public function addElementsToDataSet (StoreableCriteria $criteriaInstance, Requestable $requestInstance = NULL) {
347 // Walk only through out-dated columns
348 foreach ($this->outDated as $key => $dummy) {
349 // Does this key exist?
350 //* DEBUG: */ echo "outDated: {$key}<br />\n";
351 if ($this->find($key)) {
353 $criteriaInstance->addCriteria($key, $this->getFoundValue());
359 * Find a key inside the result array
361 * @param $key The key we shall find
362 * @return $found Whether the key was found or not
364 public function find ($key) {
365 // By default nothing is found
368 // Rewind the pointer
371 // Walk through all entries
372 while ($this->valid()) {
373 // Advance to next entry
376 // Get the whole array
377 $currentEntry = $this->current();
379 // Is the element there?
380 if (isset($currentEntry[$key])) {
385 $this->foundValue = $currentEntry[$key];
387 // And stop searching
397 * Solver for result index value with call-back method
399 * @param $databaseColumn Database column where the index might be found
400 * @param $wrapperInstance The wrapper instance to ask for array element
401 * @para $callBack Call-back object for setting the index;
402 * 0=object instance,1=method name
404 * @todo Find a caching way without modifying the result array
406 public function solveResultIndex ($databaseColumn, DatabaseWrapper $wrapperInstance, array $callBack) {
407 // By default nothing is found
410 // Is the element in result itself found?
411 if ($this->find($databaseColumn)) {
413 $indexValue = $this->getFoundValue();
414 } elseif ($this->find($wrapperInstance->getIndexKey())) {
416 $indexValue = $this->getFoundValue();
420 call_user_func_array($callBack, array($indexValue));