1
0
mirror of https://github.com/dg/dibi.git synced 2025-02-24 02:43:09 +01:00
php-dibi/dibi/libs/DibiResult.php

489 lines
11 KiB
PHP
Raw Normal View History

2006-06-04 23:06:33 +00:00
<?php
/**
* dibi - tiny'n'smart database abstraction layer
* ----------------------------------------------
*
* Copyright (c) 2005, 2007 David Grudl aka -dgx- (http://www.dgx.cz)
*
* This source file is subject to the "dibi license" that is bundled
* with this package in the file license.txt.
*
* For more information please see http://php7.org/dibi/
2006-06-04 23:06:33 +00:00
*
* @copyright Copyright (c) 2005, 2007 David Grudl
* @license http://php7.org/dibi/license dibi license
* @link http://php7.org/dibi/
* @package dibi
2006-06-04 23:06:33 +00:00
*/
/**
* dibi result-set abstract class
*
* <code>
* $result = dibi::query('SELECT * FROM [table]');
*
* $row = $result->fetch();
2006-06-04 23:06:33 +00:00
* $value = $result->fetchSingle();
* $table = $result->fetchAll();
* $pairs = $result->fetchPairs();
* $assoc = $result->fetchAssoc('id');
* $assoc = $result->fetchAssoc('active', 'id');
*
2006-06-04 23:06:33 +00:00
* unset($result);
* </code>
*
* @author David Grudl
* @copyright Copyright (c) 2005, 2007 David Grudl
* @package dibi
* @version $Revision$ $Date$
2006-06-04 23:06:33 +00:00
*/
class DibiResult extends NObject implements IteratorAggregate, Countable
2006-06-04 23:06:33 +00:00
{
/**
* DibiDriverInterface
2006-06-04 23:06:33 +00:00
* @var array
*/
private $driver;
2006-06-04 23:06:33 +00:00
/**
* Describes columns types
* @var array
*/
protected $convert;
/**
* Describes columns types
* @var array
*/
protected $meta;
/**
* Already fetched? Used for allowance for first seek(0)
* @var bool
*/
protected $fetched = FALSE;
2007-06-25 23:47:05 +00:00
private static $types = array(
dibi::FIELD_TEXT => 'string',
dibi::FIELD_BINARY => 'string',
dibi::FIELD_BOOL => 'bool',
dibi::FIELD_INTEGER => 'int',
dibi::FIELD_FLOAT => 'float',
dibi::FIELD_COUNTER => 'int',
);
2006-06-04 23:06:33 +00:00
public function __construct($driver)
{
$this->driver = $driver;
}
/**
* Returns the resultset resource
*
* @return mixed
*/
final public function getResource()
{
return $this->driver->getResultResource();
}
2006-06-04 23:06:33 +00:00
/**
* Moves cursor position without fetching row
*
2006-06-04 23:06:33 +00:00
* @param int the 0-based cursor pos to seek to
* @return void
* @throws DibiException
2006-06-04 23:06:33 +00:00
*/
final public function seek($row)
{
if ($row === 0 && !$this->fetched) {
return TRUE;
}
$this->driver->seek($row);
}
2006-06-04 23:06:33 +00:00
2006-06-04 23:06:33 +00:00
/**
* Returns the number of rows in a result set
*
2006-06-04 23:06:33 +00:00
* @return int
*/
final public function rowCount()
{
return $this->driver->rowCount();
}
2006-06-04 23:06:33 +00:00
/**
* Fetches the row at current position, process optional type conversion
* and moves the internal cursor to the next position
*
2007-06-25 17:02:12 +00:00
* @return array|FALSE array on success, FALSE if no next record
2006-06-04 23:06:33 +00:00
*/
final public function fetch()
{
$row = $this->driver->fetch();
if (!is_array($row)) return FALSE;
$this->fetched = TRUE;
2006-06-04 23:06:33 +00:00
// types-converting?
if ($t = $this->convert) { // little speed-up
2007-06-25 17:02:12 +00:00
foreach ($row as $key => $value) {
if (isset($t[$key])) {
2007-06-25 17:02:12 +00:00
$row[$key] = $this->convert($value, $t[$key]);
}
2006-06-04 23:06:33 +00:00
}
}
2007-06-25 17:02:12 +00:00
return $row;
2006-06-04 23:06:33 +00:00
}
/**
* Like fetch(), but returns only first field
*
2006-06-04 23:06:33 +00:00
* @return mixed value on success, FALSE if no next record
*/
final function fetchSingle()
{
$row = $this->driver->fetch();
if (!is_array($row)) return FALSE;
$this->fetched = TRUE;
2006-06-04 23:06:33 +00:00
// types-converting?
if ($t = $this->convert) { // little speed-up
2007-06-25 17:02:12 +00:00
$value = reset($row);
$key = key($row);
2006-06-04 23:06:33 +00:00
return isset($t[$key])
? $this->convert($value, $t[$key])
: $value;
}
2007-06-25 17:02:12 +00:00
return reset($row);
2006-06-04 23:06:33 +00:00
}
/**
2007-02-05 05:14:48 +00:00
* Fetches all records from table.
*
2006-06-04 23:06:33 +00:00
* @return array
*/
final function fetchAll()
{
$this->seek(0);
2007-06-25 17:02:12 +00:00
$row = $this->fetch();
if (!$row) return array(); // empty resultset
2006-06-04 23:06:33 +00:00
2007-06-25 17:02:12 +00:00
$data = array();
if (count($row) === 1) {
$key = key($row);
2006-06-04 23:06:33 +00:00
do {
2007-06-25 17:02:12 +00:00
$data[] = $row[$key];
} while ($row = $this->fetch());
2006-06-04 23:06:33 +00:00
} else {
do {
2007-06-25 17:02:12 +00:00
$data[] = $row;
} while ($row = $this->fetch());
2006-06-04 23:06:33 +00:00
}
2007-06-25 17:02:12 +00:00
return $data;
}
/**
2007-02-05 05:14:48 +00:00
* Fetches all records from table and returns associative tree
* Associative descriptor: assoc1,*,assoc2,#,assco3
2007-06-25 17:02:12 +00:00
* builds a tree: $data[value1][index][value2]['assoc3'][value3] = {record}
2007-02-05 05:14:48 +00:00
*
* @param string associative descriptor
* @return array
* @throws InvalidArgumentException
*/
2007-02-05 05:14:48 +00:00
final function fetchAssoc($assoc)
{
$this->seek(0);
2007-06-25 17:02:12 +00:00
$row = $this->fetch();
if (!$row) return array(); // empty resultset
2007-06-25 17:02:12 +00:00
$data = NULL;
2007-02-05 05:14:48 +00:00
$assoc = explode(',', $assoc);
// check fields
foreach ($assoc as $as) {
if ($as !== '*' && $as !== '#' && !array_key_exists($as, $row)) {
throw new InvalidArgumentException("Unknown column '$as' in associative descriptor");
}
}
2007-02-05 05:14:48 +00:00
if (count($assoc) === 1) { // speed-up
$as = $assoc[0];
do {
2007-06-25 17:02:12 +00:00
$data[ $row[$as] ] = $row;
} while ($row = $this->fetch());
return $data;
2007-02-05 05:14:48 +00:00
}
2007-02-05 05:14:48 +00:00
$last = count($assoc) - 1;
if ($assoc[$last] === '#') unset($assoc[$last]);
2007-02-05 05:14:48 +00:00
// make associative tree
do {
2007-06-25 17:02:12 +00:00
$x = & $data;
2007-02-05 05:14:48 +00:00
// iterative deepening
foreach ($assoc as $i => $as) {
if ($as === '*') { // indexed-array node
$x = & $x[];
} elseif ($as === '#') { // "record" node
if ($x === NULL) {
2007-06-25 17:02:12 +00:00
$x = $row;
2007-02-05 05:14:48 +00:00
$x = & $x[ $assoc[$i+1] ];
$x = NULL; // prepare child node
} else {
$x = & $x[ $assoc[$i+1] ];
}
} else { // associative-array node
2007-06-25 17:02:12 +00:00
$x = & $x[ $row[ $as ] ];
2007-02-05 05:14:48 +00:00
}
2006-06-04 23:06:33 +00:00
}
2007-06-25 17:02:12 +00:00
if ($x === NULL) $x = $row; // build leaf
2006-06-04 23:06:33 +00:00
2007-06-25 17:02:12 +00:00
} while ($row = $this->fetch());
2006-06-04 23:06:33 +00:00
2007-02-05 05:14:48 +00:00
unset($x);
2007-06-25 17:02:12 +00:00
return $data;
2006-06-04 23:06:33 +00:00
}
2007-02-05 05:14:48 +00:00
2006-06-04 23:06:33 +00:00
/**
* Fetches all records from table like $key => $value pairs
*
2007-04-25 08:19:03 +00:00
* @param string associative key
* @param string value
2006-06-04 23:06:33 +00:00
* @return array
* @throws InvalidArgumentException
2006-06-04 23:06:33 +00:00
*/
final function fetchPairs($key = NULL, $value = NULL)
2006-06-04 23:06:33 +00:00
{
$this->seek(0);
2007-06-25 17:02:12 +00:00
$row = $this->fetch();
if (!$row) return array(); // empty resultset
2006-06-04 23:06:33 +00:00
2007-06-25 17:02:12 +00:00
$data = array();
2007-06-11 00:25:48 +00:00
2007-04-25 08:19:03 +00:00
if ($value === NULL) {
if ($key !== NULL) {
throw new InvalidArgumentException("Either none or both fields must be specified");
}
if (count($row) < 2) {
throw new LoginException("Result must have at least two columns");
}
2007-06-11 00:25:48 +00:00
// autodetect
2007-06-25 17:02:12 +00:00
$tmp = array_keys($row);
2007-04-25 08:19:03 +00:00
$key = $tmp[0];
$value = $tmp[1];
2007-06-11 00:25:48 +00:00
2007-04-25 08:19:03 +00:00
} else {
if (!array_key_exists($value, $row)) {
throw new InvalidArgumentException("Unknown value column '$value'");
}
2007-06-11 00:25:48 +00:00
if ($key === NULL) { // indexed-array
2007-06-11 00:25:48 +00:00
do {
2007-06-25 17:02:12 +00:00
$data[] = $row[$value];
} while ($row = $this->fetch());
return $data;
2007-06-11 00:25:48 +00:00
}
if (!array_key_exists($key, $row)) {
throw new InvalidArgumentException("Unknown key column '$key'");
}
2007-04-25 08:19:03 +00:00
}
2006-06-04 23:06:33 +00:00
do {
2007-06-25 17:02:12 +00:00
$data[ $row[$key] ] = $row[$value];
} while ($row = $this->fetch());
2006-06-04 23:06:33 +00:00
2007-06-25 17:02:12 +00:00
return $data;
2006-06-04 23:06:33 +00:00
}
/**
* Automatically frees the resources allocated for this result set
*
2006-06-04 23:06:33 +00:00
* @return void
*/
public function __destruct()
{
@$this->driver->free();
2006-06-04 23:06:33 +00:00
}
final public function setType($field, $type = NULL)
2006-06-04 23:06:33 +00:00
{
if ($field === TRUE) {
$this->buildMeta();
2006-06-04 23:06:33 +00:00
} elseif (is_array($field)) {
2006-06-04 23:06:33 +00:00
$this->convert = $field;
} else {
2006-06-04 23:06:33 +00:00
$this->convert[$field] = $type;
}
2006-06-04 23:06:33 +00:00
}
2006-06-04 23:06:33 +00:00
/** is this needed? */
final public function getType($field)
2006-06-04 23:06:33 +00:00
{
return isset($this->convert[$field]) ? $this->convert[$field] : NULL;
}
final public function convert($value, $type)
2006-06-04 23:06:33 +00:00
{
if ($value === NULL || $value === FALSE) {
2006-06-04 23:06:33 +00:00
return $value;
}
2006-06-04 23:06:33 +00:00
if (isset(self::$types[$type])) {
settype($value, self::$types[$type]);
2006-06-04 23:06:33 +00:00
return $value;
}
if ($type === dibi::FIELD_DATE || $type === dibi::FIELD_DATETIME) {
2006-06-07 15:50:32 +00:00
return strtotime($value); // !!! not good
}
2006-06-04 23:06:33 +00:00
return $value;
}
/**
* Gets an array of field names
*
* @return array
*/
final public function getFields()
{
$this->buildMeta();
return array_keys($this->meta);
}
/**
* Gets an array of meta informations about column
*
* @param string column name
* @return array
*/
final public function getMetaData($field)
{
$this->buildMeta();
return isset($this->meta[$field]) ? $this->meta[$field] : FALSE;
}
/**
* Acquires ....
*
* @return void
*/
final protected function buildMeta()
{
if ($this->meta === NULL) {
$this->meta = $this->driver->buildMeta();
foreach ($this->meta as $name => $info) {
$this->convert[$name] = $info['type'];
}
}
}
/**
* Displays complete result-set as HTML table for debug purposes
*
* @return void
*/
public function dump()
{
2007-11-11 04:59:39 +00:00
echo "\n<table class=\"dump\">\n<thead>\n\t<tr>\n\t\t<th>#row</th>\n";
foreach ($this->getFields() as $field) {
2007-11-11 04:59:39 +00:00
echo "\t\t<th>" . htmlSpecialChars($field) . "</th>\n";
}
2007-11-11 04:59:39 +00:00
echo "\t</tr>\n</thead>\n<tbody>\n";
foreach ($this as $row => $fields) {
2007-11-11 04:59:39 +00:00
echo "\t<tr>\n\t\t<th>", $row, "</th>\n";
foreach ($fields as $field) {
//if (is_object($field)) $field = $field->__toString();
2007-11-11 04:59:39 +00:00
echo "\t\t<td>", htmlSpecialChars($field), "</td>\n";
}
2007-11-11 04:59:39 +00:00
echo "\t</tr>\n";
}
2007-11-11 04:59:39 +00:00
echo "</tbody>\n</table>\n";
}
/**
* Required by the IteratorAggregate interface
* @param int offset
* @param int limit
* @return ArrayIterator
*/
final public function getIterator($offset = NULL, $limit = NULL)
2006-06-04 23:06:33 +00:00
{
return new DibiResultIterator($this, $offset, $limit);
2006-06-04 23:06:33 +00:00
}
/**
* Required by the Countable interface
* @return int
*/
final public function count()
2006-06-04 23:06:33 +00:00
{
return $this->rowCount();
}
}