Location: PHPKode > scripts > Limit Result Set Iterator > limit-result-set-iterator/LimitResultSetIterator.php
<?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);	
}
Return current item: Limit Result Set Iterator