2008-07-17 03:51:29 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
2010-09-14 18:40:41 +02:00
|
|
|
* This file is part of the "dibi" - smart database abstraction layer.
|
2012-01-02 20:24:16 +01:00
|
|
|
* Copyright (c) 2005 David Grudl (http://davidgrudl.com)
|
2008-07-17 03:51:29 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2010-08-03 22:48:44 +02:00
|
|
|
* dibi result set.
|
2008-07-17 03:51:29 +00:00
|
|
|
*
|
|
|
|
* <code>
|
|
|
|
* $result = dibi::query('SELECT * FROM [table]');
|
|
|
|
*
|
|
|
|
* $row = $result->fetch();
|
|
|
|
* $value = $result->fetchSingle();
|
|
|
|
* $table = $result->fetchAll();
|
|
|
|
* $pairs = $result->fetchPairs();
|
|
|
|
* $assoc = $result->fetchAssoc('id');
|
|
|
|
* $assoc = $result->fetchAssoc('active,#,id');
|
|
|
|
*
|
|
|
|
* unset($result);
|
|
|
|
* </code>
|
|
|
|
*
|
2010-09-14 18:40:41 +02:00
|
|
|
* @author David Grudl
|
2012-01-03 04:50:11 +01:00
|
|
|
* @package dibi
|
2010-04-22 12:12:11 +02:00
|
|
|
*
|
|
|
|
* @property-read mixed $resource
|
2010-08-04 15:27:41 +02:00
|
|
|
* @property-read IDibiResultDriver $driver
|
2010-04-22 12:12:11 +02:00
|
|
|
* @property-read int $rowCount
|
|
|
|
* @property-read DibiResultIterator $iterator
|
|
|
|
* @property string $rowClass
|
|
|
|
* @property-read DibiResultInfo $info
|
2008-07-17 03:51:29 +00:00
|
|
|
*/
|
2009-02-05 21:08:00 +00:00
|
|
|
class DibiResult extends DibiObject implements IDataSource
|
2008-07-17 03:51:29 +00:00
|
|
|
{
|
2010-08-04 15:27:41 +02:00
|
|
|
/** @var array IDibiResultDriver */
|
2008-07-17 03:51:29 +00:00
|
|
|
private $driver;
|
|
|
|
|
2008-10-28 15:24:47 +00:00
|
|
|
/** @var array Translate table */
|
2012-01-11 23:01:10 +01:00
|
|
|
private $types = array();
|
2008-07-17 03:51:29 +00:00
|
|
|
|
2009-09-09 17:02:46 +02:00
|
|
|
/** @var DibiResultInfo */
|
2008-10-28 14:37:40 +00:00
|
|
|
private $meta;
|
2008-07-17 03:51:29 +00:00
|
|
|
|
2008-10-28 15:24:47 +00:00
|
|
|
/** @var bool Already fetched? Used for allowance for first seek(0) */
|
2008-07-17 03:51:29 +00:00
|
|
|
private $fetched = FALSE;
|
|
|
|
|
2008-10-30 15:40:17 +00:00
|
|
|
/** @var string returned object class */
|
2010-02-24 02:43:15 +01:00
|
|
|
private $rowClass = 'DibiRow';
|
2008-10-30 15:40:17 +00:00
|
|
|
|
2010-12-03 13:20:23 -08:00
|
|
|
/** @var Callback returned object factory*/
|
|
|
|
private $rowFactory;
|
|
|
|
|
2012-01-18 21:08:34 +01:00
|
|
|
/** @var array format */
|
|
|
|
private $formats = array();
|
2010-02-24 06:43:08 +01:00
|
|
|
|
2008-07-17 03:51:29 +00:00
|
|
|
|
|
|
|
/**
|
2010-08-04 15:27:41 +02:00
|
|
|
* @param IDibiResultDriver
|
2008-07-17 03:51:29 +00:00
|
|
|
*/
|
2012-01-18 21:08:34 +01:00
|
|
|
public function __construct($driver)
|
2008-07-17 03:51:29 +00:00
|
|
|
{
|
|
|
|
$this->driver = $driver;
|
2012-01-11 23:01:10 +01:00
|
|
|
$this->detectTypes();
|
2008-07-17 03:51:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2012-01-19 00:12:08 +01:00
|
|
|
* @deprecated
|
2008-07-17 03:51:29 +00:00
|
|
|
*/
|
|
|
|
final public function getResource()
|
|
|
|
{
|
2012-01-19 00:12:08 +01:00
|
|
|
return $this->getResultDriver()->getResultResource();
|
2008-07-17 03:51:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-09-09 17:01:30 +02:00
|
|
|
/**
|
|
|
|
* Frees the resources allocated for this result set.
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
final public function free()
|
|
|
|
{
|
|
|
|
if ($this->driver !== NULL) {
|
|
|
|
$this->driver->free();
|
|
|
|
$this->driver = $this->meta = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Safe access to property $driver.
|
2010-08-04 15:27:41 +02:00
|
|
|
* @return IDibiResultDriver
|
2011-07-01 07:58:27 +02:00
|
|
|
* @throws RuntimeException
|
2009-09-09 17:01:30 +02:00
|
|
|
*/
|
2012-01-19 00:12:08 +01:00
|
|
|
final public function getResultDriver()
|
2009-09-09 17:01:30 +02:00
|
|
|
{
|
|
|
|
if ($this->driver === NULL) {
|
2011-07-01 07:58:27 +02:00
|
|
|
throw new RuntimeException('Result-set was released from memory.');
|
2009-09-09 17:01:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return $this->driver;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/********************* rows ****************d*g**/
|
|
|
|
|
|
|
|
|
2008-07-17 03:51:29 +00:00
|
|
|
/**
|
|
|
|
* Moves cursor position without fetching row.
|
|
|
|
* @param int the 0-based cursor pos to seek to
|
|
|
|
* @return boolean TRUE on success, FALSE if unable to seek to specified record
|
|
|
|
* @throws DibiException
|
|
|
|
*/
|
|
|
|
final public function seek($row)
|
|
|
|
{
|
2012-01-19 00:12:08 +01:00
|
|
|
return ($row !== 0 || $this->fetched) ? (bool) $this->getResultDriver()->seek($row) : TRUE;
|
2008-07-17 03:51:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2009-09-09 17:01:30 +02:00
|
|
|
* Required by the Countable interface.
|
2008-07-17 03:51:29 +00:00
|
|
|
* @return int
|
|
|
|
*/
|
2009-09-09 17:01:30 +02:00
|
|
|
final public function count()
|
2009-02-26 20:02:14 +00:00
|
|
|
{
|
2012-01-19 00:12:08 +01:00
|
|
|
return $this->getResultDriver()->getRowCount();
|
2009-02-26 20:02:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2009-09-09 17:01:30 +02:00
|
|
|
* Returns the number of rows in a result set.
|
2009-02-26 20:02:14 +00:00
|
|
|
* @return int
|
|
|
|
*/
|
2009-09-09 17:01:30 +02:00
|
|
|
final public function getRowCount()
|
2008-07-17 03:51:29 +00:00
|
|
|
{
|
2012-01-19 00:12:08 +01:00
|
|
|
return $this->getResultDriver()->getRowCount();
|
2008-07-17 03:51:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2009-09-09 17:01:30 +02:00
|
|
|
* Required by the IteratorAggregate interface.
|
|
|
|
* @return DibiResultIterator
|
2008-07-17 03:51:29 +00:00
|
|
|
*/
|
2010-08-03 16:59:31 +02:00
|
|
|
final public function getIterator()
|
2008-07-17 03:51:29 +00:00
|
|
|
{
|
2010-08-03 16:59:31 +02:00
|
|
|
return new DibiResultIterator($this);
|
2008-07-17 03:51:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-09-09 17:01:30 +02:00
|
|
|
/********************* fetching rows ****************d*g**/
|
2008-07-17 03:51:29 +00:00
|
|
|
|
|
|
|
|
2008-10-30 15:40:17 +00:00
|
|
|
/**
|
|
|
|
* Set fetched object class. This class should extend the DibiRow class.
|
|
|
|
* @param string
|
2013-07-02 18:42:55 +02:00
|
|
|
* @return self
|
2008-10-30 15:40:17 +00:00
|
|
|
*/
|
|
|
|
public function setRowClass($class)
|
|
|
|
{
|
2010-02-24 02:43:15 +01:00
|
|
|
$this->rowClass = $class;
|
2009-05-24 23:32:42 +00:00
|
|
|
return $this;
|
2008-10-30 15:40:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns fetched object class name.
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getRowClass()
|
|
|
|
{
|
2010-02-24 02:43:15 +01:00
|
|
|
return $this->rowClass;
|
2008-10-30 15:40:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-03 13:20:23 -08:00
|
|
|
/**
|
|
|
|
* Set a factory to create fetched object instances. These should extend the DibiRow class.
|
|
|
|
* @param callback
|
2013-07-02 18:42:55 +02:00
|
|
|
* @return self
|
2010-12-03 13:20:23 -08:00
|
|
|
*/
|
|
|
|
public function setRowFactory($callback)
|
|
|
|
{
|
|
|
|
$this->rowFactory = $callback;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-17 03:51:29 +00:00
|
|
|
/**
|
|
|
|
* Fetches the row at current position, process optional type conversion.
|
|
|
|
* and moves the internal cursor to the next position
|
2008-10-10 17:39:33 +00:00
|
|
|
* @return DibiRow|FALSE array on success, FALSE if no next record
|
2008-07-17 03:51:29 +00:00
|
|
|
*/
|
2008-10-10 17:39:33 +00:00
|
|
|
final public function fetch()
|
2008-07-17 03:51:29 +00:00
|
|
|
{
|
2012-01-19 00:12:08 +01:00
|
|
|
$row = $this->getResultDriver()->fetch(TRUE);
|
2012-01-11 23:01:10 +01:00
|
|
|
if (!is_array($row)) {
|
|
|
|
return FALSE;
|
2008-07-17 03:51:29 +00:00
|
|
|
}
|
2012-01-11 23:01:10 +01:00
|
|
|
$this->fetched = TRUE;
|
|
|
|
$this->normalize($row);
|
2010-12-03 13:20:23 -08:00
|
|
|
if ($this->rowFactory) {
|
|
|
|
return call_user_func($this->rowFactory, $row);
|
|
|
|
} elseif ($this->rowClass) {
|
2012-01-19 05:44:39 +01:00
|
|
|
$row = new $this->rowClass($row);
|
|
|
|
}
|
|
|
|
return $row;
|
2008-07-17 03:51:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Like fetch(), but returns only first field.
|
|
|
|
* @return mixed value on success, FALSE if no next record
|
|
|
|
*/
|
2008-08-28 02:02:21 +00:00
|
|
|
final public function fetchSingle()
|
2008-07-17 03:51:29 +00:00
|
|
|
{
|
2012-01-19 00:12:08 +01:00
|
|
|
$row = $this->getResultDriver()->fetch(TRUE);
|
2012-01-11 23:01:10 +01:00
|
|
|
if (!is_array($row)) {
|
|
|
|
return FALSE;
|
2008-07-17 03:51:29 +00:00
|
|
|
}
|
2012-01-11 23:01:10 +01:00
|
|
|
$this->fetched = TRUE;
|
|
|
|
$this->normalize($row);
|
|
|
|
return reset($row);
|
2008-07-17 03:51:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetches all records from table.
|
|
|
|
* @param int offset
|
|
|
|
* @param int limit
|
2013-10-24 21:15:48 +02:00
|
|
|
* @return DibiRow[]
|
2008-07-17 03:51:29 +00:00
|
|
|
*/
|
2008-10-01 16:04:16 +00:00
|
|
|
final public function fetchAll($offset = NULL, $limit = NULL)
|
2008-07-17 03:51:29 +00:00
|
|
|
{
|
|
|
|
$limit = $limit === NULL ? -1 : (int) $limit;
|
|
|
|
$this->seek((int) $offset);
|
|
|
|
$row = $this->fetch();
|
2013-07-02 18:42:55 +02:00
|
|
|
if (!$row) {
|
|
|
|
return array(); // empty result set
|
|
|
|
}
|
2008-07-17 03:51:29 +00:00
|
|
|
|
|
|
|
$data = array();
|
2008-10-01 16:04:16 +00:00
|
|
|
do {
|
2013-07-02 18:42:55 +02:00
|
|
|
if ($limit === 0) {
|
|
|
|
break;
|
|
|
|
}
|
2008-10-01 16:04:16 +00:00
|
|
|
$limit--;
|
|
|
|
$data[] = $row;
|
|
|
|
} while ($row = $this->fetch());
|
2008-07-17 03:51:29 +00:00
|
|
|
|
|
|
|
return $data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetches all records from table and returns associative tree.
|
2009-10-06 18:09:13 +02:00
|
|
|
* Examples:
|
|
|
|
* - associative descriptor: col1[]col2->col3
|
|
|
|
* builds a tree: $tree[$val1][$index][$val2]->col3[$val3] = {record}
|
|
|
|
* - associative descriptor: col1|col2->col3=col4
|
|
|
|
* builds a tree: $tree[$val1][$val2]->col3[$val3] = val4
|
2008-07-17 03:51:29 +00:00
|
|
|
* @param string associative descriptor
|
2008-10-10 17:39:33 +00:00
|
|
|
* @return DibiRow
|
2008-07-17 03:51:29 +00:00
|
|
|
* @throws InvalidArgumentException
|
|
|
|
*/
|
2008-08-28 02:02:21 +00:00
|
|
|
final public function fetchAssoc($assoc)
|
2008-07-17 03:51:29 +00:00
|
|
|
{
|
2009-10-06 18:09:13 +02:00
|
|
|
if (strpos($assoc, ',') !== FALSE) {
|
|
|
|
return $this->oldFetchAssoc($assoc);
|
|
|
|
}
|
|
|
|
|
2008-07-17 03:51:29 +00:00
|
|
|
$this->seek(0);
|
2008-10-10 17:39:33 +00:00
|
|
|
$row = $this->fetch();
|
2013-07-02 18:42:55 +02:00
|
|
|
if (!$row) {
|
|
|
|
return array(); // empty result set
|
|
|
|
}
|
2008-07-17 03:51:29 +00:00
|
|
|
|
|
|
|
$data = NULL;
|
2009-10-06 18:09:13 +02:00
|
|
|
$assoc = preg_split('#(\[\]|->|=|\|)#', $assoc, NULL, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
|
2008-07-17 03:51:29 +00:00
|
|
|
|
|
|
|
// check columns
|
|
|
|
foreach ($assoc as $as) {
|
2008-10-21 13:42:53 +00:00
|
|
|
// offsetExists ignores NULL in PHP 5.2.1, isset() surprisingly NULL accepts
|
2010-04-26 21:20:10 +02:00
|
|
|
if ($as !== '[]' && $as !== '=' && $as !== '->' && $as !== '|' && !property_exists($row, $as)) {
|
2008-07-17 03:51:29 +00:00
|
|
|
throw new InvalidArgumentException("Unknown column '$as' in associative descriptor.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-06 18:09:13 +02:00
|
|
|
if ($as === '->') { // must not be last
|
|
|
|
array_pop($assoc);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (empty($assoc)) {
|
|
|
|
$assoc[] = '[]';
|
|
|
|
}
|
|
|
|
|
|
|
|
// make associative tree
|
|
|
|
do {
|
|
|
|
$x = & $data;
|
|
|
|
|
|
|
|
// iterative deepening
|
|
|
|
foreach ($assoc as $i => $as) {
|
|
|
|
if ($as === '[]') { // indexed-array node
|
|
|
|
$x = & $x[];
|
|
|
|
|
|
|
|
} elseif ($as === '=') { // "value" node
|
|
|
|
$x = $row->{$assoc[$i+1]};
|
2009-12-09 02:34:58 +01:00
|
|
|
continue 2;
|
2009-10-06 18:09:13 +02:00
|
|
|
|
|
|
|
} elseif ($as === '->') { // "object" node
|
|
|
|
if ($x === NULL) {
|
|
|
|
$x = clone $row;
|
|
|
|
$x = & $x->{$assoc[$i+1]};
|
|
|
|
$x = NULL; // prepare child node
|
|
|
|
} else {
|
|
|
|
$x = & $x->{$assoc[$i+1]};
|
|
|
|
}
|
|
|
|
|
|
|
|
} elseif ($as !== '|') { // associative-array node
|
|
|
|
$x = & $x[$row->$as];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($x === NULL) { // build leaf
|
|
|
|
$x = $row;
|
|
|
|
}
|
|
|
|
|
|
|
|
} while ($row = $this->fetch());
|
|
|
|
|
|
|
|
unset($x);
|
|
|
|
return $data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @deprecated
|
|
|
|
*/
|
|
|
|
private function oldFetchAssoc($assoc)
|
|
|
|
{
|
|
|
|
$this->seek(0);
|
|
|
|
$row = $this->fetch();
|
2013-07-02 18:42:55 +02:00
|
|
|
if (!$row) {
|
|
|
|
return array(); // empty result set
|
|
|
|
}
|
2009-10-06 18:09:13 +02:00
|
|
|
|
|
|
|
$data = NULL;
|
|
|
|
$assoc = explode(',', $assoc);
|
|
|
|
|
2008-07-17 03:51:29 +00:00
|
|
|
// strip leading = and @
|
2008-10-10 17:39:33 +00:00
|
|
|
$leaf = '@'; // gap
|
2008-07-17 03:51:29 +00:00
|
|
|
$last = count($assoc) - 1;
|
|
|
|
while ($assoc[$last] === '=' || $assoc[$last] === '@') {
|
|
|
|
$leaf = $assoc[$last];
|
|
|
|
unset($assoc[$last]);
|
|
|
|
$last--;
|
|
|
|
|
|
|
|
if ($last < 0) {
|
|
|
|
$assoc[] = '#';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
|
|
|
$x = & $data;
|
|
|
|
|
|
|
|
foreach ($assoc as $i => $as) {
|
|
|
|
if ($as === '#') { // indexed-array node
|
|
|
|
$x = & $x[];
|
|
|
|
|
|
|
|
} elseif ($as === '=') { // "record" node
|
|
|
|
if ($x === NULL) {
|
2010-04-26 20:44:17 +02:00
|
|
|
$x = $row->toArray();
|
2008-07-17 03:51:29 +00:00
|
|
|
$x = & $x[ $assoc[$i+1] ];
|
|
|
|
$x = NULL; // prepare child node
|
|
|
|
} else {
|
|
|
|
$x = & $x[ $assoc[$i+1] ];
|
|
|
|
}
|
|
|
|
|
|
|
|
} elseif ($as === '@') { // "object" node
|
|
|
|
if ($x === NULL) {
|
2008-10-10 17:39:33 +00:00
|
|
|
$x = clone $row;
|
2008-07-17 03:51:29 +00:00
|
|
|
$x = & $x->{$assoc[$i+1]};
|
|
|
|
$x = NULL; // prepare child node
|
|
|
|
} else {
|
|
|
|
$x = & $x->{$assoc[$i+1]};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} else { // associative-array node
|
2009-10-06 16:51:27 +02:00
|
|
|
$x = & $x[$row->$as];
|
2008-07-17 03:51:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($x === NULL) { // build leaf
|
2008-09-03 22:47:49 +00:00
|
|
|
if ($leaf === '=') {
|
2010-04-26 20:44:17 +02:00
|
|
|
$x = $row->toArray();
|
2008-09-03 22:47:49 +00:00
|
|
|
} else {
|
2008-10-10 17:39:33 +00:00
|
|
|
$x = $row;
|
2008-09-03 22:47:49 +00:00
|
|
|
}
|
2008-07-17 03:51:29 +00:00
|
|
|
}
|
|
|
|
|
2008-10-10 17:39:33 +00:00
|
|
|
} while ($row = $this->fetch());
|
2008-07-17 03:51:29 +00:00
|
|
|
|
|
|
|
unset($x);
|
|
|
|
return $data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetches all records from table like $key => $value pairs.
|
|
|
|
* @param string associative key
|
|
|
|
* @param string value
|
|
|
|
* @return array
|
|
|
|
* @throws InvalidArgumentException
|
|
|
|
*/
|
2008-08-28 02:02:21 +00:00
|
|
|
final public function fetchPairs($key = NULL, $value = NULL)
|
2008-07-17 03:51:29 +00:00
|
|
|
{
|
|
|
|
$this->seek(0);
|
2008-10-10 17:39:33 +00:00
|
|
|
$row = $this->fetch();
|
2013-07-02 18:42:55 +02:00
|
|
|
if (!$row) {
|
|
|
|
return array(); // empty result set
|
|
|
|
}
|
2008-07-17 03:51:29 +00:00
|
|
|
|
|
|
|
$data = array();
|
|
|
|
|
|
|
|
if ($value === NULL) {
|
|
|
|
if ($key !== NULL) {
|
|
|
|
throw new InvalidArgumentException("Either none or both columns must be specified.");
|
|
|
|
}
|
|
|
|
|
|
|
|
// autodetect
|
2010-04-26 20:44:17 +02:00
|
|
|
$tmp = array_keys($row->toArray());
|
2008-07-17 03:51:29 +00:00
|
|
|
$key = $tmp[0];
|
2008-10-01 16:04:16 +00:00
|
|
|
if (count($row) < 2) { // indexed-array
|
|
|
|
do {
|
|
|
|
$data[] = $row[$key];
|
2008-10-10 17:39:33 +00:00
|
|
|
} while ($row = $this->fetch());
|
2008-10-01 16:04:16 +00:00
|
|
|
return $data;
|
|
|
|
}
|
|
|
|
|
2008-07-17 03:51:29 +00:00
|
|
|
$value = $tmp[1];
|
|
|
|
|
|
|
|
} else {
|
2010-04-26 21:20:10 +02:00
|
|
|
if (!property_exists($row, $value)) {
|
2008-07-17 03:51:29 +00:00
|
|
|
throw new InvalidArgumentException("Unknown value column '$value'.");
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($key === NULL) { // indexed-array
|
|
|
|
do {
|
|
|
|
$data[] = $row[$value];
|
2008-10-10 17:39:33 +00:00
|
|
|
} while ($row = $this->fetch());
|
2008-07-17 03:51:29 +00:00
|
|
|
return $data;
|
|
|
|
}
|
|
|
|
|
2010-04-26 21:20:10 +02:00
|
|
|
if (!property_exists($row, $key)) {
|
2008-07-17 03:51:29 +00:00
|
|
|
throw new InvalidArgumentException("Unknown key column '$key'.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
2013-09-30 00:30:09 +02:00
|
|
|
$data[ (string) $row[$key] ] = $row[$value];
|
2008-10-10 17:39:33 +00:00
|
|
|
} while ($row = $this->fetch());
|
2008-07-17 03:51:29 +00:00
|
|
|
|
|
|
|
return $data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-11 23:01:10 +01:00
|
|
|
/********************* column types ****************d*g**/
|
2009-09-09 17:01:30 +02:00
|
|
|
|
|
|
|
|
2008-07-17 03:51:29 +00:00
|
|
|
/**
|
2012-01-11 23:01:10 +01:00
|
|
|
* Autodetect column types.
|
|
|
|
* @return void
|
2008-07-17 03:51:29 +00:00
|
|
|
*/
|
2012-01-11 23:01:10 +01:00
|
|
|
private function detectTypes()
|
2008-07-17 03:51:29 +00:00
|
|
|
{
|
2012-01-11 23:01:10 +01:00
|
|
|
$cache = DibiColumnInfo::getTypeCache();
|
|
|
|
try {
|
2012-01-19 00:12:08 +01:00
|
|
|
foreach ($this->getResultDriver()->getResultColumns() as $col) {
|
2012-01-11 23:01:10 +01:00
|
|
|
$this->types[$col['name']] = $cache->{$col['nativetype']};
|
|
|
|
}
|
|
|
|
} catch (DibiNotSupportedException $e) {}
|
2008-07-17 03:51:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-10-28 14:37:40 +00:00
|
|
|
/**
|
2012-01-11 23:01:10 +01:00
|
|
|
* Converts values to specified type and format.
|
|
|
|
* @param array
|
2008-10-28 14:37:40 +00:00
|
|
|
* @return void
|
|
|
|
*/
|
2012-01-11 23:01:10 +01:00
|
|
|
private function normalize(array & $row)
|
2008-10-28 14:37:40 +00:00
|
|
|
{
|
2012-01-11 23:01:10 +01:00
|
|
|
foreach ($this->types as $key => $type) {
|
|
|
|
if (!isset($row[$key])) { // NULL
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
$value = $row[$key];
|
|
|
|
if ($value === FALSE || $type === dibi::TEXT) {
|
|
|
|
|
|
|
|
} elseif ($type === dibi::INTEGER) {
|
|
|
|
$row[$key] = is_float($tmp = $value * 1) ? $value : $tmp;
|
|
|
|
|
|
|
|
} elseif ($type === dibi::FLOAT) {
|
2014-02-11 17:04:19 +01:00
|
|
|
$row[$key] = ltrim((string) ($tmp = (float) $value), '0') === ltrim(rtrim(rtrim($value, '0'), '.'), '0') ? $tmp : $value;
|
2012-01-11 23:01:10 +01:00
|
|
|
|
|
|
|
} elseif ($type === dibi::BOOL) {
|
|
|
|
$row[$key] = ((bool) $value) && $value !== 'f' && $value !== 'F';
|
|
|
|
|
|
|
|
} elseif ($type === dibi::DATE || $type === dibi::DATETIME) {
|
2013-10-04 01:19:20 +02:00
|
|
|
if ((int) $value !== 0 || substr((string) $value, 0, 3) === '00:') { // '', NULL, FALSE, '0000-00-00', ...
|
2012-01-11 23:01:10 +01:00
|
|
|
$value = new DibiDateTime($value);
|
2013-10-04 01:19:20 +02:00
|
|
|
$row[$key] = empty($this->formats[$type]) ? $value : $value->format($this->formats[$type]);
|
2012-01-11 23:01:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
} elseif ($type === dibi::BINARY) {
|
2012-01-19 00:12:08 +01:00
|
|
|
$row[$key] = $this->getResultDriver()->unescape($value, $type);
|
2012-01-11 23:01:10 +01:00
|
|
|
}
|
2008-10-28 14:37:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-17 03:51:29 +00:00
|
|
|
/**
|
2012-01-11 23:01:10 +01:00
|
|
|
* Define column type.
|
|
|
|
* @param string column
|
|
|
|
* @param string type (use constant Dibi::*)
|
2013-07-02 18:42:55 +02:00
|
|
|
* @return self
|
2008-07-17 03:51:29 +00:00
|
|
|
*/
|
2012-01-11 23:01:10 +01:00
|
|
|
final public function setType($col, $type)
|
2008-07-17 03:51:29 +00:00
|
|
|
{
|
2012-01-11 23:01:10 +01:00
|
|
|
$this->types[$col] = $type;
|
2009-09-18 03:38:10 +02:00
|
|
|
return $this;
|
2008-07-17 03:51:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns column type.
|
2010-02-24 06:43:08 +01:00
|
|
|
* @return string
|
2008-07-17 03:51:29 +00:00
|
|
|
*/
|
|
|
|
final public function getType($col)
|
|
|
|
{
|
2010-02-24 02:43:15 +01:00
|
|
|
return isset($this->types[$col]) ? $this->types[$col] : NULL;
|
2008-07-17 03:51:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-18 21:08:34 +01:00
|
|
|
/**
|
|
|
|
* Sets data format.
|
|
|
|
* @param string type (use constant Dibi::*)
|
|
|
|
* @param string format
|
2013-07-02 18:42:55 +02:00
|
|
|
* @return self
|
2012-01-18 21:08:34 +01:00
|
|
|
*/
|
|
|
|
final public function setFormat($type, $format)
|
|
|
|
{
|
|
|
|
$this->formats[$type] = $format;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns data format.
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
final public function getFormat($type)
|
|
|
|
{
|
|
|
|
return isset($this->formats[$type]) ? $this->formats[$type] : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-11 23:01:10 +01:00
|
|
|
/********************* meta info ****************d*g**/
|
2008-07-17 03:51:29 +00:00
|
|
|
|
|
|
|
|
2009-09-09 17:01:30 +02:00
|
|
|
/**
|
2009-09-09 17:02:46 +02:00
|
|
|
* Returns a meta information about the current result set.
|
|
|
|
* @return DibiResultInfo
|
2009-09-09 17:01:30 +02:00
|
|
|
*/
|
2009-09-09 17:02:46 +02:00
|
|
|
public function getInfo()
|
2009-09-09 17:01:30 +02:00
|
|
|
{
|
|
|
|
if ($this->meta === NULL) {
|
2012-01-19 00:12:08 +01:00
|
|
|
$this->meta = new DibiResultInfo($this->getResultDriver());
|
2009-09-09 17:01:30 +02:00
|
|
|
}
|
|
|
|
return $this->meta;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-17 03:51:29 +00:00
|
|
|
/**
|
2009-09-09 17:02:46 +02:00
|
|
|
* @deprecated
|
2008-07-17 03:51:29 +00:00
|
|
|
*/
|
2008-10-02 17:13:43 +00:00
|
|
|
final public function getColumns()
|
2008-07-17 03:51:29 +00:00
|
|
|
{
|
2009-09-09 17:02:46 +02:00
|
|
|
return $this->getInfo()->getColumns();
|
2008-10-02 17:13:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-09-09 17:01:30 +02:00
|
|
|
/********************* misc tools ****************d*g**/
|
|
|
|
|
|
|
|
|
2008-07-17 03:51:29 +00:00
|
|
|
/**
|
2012-10-03 22:21:38 +02:00
|
|
|
* Displays complete result set as HTML or text table for debug purposes.
|
2008-07-17 03:51:29 +00:00
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
final public function dump()
|
|
|
|
{
|
2008-09-03 22:47:49 +00:00
|
|
|
$i = 0;
|
|
|
|
$this->seek(0);
|
2012-10-03 22:21:38 +02:00
|
|
|
if (PHP_SAPI === 'cli') {
|
|
|
|
$hasColors = (substr(getenv('TERM'), 0, 5) === 'xterm');
|
|
|
|
$maxLen = 0;
|
|
|
|
while ($row = $this->fetch()) {
|
|
|
|
if ($i === 0) {
|
|
|
|
foreach ($row as $col => $foo) {
|
|
|
|
$len = mb_strlen($col);
|
2013-07-02 18:42:55 +02:00
|
|
|
$maxLen = max($len, $maxLen);
|
2012-10-03 22:21:38 +02:00
|
|
|
}
|
|
|
|
}
|
2008-07-17 03:51:29 +00:00
|
|
|
|
2012-10-03 22:21:38 +02:00
|
|
|
if ($hasColors) {
|
|
|
|
echo "\033[1;37m#row: $i\033[0m\n";
|
|
|
|
} else {
|
|
|
|
echo "#row: $i\n";
|
2008-07-17 03:51:29 +00:00
|
|
|
}
|
|
|
|
|
2012-10-03 22:21:38 +02:00
|
|
|
foreach ($row as $col => $val) {
|
|
|
|
$spaces = $maxLen - mb_strlen($col) + 2;
|
|
|
|
echo "$col" . str_repeat(" ", $spaces) . "$val\n";
|
|
|
|
}
|
2008-07-17 03:51:29 +00:00
|
|
|
|
2012-10-03 22:21:38 +02:00
|
|
|
echo "\n";
|
|
|
|
$i++;
|
2008-07-17 03:51:29 +00:00
|
|
|
}
|
|
|
|
|
2013-07-02 18:42:55 +02:00
|
|
|
if ($i === 0) {
|
|
|
|
echo "empty result set\n";
|
|
|
|
}
|
2012-10-03 22:21:38 +02:00
|
|
|
echo "\n";
|
|
|
|
|
2008-07-17 03:51:29 +00:00
|
|
|
} else {
|
2012-10-03 22:21:38 +02:00
|
|
|
while ($row = $this->fetch()) {
|
|
|
|
if ($i === 0) {
|
|
|
|
echo "\n<table class=\"dump\">\n<thead>\n\t<tr>\n\t\t<th>#row</th>\n";
|
|
|
|
|
|
|
|
foreach ($row as $col => $foo) {
|
|
|
|
echo "\t\t<th>" . htmlSpecialChars($col) . "</th>\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
echo "\t</tr>\n</thead>\n<tbody>\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
echo "\t<tr>\n\t\t<th>", $i, "</th>\n";
|
|
|
|
foreach ($row as $col) {
|
|
|
|
//if (is_object($col)) $col = $col->__toString();
|
|
|
|
echo "\t\t<td>", htmlSpecialChars($col), "</td>\n";
|
|
|
|
}
|
|
|
|
echo "\t</tr>\n";
|
|
|
|
$i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($i === 0) {
|
|
|
|
echo '<p><em>empty result set</em></p>';
|
|
|
|
} else {
|
|
|
|
echo "</tbody>\n</table>\n";
|
|
|
|
}
|
2008-07-17 03:51:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|