From 74ce82bd505ca44fba54fd6579b1c95410e7961d Mon Sep 17 00:00:00 2001 From: romanb Date: Sun, 18 May 2008 16:21:55 +0000 Subject: [PATCH] Initial HYDRATE_SINGLE_SCALAR implementation & test. --- lib/Doctrine/Hydrator/Exception.php | 7 +- lib/Doctrine/HydratorNew.php | 18 ++++- tests/Orm/Hydration/BasicHydrationTest.php | 80 +++++++++++++++++++ .../mocks/Doctrine_HydratorMockStatement.php | 8 ++ 4 files changed, 111 insertions(+), 2 deletions(-) diff --git a/lib/Doctrine/Hydrator/Exception.php b/lib/Doctrine/Hydrator/Exception.php index 8bc54edd0..63ed67380 100644 --- a/lib/Doctrine/Hydrator/Exception.php +++ b/lib/Doctrine/Hydrator/Exception.php @@ -18,7 +18,7 @@ * and is licensed under the LGPL. For more information, see * . */ -Doctrine::autoload('Doctrine_Exception'); + /** * Doctrine_Hydrator_Exception * @@ -41,4 +41,9 @@ class Doctrine_Hydrator_Exception extends Doctrine_Exception { return new self("Hydration failed. Found a non-existent field '$field'."); } + + public static function nonUniqueResult() + { + return new self("Hydration failed. Non-unique result returned."); + } } \ No newline at end of file diff --git a/lib/Doctrine/HydratorNew.php b/lib/Doctrine/HydratorNew.php index b31de007e..e3b981e2f 100644 --- a/lib/Doctrine/HydratorNew.php +++ b/lib/Doctrine/HydratorNew.php @@ -77,6 +77,7 @@ class Doctrine_HydratorNew extends Doctrine_Hydrator_Abstract * ) * ) * @return mixed The created object/array graph. + * @throws Doctrine_Hydrator_Exception If the hydration process failed. */ public function hydrateResultSet($parserResult) { @@ -147,9 +148,20 @@ class Doctrine_HydratorNew extends Doctrine_Hydrator_Abstract $idTemplate[$dqlAlias] = ''; } - // Process result set + $cache = array(); + // Evaluate HYDRATE_SINGLE_SCALAR + if ($hydrationMode == Doctrine::HYDRATE_SINGLE_SCALAR) { + $result = $stmt->fetchAll(PDO::FETCH_ASSOC); + if (count($result) > 1 || count($result[0]) > 1) { + throw Doctrine_Hydrator_Exception::nonUniqueResult(); + } + return array_shift($this->_gatherScalarRowData($result[0], $cache)); + } + + // Process result set while ($data = $stmt->fetch(Doctrine::FETCH_ASSOC)) { + // Evaluate HYDRATE_SCALAR if ($hydrationMode == Doctrine::HYDRATE_SCALAR) { $result[] = $this->_gatherScalarRowData($data, $cache); continue; @@ -372,6 +384,8 @@ class Doctrine_HydratorNew extends Doctrine_Hydrator_Abstract * * @return array An array with all the fields (name => value) of the data row, * grouped by their component (alias). + * @todo Significant code duplication with _gatherScalarRowData(). Good refactoring + * possible without sacrificing performance? */ protected function _gatherRowData(&$data, &$cache, &$id, &$nonemptyComponents) { @@ -455,6 +469,8 @@ class Doctrine_HydratorNew extends Doctrine_Hydrator_Abstract * @param array $data * @param array $cache * @return array The processed row. + * @todo Significant code duplication with _gatherRowData(). Good refactoring + * possible without sacrificing performance? */ private function _gatherScalarRowData(&$data, &$cache) { diff --git a/tests/Orm/Hydration/BasicHydrationTest.php b/tests/Orm/Hydration/BasicHydrationTest.php index 3cba5a78e..96958193e 100644 --- a/tests/Orm/Hydration/BasicHydrationTest.php +++ b/tests/Orm/Hydration/BasicHydrationTest.php @@ -856,6 +856,86 @@ class Orm_Hydration_BasicHydrationTest extends Doctrine_OrmTestCase } + /** Result set provider for the HYDRATE_SINGLE_SCALAR tests */ + public static function singleScalarResultSetProvider() { + return array( + // valid + array('name' => 'result1', + 'resultSet' => array( + array( + 'u__name' => 'romanb' + ) + )), + // valid + array('name' => 'result2', + 'resultSet' => array( + array( + 'u__id' => '1' + ) + )), + // invalid + array('name' => 'result3', + 'resultSet' => array( + array( + 'u__id' => '1', + 'u__name' => 'romanb' + ) + )), + // invalid + array('name' => 'result4', + 'resultSet' => array( + array( + 'u__id' => '1' + ), + array( + 'u__id' => '2' + ) + )), + ); + } + /** + * select u.name from CmsUser u where u.id = 1 + * + * @dataProvider singleScalarResultSetProvider + */ + public function testHydrateSingleScalar($name, $resultSet) + { + // Faked query components + $queryComponents = array( + 'u' => array( + 'table' => $this->_em->getClassMetadata('CmsUser'), + 'mapper' => $this->_em->getEntityPersister('CmsUser'), + 'parent' => null, + 'relation' => null, + 'map' => null + ) + ); + + // Faked table alias map + $tableAliasMap = array( + 'u' => 'u' + ); + + $stmt = new Doctrine_HydratorMockStatement($resultSet); + $hydrator = new Doctrine_HydratorNew($this->_em); + + if ($name == 'result1') { + $result = $hydrator->hydrateResultSet($this->_createParserResult( + $stmt, $queryComponents, $tableAliasMap, Doctrine::HYDRATE_SINGLE_SCALAR)); + $this->assertEquals('romanb', $result); + } else if ($name == 'result2') { + $result = $hydrator->hydrateResultSet($this->_createParserResult( + $stmt, $queryComponents, $tableAliasMap, Doctrine::HYDRATE_SINGLE_SCALAR)); + $this->assertEquals(1, $result); + } else if ($name == 'result3' || $name == 'result4') { + try { + $result = $hydrator->hydrateResultSet($this->_createParserResult( + $stmt, $queryComponents, $tableAliasMap, Doctrine::HYDRATE_SINGLE_SCALAR)); + $this->fail(); + } catch (Doctrine_Hydrator_Exception $ex) {} + } + + } } diff --git a/tests/lib/mocks/Doctrine_HydratorMockStatement.php b/tests/lib/mocks/Doctrine_HydratorMockStatement.php index ffa6fe73f..9e37a4c3d 100644 --- a/tests/lib/mocks/Doctrine_HydratorMockStatement.php +++ b/tests/lib/mocks/Doctrine_HydratorMockStatement.php @@ -33,6 +33,14 @@ class Doctrine_HydratorMockStatement return $this->_resultSet; } + public function fetchColumn($columnNumber = 0) + { + $row = array_shift($this->_resultSet); + if ( ! is_array($row)) return false; + $val = array_shift($row); + return $val !== null ? $val : false; + } + /** * Fetches the next row in the result set. *