From 2e90cd9924d551f7e090e82eb393313b74703e51 Mon Sep 17 00:00:00 2001 From: "Fabio B. Silva" Date: Sun, 16 Dec 2012 20:48:43 -0200 Subject: [PATCH 1/3] Identity function support composite primary key --- .../Query/AST/Functions/IdentityFunction.php | 67 +++++++++++++++---- .../Functional/CompositePrimaryKeyTest.php | 18 +++++ .../ORM/Query/SelectSqlGenerationTest.php | 23 +++++++ 3 files changed, 96 insertions(+), 12 deletions(-) diff --git a/lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php index 091942da6..a6c66c2bd 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php @@ -20,9 +20,12 @@ namespace Doctrine\ORM\Query\AST\Functions; use Doctrine\ORM\Query\Lexer; +use Doctrine\ORM\Query\Parser; +use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\QueryException; /** - * "IDENTITY" "(" SingleValuedAssociationPathExpression ")" + * "IDENTITY" "(" SingleValuedAssociationPathExpression {"," string} ")" * * * @link www.doctrine-project.org @@ -32,35 +35,75 @@ use Doctrine\ORM\Query\Lexer; */ class IdentityFunction extends FunctionNode { + /** + * @var \Doctrine\ORM\Query\AST\PathExpression + */ public $pathExpression; /** - * @override + * @var integer */ - public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) - { - $dqlAlias = $this->pathExpression->identificationVariable; - $assocField = $this->pathExpression->field; + public $fieldMapping; - $qComp = $sqlWalker->getQueryComponent($dqlAlias); - $class = $qComp['metadata']; - $assoc = $class->associationMappings[$assocField]; + /** + * {@inheritdoc} + */ + public function getSql(SqlWalker $sqlWalker) + { + $platform = $sqlWalker->getEntityManager()->getConnection()->getDatabasePlatform(); + $quoteStrategy = $sqlWalker->getEntityManager()->getConfiguration()->getQuoteStrategy(); + $dqlAlias = $this->pathExpression->identificationVariable; + $assocField = $this->pathExpression->field; + $qComp = $sqlWalker->getQueryComponent($dqlAlias); + $class = $qComp['metadata']; + $assoc = $class->associationMappings[$assocField]; + $targetEntity = $sqlWalker->getEntityManager()->getClassMetadata($assoc['targetEntity']); + $joinColumn = reset($assoc['joinColumns']); + + if ($this->fieldMapping !== null) { + if ( ! isset($targetEntity->fieldMappings[$this->fieldMapping])) { + throw new QueryException(sprintf('Undefined reference field mapping "%s"', $this->fieldMapping)); + } + + $field = $targetEntity->fieldMappings[$this->fieldMapping]; + $joinColumn = null; + + foreach ($assoc['joinColumns'] as $mapping) { + if($mapping['referencedColumnName'] === $field['columnName']) { + $joinColumn = $mapping; + + break; + } + } + + if ($joinColumn === null) { + throw new QueryException(sprintf('Unable to resolve the reference field mapping "%s"', $this->fieldMapping)); + } + } $tableAlias = $sqlWalker->getSQLTableAlias($class->getTableName(), $dqlAlias); + $columName = $quoteStrategy->getJoinColumnName($joinColumn, $targetEntity, $platform); - return $tableAlias . '.' . reset($assoc['targetToSourceKeyColumns']); + return $tableAlias . '.' . $columName; } /** - * @override + * {@inheritdoc} */ - public function parse(\Doctrine\ORM\Query\Parser $parser) + public function parse(Parser $parser) { $parser->match(Lexer::T_IDENTIFIER); $parser->match(Lexer::T_OPEN_PARENTHESIS); $this->pathExpression = $parser->SingleValuedAssociationPathExpression(); + if ($parser->getLexer()->lookahead['type'] == Lexer::T_COMMA) { + $parser->match(Lexer::T_COMMA); + $parser->match(Lexer::T_STRING); + + $this->fieldMapping = $parser->getLexer()->token['value']; + } + $parser->match(Lexer::T_CLOSE_PARENTHESIS); } } diff --git a/tests/Doctrine/Tests/ORM/Functional/CompositePrimaryKeyTest.php b/tests/Doctrine/Tests/ORM/Functional/CompositePrimaryKeyTest.php index 1af930a0c..5a27b89af 100644 --- a/tests/Doctrine/Tests/ORM/Functional/CompositePrimaryKeyTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/CompositePrimaryKeyTest.php @@ -72,6 +72,24 @@ class CompositePrimaryKeyTest extends \Doctrine\Tests\OrmFunctionalTestCase $sql = $this->_em->createQuery($dql)->getSQL(); } + public function testIdentityFunctionWithCompositePrimaryKey() + { + $this->putGermanysBrandenburderTor(); + + $poi = $this->_em->find('Doctrine\Tests\Models\Navigation\NavPointOfInterest', array('lat' => 100, 'long' => 200)); + $photo = new NavPhotos($poi, "asdf"); + $this->_em->persist($photo); + $this->_em->flush(); + $this->_em->clear(); + + $dql = "SELECT IDENTITY(p.poi, 'long') AS long, IDENTITY(p.poi, 'lat') AS lat FROM Doctrine\Tests\Models\Navigation\NavPhotos p"; + $result = $this->_em->createQuery($dql)->getResult(); + + $this->assertCount(1, $result); + $this->assertEquals(200, $result[0]['long']); + $this->assertEquals(100, $result[0]['lat']); + } + public function testManyToManyCompositeRelation() { $this->putGermanysBrandenburderTor(); diff --git a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php index bb4bcea3c..ef52c4705 100644 --- a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php +++ b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php @@ -1261,6 +1261,29 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase ); } + public function testIdentityFunctionWithCompositePrimaryKey() + { + $this->assertSqlGeneration( + "SELECT IDENTITY(p.poi, 'long') AS long FROM Doctrine\Tests\Models\Navigation\NavPhotos p", + "SELECT n0_.poi_long AS sclr0 FROM navigation_photos n0_" + ); + + $this->assertSqlGeneration( + "SELECT IDENTITY(p.poi, 'lat') AS lat FROM Doctrine\Tests\Models\Navigation\NavPhotos p", + "SELECT n0_.poi_lat AS sclr0 FROM navigation_photos n0_" + ); + + $this->assertSqlGeneration( + "SELECT IDENTITY(p.poi, 'long') AS long, IDENTITY(p.poi, 'lat') AS lat FROM Doctrine\Tests\Models\Navigation\NavPhotos p", + "SELECT n0_.poi_long AS sclr0, n0_.poi_lat AS sclr1 FROM navigation_photos n0_" + ); + + $this->assertInvalidSqlGeneration( + "SELECT IDENTITY(p.poi, 'invalid') AS invalid FROM Doctrine\Tests\Models\Navigation\NavPhotos p", + "Doctrine\ORM\Query\QueryException" + ); + } + /** * @group DDC-1339 */ From 99ab58febd1f84eea6aafc6c63f6166545443126 Mon Sep 17 00:00:00 2001 From: "Fabio B. Silva" Date: Mon, 17 Dec 2012 10:03:41 -0200 Subject: [PATCH 2/3] Fix CS --- lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php index a6c66c2bd..540f2df9d 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php @@ -69,6 +69,7 @@ class IdentityFunction extends FunctionNode $joinColumn = null; foreach ($assoc['joinColumns'] as $mapping) { + if($mapping['referencedColumnName'] === $field['columnName']) { $joinColumn = $mapping; @@ -97,14 +98,13 @@ class IdentityFunction extends FunctionNode $this->pathExpression = $parser->SingleValuedAssociationPathExpression(); - if ($parser->getLexer()->lookahead['type'] == Lexer::T_COMMA) { + if ($parser->getLexer()->isNextToken(Lexer::T_COMMA)) { $parser->match(Lexer::T_COMMA); $parser->match(Lexer::T_STRING); $this->fieldMapping = $parser->getLexer()->token['value']; } - + $parser->match(Lexer::T_CLOSE_PARENTHESIS); } } - From 3d99711ac8fd06ed2c80b0c7c0da12b30b6f21d9 Mon Sep 17 00:00:00 2001 From: "Fabio B. Silva" Date: Mon, 17 Dec 2012 10:13:25 -0200 Subject: [PATCH 3/3] fix PHPDoc --- lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php index 540f2df9d..7e1d75aee 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php @@ -41,7 +41,7 @@ class IdentityFunction extends FunctionNode public $pathExpression; /** - * @var integer + * @var string */ public $fieldMapping;