setQuery($param); } else { throw Exception('Incorrect or missing param'); } } /** * Get item from the array on specified index. This method may trigger * DB query if index is not existing. * * @param $index integer * @return mixed depending on the objectType * @access public */ public function offsetGet($index) { if($this->_debug) { $logger = Registry::get('logger'); $logger->debug('offset: ' . $index , ', count: ' . $this->count()); } if(Validate::isInteger($index)) { if(!$this->offsetExists($index)) { $this->_offset = $this->_getQueryOffset($index); $this->_executeQuery(); } return parent::offsetGet($index); } else { throw Exception('Incorrect or missing param, must be integer'); } } /** * Sets the SQL query to retrieve data from DB. MUST BE CORRECT! * * @param $sql string * @return void * @access public */ public function setQuery($sql) { $this->_query = $sql; $this->_countQuery = ''; } /** * Sets query limit. * * @param $limit integer * @return void * @access public */ public function setQueryLimit($limit) { if(Validate::isInteger($limit)) { $this->_limit = $limit; } else { throw Exception('Invalid parameter (' . $limit . '), should be integer'); } } /** * Sets remote id column name. DataEntity specific * * @param $remoteId string * @return void * @access public */ public function setRemoteId($remoteId) { $this->_remoteId = $remoteId; } /** * Sets class name of stored / returned objects. Class should extend DataEntity. * * @param $type string * @return void * @access public */ public function setObjectType($type) { $this->_objectType = $type; } /** * Sets if to write queries to debug.log * * @param $value boolean * @return void */ public function setDebug($value) { $this->_debug = $value; } /** * Magic function, used in echo or similar functions. Prevents us from getting fatals * * @see http://www.php.net/manual/en/language.oop5.magic.php#language.oop5.magic.tostring * @return string * @access public */ public function __toString() { return get_class($this); } /** * Returns iterator. Used in foreach loop * * @return ExpandableArray */ public function getIterator() { return $this; } public function count() { if(!$this->_count) { $q = preg_replace('|^select.*from|i', 'select count(*) c from', $this->_query); $db = Registry::get('db'); $result = $db->Execute($q); if($result) { $this->_count = $result->fields[0]; } } return $this->_count; } /** * Runs query on DB and replaces stored array. It calls registry to get db object. * * @return void */ private function _executeQuery() { $q = $this->_query . ' LIMIT ' . $this->_offset . ', ' . $this->_limit; $db = Registry::get('db'); $result = $db->Execute($q); if($result) { if($this->_debug) { Registry::get('logger')->debug($q); } $index = $this->_offset; $arrObjects = array(); foreach ($result as $row) { $obj = new $this->_objectType($row[$this->_remoteId]); if($obj->exists()) { $arrObjects[$index++] = $obj; } } $this->exchangeArray($arrObjects); } } /** * Counts offset that should be used in query. It will allow us to randomly access * items stored in the array. * * @param $requestedIndex * @return integer */ private function _getQueryOffset($requestedIndex) { return floor($requestedIndex / $this->_limit) * $this->_limit; } /***** Iterator Methods from here *****/ /** * Return current element * * @return mixed * @access public */ public function current() { return $this->offsetGet($this->_iteratorPos); } /** * Returns array key * * @return integer * @access public */ public function key() { return $this->_iteratorPos; } /** * Moves iterator to next element * * @return mixed * @access public */ public function next() { return $this->offsetGet(++$this->_iteratorPos); } /** * Points iterator to the first element of array * * @return void * @access public */ public function rewind() { $this->_iteratorPos = 0; } /** * Checks if there is object at that index * * @return boolean * @access public */ public function valid() { return is_object($this->offsetGet($this->_iteratorPos)); } }