Permalink
Browse files

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.
  • Loading branch information...
1 parent ce227fa commit f4acc79a3e91059a932d7a2d43309f6f8f65fa59 @damz damz committed Nov 2, 2011
@@ -22,11 +22,12 @@
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 @@ public function columnCount()
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 @@
* 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
@@ -79,6 +79,11 @@ class ResultCacheStatement implements ResultStatement
private $data;
/**
+ * @var int
+ */
+ private $defaultFetchStyle = PDO::FETCH_BOTH;
+
+ /**
* @param Statement $stmt
* @param Cache $resultCache
* @param string $cacheKey
@@ -127,6 +132,17 @@ public function columnCount()
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 @@
* @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();
/**
@@ -186,6 +187,23 @@ public function execute($params = null)
/**
* {@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}
+ */
public function fetch($fetchStyle = PDO::FETCH_BOTH)
{
if ( ! isset(self::$fetchStyleMap[$fetchStyle])) {
@@ -30,4 +30,13 @@
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);
fabpot
fabpot May 5, 2012 Member

This is wrong. How do you set the class name when you set the fetch style to FETCH_CLASS?

fabpot
fabpot May 5, 2012 Member

There is already an opened issue for this problem: http://www.doctrine-project.org/jira/browse/DBAL-214

+ }
}
@@ -26,7 +26,7 @@
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
-interface ResultStatement
+interface ResultStatement extends \Traversable
{
/**
* Closes the cursor, enabling the statement to be executed again.
@@ -47,6 +47,14 @@ function closeCursor();
function columnCount();
/**
+ * setFetchMode
+ * Set the fetch mode to use while iterating this statement.
+ *
+ * @param integer $fetchStyle
+ */
+ public function setFetchMode($fetchStyle);
+
+ /**
* fetch
*
* @see Query::HYDRATE_* constants
@@ -30,7 +30,7 @@
* @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 @@ public function execute($params = null)
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 @@
* @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 @@ public function errorInfo()
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 @@ public function testPrepareWithFetchColumn()
$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';
@@ -61,6 +61,11 @@ public function testFullFetchMode()
$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 @@ public function testMixingFetch()
$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 @@ private function hydrateStmt($stmt, $fetchStyle = \PDO::FETCH_ASSOC)
$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;
+ }
}

0 comments on commit f4acc79

Please sign in to comment.