Commit 639718e9 authored by romanb's avatar romanb

[2.0][DDC-335][DDC-347][DDC-317] Fixed. Also prepared DQL for CASE/COALESCE/NULLIF support.

parent 6f6628c2
...@@ -124,10 +124,6 @@ class DoctrineException extends \Exception ...@@ -124,10 +124,6 @@ class DoctrineException extends \Exception
if ( ! self::$_messages) { if ( ! self::$_messages) {
// Lazy-init messages // Lazy-init messages
self::$_messages = array( self::$_messages = array(
'DoctrineException#partialObjectsAreDangerous' =>
"Loading partial objects is dangerous. Fetch full objects or consider " .
"using a different fetch mode. If you really want partial objects, " .
"set the doctrine.forcePartialLoad query hint to TRUE.",
'QueryException#nonUniqueResult' => 'QueryException#nonUniqueResult' =>
"The query contains more than one result." "The query contains more than one result."
); );
......
...@@ -79,6 +79,9 @@ class ArrayHydrator extends AbstractHydrator ...@@ -79,6 +79,9 @@ class ArrayHydrator extends AbstractHydrator
if (isset($rowData['scalars'])) { if (isset($rowData['scalars'])) {
$scalars = $rowData['scalars']; $scalars = $rowData['scalars'];
unset($rowData['scalars']); unset($rowData['scalars']);
if (empty($rowData)) {
++$this->_resultCounter;
}
} }
// 2) Now hydrate the data found in the current row. // 2) Now hydrate the data found in the current row.
...@@ -129,7 +132,7 @@ class ArrayHydrator extends AbstractHydrator ...@@ -129,7 +132,7 @@ class ArrayHydrator extends AbstractHydrator
} }
end($baseElement[$relationAlias]); end($baseElement[$relationAlias]);
$this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] = $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] =
key($baseElement[$relationAlias]); key($baseElement[$relationAlias]);
} }
} else if ( ! isset($baseElement[$relationAlias])) { } else if ( ! isset($baseElement[$relationAlias])) {
$baseElement[$relationAlias] = array(); $baseElement[$relationAlias] = array();
...@@ -177,6 +180,10 @@ class ArrayHydrator extends AbstractHydrator ...@@ -177,6 +180,10 @@ class ArrayHydrator extends AbstractHydrator
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = key($result); $this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = key($result);
} else { } else {
$index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]]; $index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]];
/*if ($this->_rsm->isMixed) {
$result[] =& $result[$index];
++$this->_resultCounter;
}*/
} }
$this->updateResultPointer($result, $index, $dqlAlias, false); $this->updateResultPointer($result, $index, $dqlAlias, false);
} }
......
...@@ -251,6 +251,9 @@ class ObjectHydrator extends AbstractHydrator ...@@ -251,6 +251,9 @@ class ObjectHydrator extends AbstractHydrator
if (isset($rowData['scalars'])) { if (isset($rowData['scalars'])) {
$scalars = $rowData['scalars']; $scalars = $rowData['scalars'];
unset($rowData['scalars']); unset($rowData['scalars']);
if (empty($rowData)) {
++$this->_resultCounter;
}
} }
// Hydrate the data chunks // Hydrate the data chunks
...@@ -409,14 +412,18 @@ class ObjectHydrator extends AbstractHydrator ...@@ -409,14 +412,18 @@ class ObjectHydrator extends AbstractHydrator
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $this->_resultCounter; $this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $this->_resultCounter;
++$this->_resultCounter; ++$this->_resultCounter;
} }
// Update result pointer // Update result pointer
$this->_resultPointers[$dqlAlias] = $element; $this->_resultPointers[$dqlAlias] = $element;
} else { } else {
// Update result pointer // Update result pointer
$index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]]; $index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]];
$this->_resultPointers[$dqlAlias] = $result[$index]; $this->_resultPointers[$dqlAlias] = $result[$index];
/*if ($this->_rsm->isMixed) {
$result[] = $result[$index];
++$this->_resultCounter;
}*/
} }
} }
} }
......
...@@ -278,7 +278,7 @@ class OneToOneMapping extends AssociationMapping ...@@ -278,7 +278,7 @@ class OneToOneMapping extends AssociationMapping
/** /**
* @internal Experimental. For MetaModel API, Doctrine 2.1 or later. * @internal Experimental. For MetaModel API, Doctrine 2.1 or later.
*/ */
public static function __set_state(array $state) /*public static function __set_state(array $state)
{ {
$assoc = new self(array()); $assoc = new self(array());
$assoc->isOptional = $state['isOptional']; $assoc->isOptional = $state['isOptional'];
...@@ -302,5 +302,5 @@ class OneToOneMapping extends AssociationMapping ...@@ -302,5 +302,5 @@ class OneToOneMapping extends AssociationMapping
$assoc->sourceFieldName = $state['sourceFieldName']; $assoc->sourceFieldName = $state['sourceFieldName'];
return $assoc; return $assoc;
} }*/
} }
<?php
namespace Doctrine\ORM\Query\AST;
use Doctrine\ORM\Query\QueryException;
class ASTException extends QueryException
{
public static function noDispatchForNode($node)
{
return new self("Double-dispatch for node " . get_class($node) . " is not supported.");
}
}
\ No newline at end of file
...@@ -41,6 +41,7 @@ class SizeFunction extends FunctionNode ...@@ -41,6 +41,7 @@ class SizeFunction extends FunctionNode
/** /**
* @override * @override
* @todo If the collection being counted is already joined, the SQL can be simpler (more efficient).
*/ */
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{ {
......
...@@ -38,13 +38,10 @@ class Join extends Node ...@@ -38,13 +38,10 @@ class Join extends Node
const JOIN_TYPE_LEFT = 1; const JOIN_TYPE_LEFT = 1;
const JOIN_TYPE_LEFTOUTER = 2; const JOIN_TYPE_LEFTOUTER = 2;
const JOIN_TYPE_INNER = 3; const JOIN_TYPE_INNER = 3;
const JOIN_WHERE_ON = 1;
const JOIN_WHERE_WITH = 2;
public $joinType = self::JOIN_TYPE_INNER; public $joinType = self::JOIN_TYPE_INNER;
public $joinAssociationPathExpression = null; public $joinAssociationPathExpression = null;
public $aliasIdentificationVariable = null; public $aliasIdentificationVariable = null;
public $whereType = self::JOIN_WHERE_WITH;
public $conditionalExpression = null; public $conditionalExpression = null;
public function __construct($joinType, $joinAssocPathExpr, $aliasIdentVar) public function __construct($joinType, $joinAssocPathExpr, $aliasIdentVar)
......
...@@ -34,7 +34,17 @@ namespace Doctrine\ORM\Query\AST; ...@@ -34,7 +34,17 @@ namespace Doctrine\ORM\Query\AST;
*/ */
abstract class Node abstract class Node
{ {
abstract public function dispatch($walker); /**
* Double-dispatch method, supposed to dispatch back to the walker.
*
* Implementation is not mandatory for all nodes.
*
* @param $walker
*/
public function dispatch($walker)
{
throw ASTException::noDispatchForNode($this);
}
/** /**
* Dumps the AST Node into a string representation for information purpose only * Dumps the AST Node into a string representation for information purpose only
......
<?php
namespace Doctrine\ORM\Query\AST;
class PartialObjectExpression extends Node
{
public $identificationVariable;
public $partialFieldSet;
public function __construct($identificationVariable, array $partialFieldSet)
{
$this->identificationVariable = $identificationVariable;
$this->partialFieldSet = $partialFieldSet;
}
}
\ No newline at end of file
...@@ -88,7 +88,6 @@ class Lexer extends \Doctrine\Common\Lexer ...@@ -88,7 +88,6 @@ class Lexer extends \Doctrine\Common\Lexer
const T_NULL = 145; const T_NULL = 145;
const T_OF = 146; const T_OF = 146;
const T_OFFSET = 147; const T_OFFSET = 147;
const T_ON = 148;
const T_OPEN_PARENTHESIS = 149; const T_OPEN_PARENTHESIS = 149;
const T_OR = 150; const T_OR = 150;
const T_ORDER = 151; const T_ORDER = 151;
...@@ -104,8 +103,9 @@ class Lexer extends \Doctrine\Common\Lexer ...@@ -104,8 +103,9 @@ class Lexer extends \Doctrine\Common\Lexer
const T_UPDATE = 161; const T_UPDATE = 161;
const T_WHERE = 162; const T_WHERE = 162;
const T_WITH = 163; const T_WITH = 163;
const T_PARTIAL = 164;
private $_keywordsTable; const T_OPEN_CURLY_BRACE = 165;
const T_CLOSE_CURLY_BRACE = 166;
/** /**
* Creates a new query scanner object. * Creates a new query scanner object.
...@@ -151,7 +151,7 @@ class Lexer extends \Doctrine\Common\Lexer ...@@ -151,7 +151,7 @@ class Lexer extends \Doctrine\Common\Lexer
$value = $newVal; $value = $newVal;
return (strpos($value, '.') !== false || stripos($value, 'e') !== false) return (strpos($value, '.') !== false || stripos($value, 'e') !== false)
? self::T_FLOAT : self::T_INTEGER; ? self::T_FLOAT : self::T_INTEGER;
} }
if ($value[0] === "'") { if ($value[0] === "'") {
...@@ -176,6 +176,8 @@ class Lexer extends \Doctrine\Common\Lexer ...@@ -176,6 +176,8 @@ class Lexer extends \Doctrine\Common\Lexer
case '*': return self::T_MULTIPLY; case '*': return self::T_MULTIPLY;
case '/': return self::T_DIVIDE; case '/': return self::T_DIVIDE;
case '!': return self::T_NEGATE; case '!': return self::T_NEGATE;
case '{': return self::T_OPEN_CURLY_BRACE;
case '}': return self::T_CLOSE_CURLY_BRACE;
default: default:
// Do nothing // Do nothing
break; break;
...@@ -186,7 +188,7 @@ class Lexer extends \Doctrine\Common\Lexer ...@@ -186,7 +188,7 @@ class Lexer extends \Doctrine\Common\Lexer
} }
/** /**
* @todo Doc * @todo Inline this method.
*/ */
private function _getNumeric($value) private function _getNumeric($value)
{ {
...@@ -206,6 +208,7 @@ class Lexer extends \Doctrine\Common\Lexer ...@@ -206,6 +208,7 @@ class Lexer extends \Doctrine\Common\Lexer
* *
* @param string $identifier identifier name * @param string $identifier identifier name
* @return int token type * @return int token type
* @todo Inline this method.
*/ */
private function _checkLiteral($identifier) private function _checkLiteral($identifier)
{ {
......
This diff is collapsed.
...@@ -85,6 +85,15 @@ class QueryException extends \Doctrine\Common\DoctrineException ...@@ -85,6 +85,15 @@ class QueryException extends \Doctrine\Common\DoctrineException
"in class ".$assoc->sourceEntityName." assocation ".$assoc->sourceFieldName "in class ".$assoc->sourceEntityName." assocation ".$assoc->sourceFieldName
); );
} }
public static function partialObjectsAreDangerous()
{
return new self(
"Loading partial objects is dangerous. Fetch full objects or consider " .
"using a different fetch mode. If you really want partial objects, " .
"set the doctrine.forcePartialLoad query hint to TRUE."
);
}
public static function overwritingJoinConditionsNotYetSupported($assoc) public static function overwritingJoinConditionsNotYetSupported($assoc)
{ {
...@@ -94,4 +103,21 @@ class QueryException extends \Doctrine\Common\DoctrineException ...@@ -94,4 +103,21 @@ class QueryException extends \Doctrine\Common\DoctrineException
"Use WITH to append additional join conditions to the association." "Use WITH to append additional join conditions to the association."
); );
} }
public static function associationPathInverseSideNotSupported()
{
return new self(
"A single-valued association path expression to an inverse side is not supported".
" in DQL queries. Use an explicit join instead."
);
}
public static function associationPathCompositeKeyNotSupported()
{
return new self(
"A single-valued association path expression to an entity with a composite primary ".
"key is not supported. Explicitly name the components of the composite primary key ".
"in the query."
);
}
} }
\ No newline at end of file
This diff is collapsed.
...@@ -317,7 +317,7 @@ class UnitOfWork implements PropertyChangedListener ...@@ -317,7 +317,7 @@ class UnitOfWork implements PropertyChangedListener
} catch (\Exception $e) { } catch (\Exception $e) {
$conn->setRollbackOnly(); $conn->setRollbackOnly();
$conn->rollback(); $conn->rollback();
$this->clear(); $this->_em->close();
throw $e; throw $e;
} }
......
...@@ -116,5 +116,4 @@ class CmsUser ...@@ -116,5 +116,4 @@ class CmsUser
$address->setUser($this); $address->setUser($this);
} }
} }
} }
...@@ -286,6 +286,7 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase ...@@ -286,6 +286,7 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals('gblanco', $users[0]->username); $this->assertEquals('gblanco', $users[0]->username);
$this->assertEquals('developer', $users[0]->status); $this->assertEquals('developer', $users[0]->status);
$this->assertTrue($users[0]->phonenumbers instanceof \Doctrine\ORM\PersistentCollection); $this->assertTrue($users[0]->phonenumbers instanceof \Doctrine\ORM\PersistentCollection);
$this->assertTrue($users[0]->phonenumbers->isInitialized());
$this->assertEquals(0, $users[0]->phonenumbers->count()); $this->assertEquals(0, $users[0]->phonenumbers->count());
//$this->assertNull($users[0]->articles); //$this->assertNull($users[0]->articles);
} }
...@@ -332,7 +333,7 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase ...@@ -332,7 +333,7 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->flush(); $this->_em->flush();
$this->_em->clear(); $this->_em->clear();
$query = $this->_em->createQuery("select u, g from Doctrine\Tests\Models\CMS\CmsUser u inner join u.groups g"); $query = $this->_em->createQuery("select u, g from Doctrine\Tests\Models\CMS\CmsUser u join u.groups g");
$this->assertEquals(0, count($query->getResult())); $this->assertEquals(0, count($query->getResult()));
} }
......
...@@ -4,6 +4,7 @@ namespace Doctrine\Tests\ORM\Functional; ...@@ -4,6 +4,7 @@ namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Tests\Models\CMS\CmsUser; use Doctrine\Tests\Models\CMS\CmsUser;
use Doctrine\Tests\Models\CMS\CmsPhonenumber; use Doctrine\Tests\Models\CMS\CmsPhonenumber;
use Doctrine\Tests\Models\CMS\CmsAddress;
use Doctrine\ORM\UnitOfWork; use Doctrine\ORM\UnitOfWork;
require_once __DIR__ . '/../../TestInit.php'; require_once __DIR__ . '/../../TestInit.php';
...@@ -83,7 +84,6 @@ class DetachedEntityTest extends \Doctrine\Tests\OrmFunctionalTestCase ...@@ -83,7 +84,6 @@ class DetachedEntityTest extends \Doctrine\Tests\OrmFunctionalTestCase
$phonenumbers = $user->getPhonenumbers(); $phonenumbers = $user->getPhonenumbers();
$this->assertTrue($this->_em->contains($phonenumbers[0])); $this->assertTrue($this->_em->contains($phonenumbers[0]));
$this->assertTrue($this->_em->contains($phonenumbers[1])); $this->assertTrue($this->_em->contains($phonenumbers[1]));
} }
} }
...@@ -189,8 +189,7 @@ class QueryDqlFunctionTest extends \Doctrine\Tests\OrmFunctionalTestCase ...@@ -189,8 +189,7 @@ class QueryDqlFunctionTest extends \Doctrine\Tests\OrmFunctionalTestCase
" TRIM(LEADING '.' FROM m.name) AS str2, TRIM(CONCAT(' ', CONCAT(m.name, ' '))) AS str3 ". " TRIM(LEADING '.' FROM m.name) AS str2, TRIM(CONCAT(' ', CONCAT(m.name, ' '))) AS str3 ".
"FROM Doctrine\Tests\Models\Company\CompanyManager m"; "FROM Doctrine\Tests\Models\Company\CompanyManager m";
$result = $this->_em->createQuery($dql) $result = $this->_em->createQuery($dql)->getArrayResult();
->getArrayResult();
$this->assertEquals(4, count($result)); $this->assertEquals(4, count($result));
$this->assertEquals('Roman B', $result[0]['str1']); $this->assertEquals('Roman B', $result[0]['str1']);
...@@ -207,34 +206,34 @@ class QueryDqlFunctionTest extends \Doctrine\Tests\OrmFunctionalTestCase ...@@ -207,34 +206,34 @@ class QueryDqlFunctionTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals('Jonathan W.', $result[3]['str3']); $this->assertEquals('Jonathan W.', $result[3]['str3']);
} }
/*public function testOperatorAdd() public function testOperatorAdd()
{ {
$result = $this->_em->createQuery('SELECT m, m.salary+2500 AS add FROM Doctrine\Tests\Models\Company\CompanyManager m') $result = $this->_em->createQuery('SELECT m, m.salary+2500 AS add FROM Doctrine\Tests\Models\Company\CompanyManager m')
->getResult(); ->getResult();
$this->assertEquals(4, count($result)); $this->assertEquals(4, count($result));
$this->assertEquals(102500, $result[0]['op']); $this->assertEquals(102500, $result[0]['add']);
$this->assertEquals(202500, $result[1]['op']); $this->assertEquals(202500, $result[1]['add']);
$this->assertEquals(402500, $result[2]['op']); $this->assertEquals(402500, $result[2]['add']);
$this->assertEquals(802500, $result[3]['op']); $this->assertEquals(802500, $result[3]['add']);
} }
public function testOperatorSub() public function testOperatorSub()
{ {
$result = $this->_em->createQuery('SELECT m, m.salary-2500 AS add FROM Doctrine\Tests\Models\Company\CompanyManager m') $result = $this->_em->createQuery('SELECT m, m.salary-2500 AS sub FROM Doctrine\Tests\Models\Company\CompanyManager m')
->getResult(); ->getResult();
$this->assertEquals(4, count($result)); $this->assertEquals(4, count($result));
$this->assertEquals(102500, $result[0]['op']); $this->assertEquals(97500, $result[0]['sub']);
$this->assertEquals(202500, $result[1]['op']); $this->assertEquals(197500, $result[1]['sub']);
$this->assertEquals(402500, $result[2]['op']); $this->assertEquals(397500, $result[2]['sub']);
$this->assertEquals(802500, $result[3]['op']); $this->assertEquals(797500, $result[3]['sub']);
} }
public function testOperatorMultiply() public function testOperatorMultiply()
{ {
$result = $this->_em->createQuery('SELECT m, m.salary*2 AS op FROM Doctrine\Tests\Models\Company\CompanyManager m') $result = $this->_em->createQuery('SELECT m, m.salary*2 AS op FROM Doctrine\Tests\Models\Company\CompanyManager m')
->getResult(); ->getResult();
$this->assertEquals(4, count($result)); $this->assertEquals(4, count($result));
$this->assertEquals(200000, $result[0]['op']); $this->assertEquals(200000, $result[0]['op']);
...@@ -243,17 +242,33 @@ class QueryDqlFunctionTest extends \Doctrine\Tests\OrmFunctionalTestCase ...@@ -243,17 +242,33 @@ class QueryDqlFunctionTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals(1600000, $result[3]['op']); $this->assertEquals(1600000, $result[3]['op']);
} }
/**
* @group test
*/
public function testOperatorDiv() public function testOperatorDiv()
{ {
$result = $this->_em->createQuery('SELECT m, (m.salary/0.5) AS op FROM Doctrine\Tests\Models\Company\CompanyManager m') $result = $this->_em->createQuery('SELECT m, (m.salary/0.5) AS op FROM Doctrine\Tests\Models\Company\CompanyManager m')
->getResult(); ->getResult();
$this->assertEquals(4, count($result)); $this->assertEquals(4, count($result));
$this->assertEquals(200000, $result[0]['op']); $this->assertEquals(200000, $result[0]['op']);
$this->assertEquals(400000, $result[1]['op']); $this->assertEquals(400000, $result[1]['op']);
$this->assertEquals(800000, $result[2]['op']); $this->assertEquals(800000, $result[2]['op']);
$this->assertEquals(1600000, $result[3]['op']); $this->assertEquals(1600000, $result[3]['op']);
}*/ }
public function testConcatFunction()
{
$arg = $this->_em->createQuery('SELECT CONCAT(m.name, m.department) AS namedep FROM Doctrine\Tests\Models\Company\CompanyManager m order by namedep desc')
->getArrayResult();
$this->assertEquals(4, count($arg));
$this->assertEquals('Roman B.IT', $arg[0]['namedep']);
$this->assertEquals('Jonathan W.Administration', $arg[1]['namedep']);
$this->assertEquals('Guilherme B.Complaint Department', $arg[2]['namedep']);
$this->assertEquals('Benjamin E.HR', $arg[3]['namedep']);
}
protected function generateFixture() protected function generateFixture()
{ {
......
...@@ -45,7 +45,7 @@ class DDC163Test extends \Doctrine\Tests\OrmFunctionalTestCase ...@@ -45,7 +45,7 @@ class DDC163Test extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->flush(); $this->_em->flush();
$this->_em->clear(); $this->_em->clear();
$dql = 'SELECT person.name, spouse.name, friend.name $dql = 'SELECT PARTIAL person.{id,name}, PARTIAL spouse.{id,name}, PARTIAL friend.{id,name}
FROM Doctrine\Tests\Models\Company\CompanyPerson person FROM Doctrine\Tests\Models\Company\CompanyPerson person
LEFT JOIN person.spouse spouse LEFT JOIN person.spouse spouse
LEFT JOIN person.friends friend LEFT JOIN person.friends friend
......
...@@ -626,6 +626,76 @@ class ArrayHydratorTest extends HydrationTestCase ...@@ -626,6 +626,76 @@ class ArrayHydratorTest extends HydrationTestCase
$this->assertTrue(isset($result[1]['boards'])); $this->assertTrue(isset($result[1]['boards']));
$this->assertEquals(1, count($result[1]['boards'])); $this->assertEquals(1, count($result[1]['boards']));
} }
/**
* DQL: select partial u.{id,status}, a.id, a.topic, c.id as cid, c.topic as ctopic from CmsUser u left join u.articles a left join a.comments c
*
*/
/*public function testChainedJoinWithScalars()
{
$rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
$rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status');
$rsm->addScalarResult('a__id', 'id');
$rsm->addScalarResult('a__topic', 'topic');
$rsm->addScalarResult('c__id', 'cid');
$rsm->addScalarResult('c__topic', 'ctopic');
// Faked result set
$resultSet = array(
//row1
array(
'u__id' => '1',
'u__status' => 'developer',
'a__id' => '1',
'a__topic' => 'The First',
'c__id' => '1',
'c__topic' => 'First Comment'
),
array(
'u__id' => '1',
'u__status' => 'developer',
'a__id' => '1',
'a__topic' => 'The First',
'c__id' => '2',
'c__topic' => 'Second Comment'
),
array(
'u__id' => '1',
'u__status' => 'developer',
'a__id' => '42',
'a__topic' => 'The Answer',
'c__id' => null,
'c__topic' => null
),
);
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm);
$this->assertEquals(3, count($result));
$this->assertEquals(2, count($result[0][0])); // User array
$this->assertEquals(1, $result[0]['id']);
$this->assertEquals('The First', $result[0]['topic']);
$this->assertEquals(1, $result[0]['cid']);
$this->assertEquals('First Comment', $result[0]['ctopic']);
$this->assertEquals(2, count($result[1][0])); // User array, duplicated
$this->assertEquals(1, $result[1]['id']); // duplicated
$this->assertEquals('The First', $result[1]['topic']); // duplicated
$this->assertEquals(2, $result[1]['cid']);
$this->assertEquals('Second Comment', $result[1]['ctopic']);
$this->assertEquals(2, count($result[2][0])); // User array, duplicated
$this->assertEquals(42, $result[2]['id']);
$this->assertEquals('The Answer', $result[2]['topic']);
$this->assertNull($result[2]['cid']);
$this->assertNull($result[2]['ctopic']);
}*/
public function testResultIteration() public function testResultIteration()
{ {
......
...@@ -743,6 +743,81 @@ class ObjectHydratorTest extends HydrationTestCase ...@@ -743,6 +743,81 @@ class ObjectHydratorTest extends HydrationTestCase
$this->assertEquals(0, $result[0]->articles->count()); $this->assertEquals(0, $result[0]->articles->count());
$this->assertEquals(0, $result[1]->articles->count()); $this->assertEquals(0, $result[1]->articles->count());
} }
/**
* DQL: select partial u.{id,status}, a.id, a.topic, c.id as cid, c.topic as ctopic from CmsUser u left join u.articles a left join a.comments c
*
* @group bubu
*/
/*public function testChainedJoinWithScalars()
{
$rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
$rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status');
$rsm->addScalarResult('a__id', 'id');
$rsm->addScalarResult('a__topic', 'topic');
$rsm->addScalarResult('c__id', 'cid');
$rsm->addScalarResult('c__topic', 'ctopic');
// Faked result set
$resultSet = array(
//row1
array(
'u__id' => '1',
'u__status' => 'developer',
'a__id' => '1',
'a__topic' => 'The First',
'c__id' => '1',
'c__topic' => 'First Comment'
),
array(
'u__id' => '1',
'u__status' => 'developer',
'a__id' => '1',
'a__topic' => 'The First',
'c__id' => '2',
'c__topic' => 'Second Comment'
),
array(
'u__id' => '1',
'u__status' => 'developer',
'a__id' => '42',
'a__topic' => 'The Answer',
'c__id' => null,
'c__topic' => null
),
);
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
$this->assertEquals(3, count($result));
$this->assertTrue($result[0][0] instanceof CmsUser); // User object
$this->assertEquals(1, $result[0]['id']);
$this->assertEquals('The First', $result[0]['topic']);
$this->assertEquals(1, $result[0]['cid']);
$this->assertEquals('First Comment', $result[0]['ctopic']);
$this->assertTrue($result[1][0] instanceof CmsUser); // Same User object
$this->assertEquals(1, $result[1]['id']); // duplicated
$this->assertEquals('The First', $result[1]['topic']); // duplicated
$this->assertEquals(2, $result[1]['cid']);
$this->assertEquals('Second Comment', $result[1]['ctopic']);
$this->assertTrue($result[2][0] instanceof CmsUser); // Same User object
$this->assertEquals(42, $result[2]['id']);
$this->assertEquals('The Answer', $result[2]['topic']);
$this->assertNull($result[2]['cid']);
$this->assertNull($result[2]['ctopic']);
$this->assertTrue($result[0][0] === $result[1][0]);
$this->assertTrue($result[1][0] === $result[2][0]);
$this->assertTrue($result[0][0] === $result[2][0]);
}*/
public function testResultIteration() public function testResultIteration()
{ {
......
...@@ -215,9 +215,9 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase ...@@ -215,9 +215,9 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :id'); $this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :id');
} }
public function testJoinConditionsSupported() public function testJoinConditionOverrideNotSupported()
{ {
$this->assertValidDql("SELECT u.name, p FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.phonenumbers p ON p.phonenumber = '123 123'"); $this->assertInvalidDql("SELECT u.name, p FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.phonenumbers p ON p.phonenumber = '123 123'");
} }
public function testIndexByClauseWithOneComponent() public function testIndexByClauseWithOneComponent()
...@@ -270,12 +270,12 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase ...@@ -270,12 +270,12 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
$this->assertInvalidDql("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.articles u WHERE u.id = 1"); $this->assertInvalidDql("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.articles u WHERE u.id = 1");
} }
/*public function testImplicitJoinInWhereOnSingleValuedAssociationPathExpression() public function testImplicitJoinInWhereOnSingleValuedAssociationPathExpression()
{ {
// This should be allowed because avatar is a single-value association. // This should be allowed because avatar is a single-value association.
// SQL: SELECT ... FROM forum_user fu INNER JOIN forum_avatar fa ON fu.avatar_id = fa.id WHERE fa.id = ? // SQL: SELECT ... FROM forum_user fu INNER JOIN forum_avatar fa ON fu.avatar_id = fa.id WHERE fa.id = ?
$this->assertValidDql("SELECT u FROM Doctrine\Tests\Models\Forum\ForumUser u WHERE u.avatar.id = ?"); $this->assertValidDql("SELECT u FROM Doctrine\Tests\Models\Forum\ForumUser u WHERE u.avatar.id = ?1");
}*/ }
public function testImplicitJoinInWhereOnCollectionValuedPathExpression() public function testImplicitJoinInWhereOnCollectionValuedPathExpression()
{ {
...@@ -319,10 +319,6 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase ...@@ -319,10 +319,6 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
} }
/** /**
* TODO: Hydration can't deal with this currently but it should be allowed.
* Also, generated SQL looks like: "... FROM cms_user, cms_article ..." which
* may not work on all dbms.
*
* The main use case for this generalized style of join is when a join condition * The main use case for this generalized style of join is when a join condition
* does not involve a foreign key relationship that is mapped to an entity relationship. * does not involve a foreign key relationship that is mapped to an entity relationship.
*/ */
...@@ -392,15 +388,30 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase ...@@ -392,15 +388,30 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
$this->assertInvalidDql('SELECT u FROM UnknownClassName u'); $this->assertInvalidDql('SELECT u FROM UnknownClassName u');
} }
/** public function testCorrectPartialObjectLoad()
* This checks for invalid attempt to hydrate a proxy. It should throw an exception {
* $this->assertValidDql('SELECT PARTIAL u.{id,name} FROM Doctrine\Tests\Models\CMS\CmsUser u');
* @expectedException \Doctrine\Common\DoctrineException }
*/
public function testPartialObjectLoad() public function testIncorrectPartialObjectLoadBecauseOfMissingIdentifier()
{
$this->assertInvalidDql('SELECT PARTIAL u.{name} FROM Doctrine\Tests\Models\CMS\CmsUser u');
}
public function testScalarExpressionInSelect()
{
$this->assertValidDql('SELECT u, 42 + u.id AS someNumber FROM Doctrine\Tests\Models\CMS\CmsUser u');
}
public function testInputParameterInSelect()
{
$this->assertValidDql('SELECT u, u.id + ?1 AS someNumber FROM Doctrine\Tests\Models\CMS\CmsUser u');
}
/* The exception is currently thrown in the SQLWalker, not earlier.
public function testInverseSideSingleValuedAssociationPathNotAllowed()
{ {
$this->parseDql('SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u', array( $this->assertInvalidDql('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.address = ?1');
\Doctrine\ORM\Query::HINT_FORCE_PARTIAL_LOAD => false
));
} }
*/
} }
\ No newline at end of file
...@@ -23,7 +23,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase ...@@ -23,7 +23,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
$query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true); $query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
parent::assertEquals($sqlToBeConfirmed, $query->getSql()); parent::assertEquals($sqlToBeConfirmed, $query->getSql());
$query->free(); $query->free();
} catch (DoctrineException $e) { } catch (\Exception $e) {
$this->fail($e->getMessage()); $this->fail($e->getMessage());
} }
} }
...@@ -534,4 +534,24 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase ...@@ -534,4 +534,24 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_addresses c1_ WHERE c1_.user_id = c0_.id AND c1_.id = ?)" "SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_addresses c1_ WHERE c1_.user_id = c0_.id AND c1_.id = ?)"
);*/ );*/
} }
public function testSingleValuedAssociationNullCheckOnOwningSide()
{
$this->assertSqlGeneration(
"SELECT a FROM Doctrine\Tests\Models\CMS\CmsAddress a WHERE a.user IS NULL",
"SELECT c0_.id AS id0, c0_.country AS country1, c0_.zip AS zip2, c0_.city AS city3 FROM cms_addresses c0_ WHERE c0_.user_id IS NULL"
);
}
// Null check on inverse side has to happen through explicit JOIN.
// "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.address IS NULL"
// where the CmsUser is the inverse side is not supported.
public function testSingleValuedAssociationNullCheckOnInverseSide()
{
$this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.address a WHERE a.id IS NULL",
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ LEFT JOIN cms_addresses c1_ ON c0_.id = c1_.user_id WHERE c1_.id IS NULL"
);
}
} }
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