Commit f4acc79a authored by Damien Tournoud's avatar Damien Tournoud

Make all Statement classes Traversable.

This enables a more natural way of interacting with result sets,
and re-introduces in Doctrine DBAL a feature that has been available
in PDO from the begining.
parent ce227fa8
......@@ -22,11 +22,12 @@ namespace Doctrine\DBAL\Cache;
use Doctrine\DBAL\Driver\ResultStatement;
use PDO;
class ArrayStatement implements ResultStatement
class ArrayStatement implements \IteratorAggregate, ResultStatement
{
private $data;
private $columnCount = 0;
private $num = 0;
private $defaultFetchStyle = PDO::FETCH_BOTH;
public function __construct(array $data)
{
......@@ -46,6 +47,17 @@ class ArrayStatement implements ResultStatement
return $this->columnCount;
}
public function setFetchMode($fetchStyle)
{
$this->defaultFetchStyle = $fetchStyle;
}
public function getIterator()
{
$data = $this->fetchAll($this->defaultFetchStyle);
return new \ArrayIterator($data);
}
public function fetch($fetchStyle = PDO::FETCH_BOTH)
{
if (isset($this->data[$this->num])) {
......
......@@ -38,7 +38,7 @@ use PDO;
* Also you have to realize that the cache will load the whole result into memory at once to ensure 2.
* This means that the memory usage for cached results might increase by using this feature.
*/
class ResultCacheStatement implements ResultStatement
class ResultCacheStatement implements \IteratorAggregate, ResultStatement
{
/**
* @var \Doctrine\Common\Cache\Cache
......@@ -78,6 +78,11 @@ class ResultCacheStatement implements ResultStatement
*/
private $data;
/**
* @var int
*/
private $defaultFetchStyle = PDO::FETCH_BOTH;
/**
* @param Statement $stmt
* @param Cache $resultCache
......@@ -127,6 +132,17 @@ class ResultCacheStatement implements ResultStatement
return $this->statement->columnCount();
}
public function setFetchMode($fetchStyle)
{
$this->defaultFetchStyle = $fetchStyle;
}
public function getIterator()
{
$data = $this->fetchAll($this->defaultFetchStyle);
return new \ArrayIterator($data);
}
/**
* fetch
*
......
......@@ -27,7 +27,7 @@ use \PDO;
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
*/
class OCI8Statement implements \Doctrine\DBAL\Driver\Statement
class OCI8Statement implements \IteratorAggregate, \Doctrine\DBAL\Driver\Statement
{
/** Statement handle. */
protected $_dbh;
......@@ -40,6 +40,7 @@ class OCI8Statement implements \Doctrine\DBAL\Driver\Statement
PDO::FETCH_NUM => OCI_NUM,
PDO::PARAM_LOB => OCI_B_BLOB,
);
protected $_defaultFetchStyle = PDO::FETCH_BOTH;
protected $_paramMap = array();
/**
......@@ -183,6 +184,23 @@ class OCI8Statement implements \Doctrine\DBAL\Driver\Statement
return $ret;
}
/**
* {@inheritdoc}
*/
public function setFetchMode($fetchStyle = PDO::FETCH_BOTH)
{
$this->_defaultFetchStyle = $fetchStyle;
}
/**
* {@inheritdoc}
*/
public function getIterator()
{
$data = $this->fetchAll($this->_defaultFetchStyle);
return new \ArrayIterator($data);
}
/**
* {@inheritdoc}
*/
......
......@@ -30,4 +30,13 @@ namespace Doctrine\DBAL\Driver;
class PDOStatement extends \PDOStatement implements Statement
{
private function __construct() {}
public function setFetchMode($fetchStyle, $params = NULL)
{
// This thin wrapper is necessary to shield against the weird signature
// of PDOStatement::setFetchMode(): even if the second and third
// parameters are optional, PHP will not let us remove it from this
// declaration.
return parent::setFetchMode($fetchStyle);
}
}
\ No newline at end of file
......@@ -26,7 +26,7 @@ use PDO;
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
interface ResultStatement
interface ResultStatement extends \Traversable
{
/**
* Closes the cursor, enabling the statement to be executed again.
......@@ -46,6 +46,14 @@ interface ResultStatement
*/
function columnCount();
/**
* setFetchMode
* Set the fetch mode to use while iterating this statement.
*
* @param integer $fetchStyle
*/
public function setFetchMode($fetchStyle);
/**
* fetch
*
......
......@@ -30,7 +30,7 @@ use PDO;
* @since 2.0
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class Statement implements \Doctrine\DBAL\Driver\Statement
class Statement implements \IteratorAggregate, \Doctrine\DBAL\Driver\Statement
{
/**
......@@ -48,6 +48,11 @@ class Statement implements \Doctrine\DBAL\Driver\Statement
*/
private $case;
/**
* @var int
*/
private $defaultFetchStyle = PDO::FETCH_BOTH;
/**
* Wraps <tt>Statement</tt> and applies portability measures
*
......@@ -96,6 +101,17 @@ class Statement implements \Doctrine\DBAL\Driver\Statement
return $this->stmt->execute($params);
}
public function setFetchMode($fetchStyle)
{
$this->defaultFetchStyle = $fetchStyle;
}
public function getIterator()
{
$data = $this->fetchAll($this->defaultFetchStyle);
return new \ArrayIterator($data);
}
public function fetch($fetchStyle = PDO::FETCH_BOTH)
{
$row = $this->stmt->fetch($fetchStyle);
......
......@@ -32,7 +32,7 @@ use PDO,
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
*/
class Statement implements DriverStatement
class Statement implements \IteratorAggregate, DriverStatement
{
/**
* @var string The SQL statement.
......@@ -177,6 +177,16 @@ class Statement implements DriverStatement
return $this->_stmt->errorInfo();
}
public function setFetchMode($fetchStyle)
{
return $this->_stmt->setFetchMode($fetchStyle);
}
public function getIterator()
{
return $this->_stmt;
}
/**
* Fetches the next row from a result set.
*
......
......@@ -99,6 +99,28 @@ class DataAccessTest extends \Doctrine\Tests\DbalFunctionalTestCase
$this->assertEquals(1, $column);
}
public function testPrepareWithIterator()
{
$paramInt = 1;
$paramStr = 'foo';
$sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
$stmt = $this->_conn->prepare($sql);
$this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
$stmt->bindParam(1, $paramInt);
$stmt->bindParam(2, $paramStr);
$stmt->execute();
$rows = array();
$stmt->setFetchMode(\PDO::FETCH_ASSOC);
foreach ($stmt as $row) {
$rows[] = array_change_key_case($row, \CASE_LOWER);
}
$this->assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $rows[0]);
}
public function testPrepareWithQuoted()
{
$table = 'fetch_table';
......
......@@ -60,6 +60,11 @@ class PortabilityTest extends \Doctrine\Tests\DbalFunctionalTestCase
$rows = $this->getPortableConnection()->fetchAll('SELECT * FROM portability_table');
$this->assertFetchResultRows($rows);
$stmt = $this->getPortableConnection()->query('SELECT * FROM portability_table');
foreach ($stmt as $row) {
$this->assertFetchResultRow($row);
}
$stmt = $this->getPortableConnection()->query('SELECT * FROM portability_table');
while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
$this->assertFetchResultRow($row);
......
......@@ -85,6 +85,24 @@ class ResultCacheTest extends \Doctrine\Tests\DbalFunctionalTestCase
$this->assertEquals($numExpectedResult, $data);
}
public function testIteratorFetch()
{
$this->assertStandardAndIteratorFetchAreEqual(\PDO::FETCH_BOTH);
$this->assertStandardAndIteratorFetchAreEqual(\PDO::FETCH_ASSOC);
$this->assertStandardAndIteratorFetchAreEqual(\PDO::FETCH_NUM);
}
public function assertStandardAndIteratorFetchAreEqual($fetchStyle)
{
$stmt = $this->_conn->executeQuery("SELECT * FROM caching", array(), array(), new QueryCacheProfile(10, "testcachekey"));
$data = $this->hydrateStmt($stmt, $fetchStyle);
$stmt = $this->_conn->executeQuery("SELECT * FROM caching", array(), array(), new QueryCacheProfile(10, "testcachekey"));
$data_iterator = $this->hydrateStmtIterator($stmt, $fetchStyle);
$this->assertEquals($data, $data_iterator);
}
public function testDontCloseNoCache()
{
$stmt = $this->_conn->executeQuery("SELECT * FROM caching", array(), array(), new QueryCacheProfile(10, "testcachekey"));
......@@ -167,4 +185,15 @@ class ResultCacheTest extends \Doctrine\Tests\DbalFunctionalTestCase
$stmt->closeCursor();
return $data;
}
private function hydrateStmtIterator($stmt, $fetchStyle = \PDO::FETCH_ASSOC)
{
$data = array();
$stmt->setFetchMode($fetchStyle);
foreach ($stmt as $row) {
$data[] = $row;
}
$stmt->closeCursor();
return $data;
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment