<?php
/**
* This is template method used for query large result set in small chunk.
* All subclass must implements every abstract function in this class.
* The process of dividing result set into small chunks is transparant to the client.
* Its automagically done by the iterator.
*
* I include example implementation code in PhpMysqlLimitResultSetIterator.php
*
* So if we have "select * from my_large_table" containing 1500 rowset and we set chunkSize = 500,
* then the class will do these 3 step automagically (transparent to the client)
*
* execute_query("select * (select * from my_large_table) as subquery limit 0,500");
* execute_query("select * (select * from my_large_table) as subquery limit 500,500");
* execute_query("select * (select * from my_large_table) as subquery limit 1000,500");
*
* Any suggestion plese send to hide@address.com
*
* REQUIREMENTS:
* PHP 5
*
* @version 0.1
* @author hide@address.com
* @see PhpMysqlLimitResultSetIterator
*/
abstract class LimitResultSetIterator implements Iterator
{
/**
* Hold select query sql
*
* @access private
* @var string
*/
var $sql;
/**
* Hold chunk size for each query
*
* @access private
* @var int
*/
var $buffSize;
/**
* Hold iteration key
*
* @access private
* @var int
*/
var $key;
/**
* Hold result set object
*
* @access private
* @var Any ResultSet Type
*/
var $rs = false;
/**
* Hold current row
*
* @access private
* @var mixed
*/
var $currentRow;
/**
* Hold query stage
*
* @access private
* @var int
*/
var $stage = 0;
/**
* Create new LimitResultSetIterator instance
*
* @param string $sql
* @param int $buffSize
* @return LimitResultSetIterator
*/
function LimitResultSetIterator($sql, $buffSize = 10000)
{
$this->sql = $sql;
$this->buffSize = $buffSize;
}
/**
* Execute the SQL
* @access private
*/
function executeSql()
{
$this->rs = $this->executeLimitedSelect($this->sql, $this->buffSize, $this->getCurrentOffset());
}
/**
* Get current offset used to limit the result
* @access private
* @return int
*/
function getCurrentOffset()
{
return ($this->stage - 1) * $this->buffSize;
}
/**
* Set current row
* @access private
*/
function setCurrentRow()
{
$this->currentRow = $this->getCurrentRow($this->rs);
}
/**
* Returns the current element
* @access public
* @return mixed
*/
function current ()
{
return $this->currentRow;
}
/**
* Returns the key of the current element.
* @access public
* @return mixed
*/
function key ()
{
return $this->key;
}
/**
* Moves the current position to the next element.
* This method is called after each foreach() loop
* @access public
*/
function next ()
{
$this->key++;
$this->setCurrentRow();
}
/**
* Rewinds back to the first element of the Iterator.
* This is the first method called when starting a foreach() loop.
* It will not be executed after foreach() loops.
* @access public
*/
function rewind ()
{
$this->stage = 0;
$this->key = 0;
}
/**
* This method is called after Iterator::rewind and Iterator::next
* to check if the current position is valid.
* @access public
* @return boolean
*/
function valid ()
{
if ($this->key % $this->buffSize == 0) {
$this->stage++;
$this->closeRs($this->rs);
$this->executeSql();
$this->setCurrentRow();
}
return $this->currentRow != false;
}
/**
* Execute the SQL in LIMITED rows
*
* Example in mysql:
* return mysql_query('select * from (' . $sql . ') mysubquery limit ' . $offset . ',' . $size, $yourConnection);
*
* @access protected
* @param string $sql
* @param int $size
* @param int $offset
* @return ResultSet
*/
abstract function executeLimitedSelect($sql, $size, $offset);
/**
* Close the result set to free up memory. Called in every stage.
*
* Example in mysql:
* mysql_free_result($rs)
*
* @access protected
*/
abstract function closeRs($rs);
/**
* Get current row for that result set
*
* Example in mysql:
* return mysql_fetch_object($rs);
*
* @access protected
* @param RecordSet $rs returned by LimitResultSetIterator::executeLimitedSelect();
*/
abstract function getCurrentRow($rs);
}