Show:

File: platform/classes/Db/Result.php

<?php

/**
 * @module Db
 */

class Db_Result
{
	/**
	 * This class lets you use Db results from Db queries
	 * @class Db_Result
	 * @constructor
	 * @param {PDOStatement|array} $stmt The PDO statement object that this result uses
	 *  Can also be an array of PDO statements, in which case
	 *  this was the result of an aggregated query.
	 * @param {Db_Query_Interface} $query The query that was run to produce this result 
	 */
	function __construct ($stmt, Db_Query_Interface $query)
	{
		if (is_array($stmt)) {
			$this->stmts = $stmt;
			$this->stmt = isset($stmt[0]) ? $stmt[0] : null;
		} else {
			$this->stmt = $stmt;
		}
		$this->query = $query;
	}
	
	/**
	 * The PDO statement object that this result uses
	 * @property stmt
	 * @type PDOStatement
	 */
	public $stmt;
	
	/**
	 * An array of PDO statements if passed to the constructor
	 * @property $stmts
	 * @type array
	 */
	public $stmts;
	
	/**
	 * The query that was run to produce this result
	 * @property $query
	 * @type Db_Query_Mysql
	 */
	public $query;

	/**
	 * Fetches an array of database rows matching the query.
	 * The query is executed and fetchAll() is called on the result.
	 * 
	 * See [PDO documentation](http://us2.php.net/manual/en/pdostatement.fetchall.php)
	 * @method fetchAll
	 * @return {array}
	 */
	function fetchAll(
		$fetch_style = PDO::FETCH_BOTH, 
		$fetch_argument = null,
		array $ctor_args = array())
	{
		$arguments = func_get_args();
		if ($this->stmts) {
			$result = array();
			foreach ($this->stmts as $stmt) {
				$r = call_user_func_array(array($stmt, 'fetchAll'), $arguments);
				if ($r) {
					$result = array_merge($result, $r);
				}
			}
		} else {
			$result = call_user_func_array(array($this->stmt, 'fetchAll'), $arguments);
		}
		return $result;
	}
	
	/**
	 * Fetches an array of database rows matching the query.
	 * The query is executed and fetchAll() is called on the result.
	 * @param {string} [$fields_prefix=''] This is the prefix, if any, to strip out when fetching the rows.
	 * @param {string} [$by_field=null] A field name to index the array by.
	 *  If the field's value is NULL in a given row, that row is just appended
	 *  in the usual way to the array.
	 * @return {array}
	 */
	function fetchArray(
		$fields_prefix = '', 
		$by_field = null)
	{
		if (empty($fields_prefix)) {
			$fields_prefix = '';
		}
		if ($this->stmts) {
			$rows = array();
			foreach ($this->stmts as $stmt) {
				$r = $stmt->fetchAll(PDO::FETCH_ASSOC);
				if ($r) {
					$rows = array_merge($rows, $r);
				}
			}
		} else {
			$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
		}
		if (!empty($fields_prefix)) {
			$prefix_len = strlen($fields_prefix);
		}
		$result = array();
		foreach ($rows as $row) {
			if (!empty($fields_prefix)) {
				$row2 = array();
				foreach ($row as $key => $value) {
					if (strncmp($key, $fields_prefix, $prefix_len) != 0)
						continue;
					$row2[substr($key, $prefix_len)] = $value;
				}
				$row = $row2;
			}
			if ($by_field and isset($row[$by_field])) {
				$result[$row[$by_field]] = $row;
			} else {
				$result[] = $row;
			}
		}
		return $result;
	}

	/**
	 * Fetches an array of Db_Row objects (possibly extended).
	 * You can pass a prefix to strip from the field names.
	 * It will also filter the result.
	 * @method fetchDbRows
	 * @param {string} [$class_name=null] The name of the class to instantiate and fill objects from.
	 *  Must extend Db_Row. Defaults to $this->query->className
	 * @param {string} [$fields_prefix=''] This is the prefix, if any, to strip out when fetching the rows.
	 * @param {string} [$by_field=null] A field name to index the array by.
	 *  If the field's value is NULL in a given row, that row is just appended
	 *  in the usual way to the array.
	 * @return {array}
	 */
	function fetchDbRows (
		$class_name = null, 
		$fields_prefix = '',
		$by_field = null)
	{
		if (empty($fields_prefix)) {
			$fields_prefix = '';
		}
		if (empty($class_name) && isset($this->query)
		and !$this->query->getClause('JOIN')) {
			$class_name = $this->query->className;
		}
		if (empty($class_name)) {
			$class_name = 'Db_Row';
		}
		if ($class_name != 'Db_Row') {
			$parent_classes = class_parents($class_name);
			if (! in_array('Db_Row', $parent_classes)) {
				throw new Exception("Class $class_name does not extend Db_Row");
			}
		}
		
		// Build an array of Db_Row objects
		$rows = array();
		$arrs = $this->fetchAll(PDO::FETCH_ASSOC);
		foreach ($arrs as $arr) {
			$method = array($class_name, 'newRow');
			if (is_callable($method)) {
				$row = call_user_func($method, $arr, $fields_prefix);
			} else {
				$row = new $class_name(array(), false);
				$row->copyFrom($arr, $fields_prefix, false, false);
			}
			$row->init($this);
			if ($by_field and isset($row->$by_field)) {
				$rows[$row->$by_field] = $row;
			} else {
				$rows[] = $row;
			}
			$callback = array($row, "afterFetch");
			if (is_callable($callback)) {
				$row->afterFetch($this);
			}
		}
		
		return $rows;
	}
	
	/**
	 * Fetches one Db_Row object (possibly extended).
	 * You can pass a prefix to strip from the field names.
	 * It will also filter the result.
	 * @method fetchDbRow
	 * @param {string} [$class_name=null] The name of the class to instantiate and fill objects from.
	 *  Must extend Db_Row. Defaults to $this->query->className
	 * @param {string} [$fields_prefix=''] This is the prefix, if any, to strip out when fetching the rows.
	 * @return {Db_Row|boolean} Returns false if no row, otherwise returns an object of type $class_name
	 */
	function fetchDbRow(
		$class_name = null, 
		$fields_prefix = '')
	{
		if (empty($fields_prefix)) {
			$fields_prefix = '';
		}
		if (empty($class_name) and isset($this->query)
		and !$this->query->getClause('JOIN')) {
			$class_name = $this->query->className;
		}
		if (empty($class_name)) {
			$class_name = 'Db_Row';
		}
		if ($class_name != 'Db_Row') {
			$parent_classes = class_parents($class_name);
			if (! in_array('Db_Row', $parent_classes)) {
				throw new Exception("Class $class_name does not extend Db_Row");
			}
		}
		
		$arr = $this->fetch(PDO::FETCH_ASSOC);
		if (!$arr) {
			return false;
		}
		$method = array($class_name, 'newRow');
		if (is_callable($method)) {
			$row = call_user_func($method, $arr, $fields_prefix);
		} else {
			$row = new $class_name(array(), false);
			$row->copyFrom($arr, $fields_prefix, false, false);
		}
		$row->init($this);
		return $row;
	}

	/**
	 * Dumps the result as an HTML table. 
	 * Side effect, though: can't fetch anymore until the cursor is closed.
	 * @method __toMarkup
	 * @return {string}
	 */
	function __toMarkup ()
	{
		$return = "<table class='dbResultTable'>\n";
		
		try {
			$rows = $this->fetchAll(PDO::FETCH_ASSOC);
			$return .= "<tr class='heading'>\n";
			if (count($rows) > 0) {
				foreach ($rows[0] as $key => $value) {
					$return .= '<td>' . htmlentities($key) . '</td>' . "\n";
				}
			} else {
				return "<div class='dbResultTable'>Db_Result contains zero rows.</div>";
			}
			$return .= "</tr>\n";
			foreach ($rows as $row) {
				$return .= "<tr>\n";
				foreach ($row as $key => $value) {
					$return .= '<td>' . htmlentities($value) . '</td>' . "\n";
				}
				$return .= "</tr>\n";
			}
			$return .= "</table>";
			return $return;
		} catch (Exception $e) {
			return $e->getMessage();
		}
	}
	
	/**
	 * Dumps the result as a table in text mode
	 * Side effect, though: can't fetch anymore until the cursor is closed.
	 * @method __toString
	 * @return {string}
	 */
	function __toString ()
	{
		return "Db_Result";
		try {
			$ob = new Q_OutputBuffer();
			$rows = $this->fetchAll(PDO::FETCH_ASSOC);
			Db::dump_table($rows);
			return $ob->getClean();
		} catch (Exception $e) {
			return $e->getMessage();
		}
	}

	/**
	 * Forwards all other calls to the PDOStatement object
	 * @method __call
	 * @param {string} $name The function name
	 * @param {array} $arguments The arguments
	 */
	function __call ($name, array $arguments)
	{
		return call_user_func_array(array($this->stmt, $name), $arguments);
	}
}
;