3 namespace CoreFramework\Result\Database;
5 // Import framework stuff
6 use CoreFramework\Criteria\Local\LocalSearchCriteria;
7 use CoreFramework\Criteria\Storing\StoreableCriteria;
8 use CoreFramework\Database\Backend\BaseDatabaseBackend;
9 use CoreFramework\Request\Requestable;
10 use CoreFramework\Result\Search\SearchableResult;
13 * A database result class
15 * @author Roland Haeder <webmaster@shipsimu.org>
17 * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2017 Core Developer Team
18 * @license GNU GPL 3.0 or any newer version
19 * @link http://www.shipsimu.org
21 * This program is free software: you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation, either version 3 of the License, or
24 * (at your option) any later version.
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
31 * You should have received a copy of the GNU General Public License
32 * along with this program. If not, see <http://www.gnu.org/licenses/>.
34 class CachedDatabaseResult extends BaseDatabaseResult implements SearchableResult, UpdateableResult, SeekableIterator {
35 // Exception constants
36 const EXCEPTION_INVALID_DATABASE_RESULT = 0x1c0;
37 const EXCEPTION_RESULT_UPDATE_FAILED = 0x1c1;
40 * Current position in array
42 private $currentPos = -1;
47 private $currentRow = NULL;
52 private $resultArray = array();
55 * Array of out-dated entries
57 private $outDated = array();
62 private $affectedRows = 0;
67 private $foundValue = '';
70 * Protected constructor
74 protected function __construct () {
75 // Call parent constructor
76 parent::__construct(__CLASS__);
80 * Creates an instance of this result by a provided result array
82 * @param $resultArray The array holding the result from query
83 * @return $resultInstance An instance of this class
85 public static final function createCachedDatabaseResult (array $resultArray) {
87 $resultInstance = new CachedDatabaseResult();
89 // Set the result array
90 $resultInstance->setResultArray($resultArray);
93 $resultInstance->setAffectedRows(count($resultArray[BaseDatabaseBackend::RESULT_INDEX_ROWS]));
95 // Return the instance
96 return $resultInstance;
100 * Setter for result array
102 * @param $resultArray The array holding the result from query
105 protected final function setResultArray (array $resultArray) {
106 $this->resultArray = $resultArray;
110 * Updates the current entry by given update criteria
112 * @param $updateInstance An instance of an Updateable criteria
115 private function updateCurrentEntryByCriteria (LocalUpdateCriteria $updateInstance) {
116 // Get the current entry key
117 $entryKey = $this->key();
119 // Now get the update criteria array and update all entries
120 foreach ($updateInstance->getUpdateCriteria() as $criteriaKey => $criteriaValue) {
122 $this->resultArray[BaseDatabaseBackend::RESULT_INDEX_ROWS][$entryKey][$criteriaKey] = $criteriaValue;
124 // Mark it as out-dated
125 $this->outDated[$criteriaKey] = 1;
130 * "Iterator" method next() to advance to the next valid entry. This method
131 * does also check if result is invalid
133 * @return $nextValid Whether the next entry is valid
135 public function next () {
136 // Default is not valid
139 // Is the result valid?
140 if ($this->valid()) {
141 // Next entry found, so count one up and cache it
143 $this->currentRow = $this->resultArray[BaseDatabaseBackend::RESULT_INDEX_ROWS][$this->currentPos];
152 * Seeks for to a specified position
154 * @param $index Index to seek for
157 public function seek ($index) {
158 // Rewind to beginning
161 // Search for the entry
162 while (($this->currentPos < $index) && ($this->valid())) {
169 * Gives back the current position or null if not found
171 * @return $current Current element to give back
173 public function current () {
174 // Default is not found
177 // Does the current enty exist?
178 if (isset($this->resultArray[BaseDatabaseBackend::RESULT_INDEX_ROWS][$this->currentPos])) {
180 $current = $this->resultArray[BaseDatabaseBackend::RESULT_INDEX_ROWS][$this->currentPos];
188 * Checks if next() and rewind will give a valid result
190 * @return $isValid Whether the next/rewind entry is valid
192 public function valid () {
193 // By default nothing is valid
197 //*NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . '] this->currentPos=' . $this->currentPos);
199 // Check if all is fine ...
200 if (($this->ifStatusIsOkay()) && (isset($this->resultArray[BaseDatabaseBackend::RESULT_INDEX_ROWS][($this->currentPos + 1)])) && (isset($this->resultArray[BaseDatabaseBackend::RESULT_INDEX_ROWS][0]))) {
210 * Returns count of entries
212 * @return $isValid Whether the next/rewind entry is valid
214 public function count () {
216 return count($this->resultArray[BaseDatabaseBackend::RESULT_INDEX_ROWS]);
220 * Determines whether the status of the query was fine (BaseDatabaseBackend::RESULT_OKAY)
222 * @return $ifStatusOkay Whether the status of the query was okay
224 public function ifStatusIsOkay () {
225 $ifStatusOkay = ((isset($this->resultArray[BaseDatabaseBackend::RESULT_INDEX_STATUS])) && ($this->resultArray[BaseDatabaseBackend::RESULT_INDEX_STATUS] === BaseDatabaseBackend::RESULT_OKAY));
226 //*NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . '] ifStatusOkay=' . intval($ifStatusOkay));
227 return $ifStatusOkay;
231 * Gets the current key of iteration
233 * @return $currentPos Key from iterator
235 public function key () {
236 return $this->currentPos;
240 * Rewind to the beginning and clear array $currentRow
244 public function rewind () {
245 $this->currentPos = -1;
246 $this->currentRow = array();
250 * Searches for an entry in data result and returns it
252 * @param $criteriaInstance The criteria to look inside the data set
253 * @return $result Found result entry
256 public function searchEntry (LocalSearchCriteria $criteriaInstance) {
257 $this->debugBackTrace('[' . '[' . __METHOD__ . ':' . __LINE__ . ']: Unfinished!');
261 * Adds an update request to the database result for writing it to the
264 * @param $criteriaInstance An instance of a updateable criteria
266 * @throws ResultUpdateException If no result was updated
268 public function add2UpdateQueue (LocalUpdateCriteria $criteriaInstance) {
269 // Rewind the pointer
272 // Get search criteria
273 $searchInstance = $criteriaInstance->getSearchInstance();
275 // And start looking for the result
277 while (($this->valid()) && ($foundEntries < $searchInstance->getLimit())) {
280 $currentEntry = $this->current();
282 // Is this entry found?
283 if ($searchInstance->ifEntryMatches($currentEntry)) {
285 $this->updateCurrentEntryByCriteria($criteriaInstance);
292 // If no entry is found/updated throw an exception
293 if ($foundEntries == 0) {
294 // Throw an exception here
295 throw new ResultUpdateException($this, self::EXCEPTION_RESULT_UPDATE_FAILED);
299 $this->setAffectedRows($foundEntries);
301 // Set update instance
302 $this->setUpdateInstance($criteriaInstance);
306 * Setter for affected rows
308 * @param $rows Number of affected rows
311 public final function setAffectedRows ($rows) {
312 $this->affectedRows = $rows;
316 * Getter for affected rows
318 * @return $rows Number of affected rows
320 public final function getAffectedRows () {
321 return $this->affectedRows;
325 * Getter for found value of previous found() call
327 * @return $foundValue Found value of previous found() call
329 public final function getFoundValue () {
330 return $this->foundValue;
334 * Checks whether we have out-dated entries or not
336 * @return $needsUpdate Whether we have out-dated entries
338 public function ifDataNeedsFlush () {
339 $needsUpdate = (count($this->outDated) > 0);
344 * Adds registration elements to a given dataset instance
346 * @param $criteriaInstance An instance of a StoreableCriteria class
347 * @param $requestInstance An instance of a Requestable class
350 public function addElementsToDataSet (StoreableCriteria $criteriaInstance, Requestable $requestInstance = NULL) {
351 // Walk only through out-dated columns
352 foreach ($this->outDated as $key => $dummy) {
353 // Does this key exist?
354 //* DEBUG: */ echo "outDated: {$key}<br />\n";
355 if ($this->find($key)) {
357 $criteriaInstance->addCriteria($key, $this->getFoundValue());
363 * Find a key inside the result array
365 * @param $key The key we shall find
366 * @return $found Whether the key was found or not
368 public function find ($key) {
369 // By default nothing is found
372 // Rewind the pointer
375 // Walk through all entries
376 while ($this->valid()) {
377 // Advance to next entry
380 // Get the whole array
381 $currentEntry = $this->current();
383 // Is the element there?
384 if (isset($currentEntry[$key])) {
389 $this->foundValue = $currentEntry[$key];
391 // And stop searching
401 * Solver for result index value with call-back method
403 * @param $databaseColumn Database column where the index might be found
404 * @param $wrapperInstance The wrapper instance to ask for array element
405 * @para $callBack Call-back object for setting the index;
406 * 0=object instance,1=method name
408 * @todo Find a caching way without modifying the result array
410 public function solveResultIndex ($databaseColumn, DatabaseWrapper $wrapperInstance, array $callBack) {
411 // By default nothing is found
414 // Is the element in result itself found?
415 if ($this->find($databaseColumn)) {
417 $indexValue = $this->getFoundValue();
418 } elseif ($this->find($wrapperInstance->getIndexKey())) {
420 $indexValue = $this->getFoundValue();
424 call_user_func_array($callBack, array($indexValue));