From 38fcc66c16563b37ca5bc0641424c5151eaab05c Mon Sep 17 00:00:00 2001 From: Alexander Kurilo Date: Thu, 26 Jun 2014 16:42:50 +0300 Subject: [PATCH] Add missing type mapping Fixes DDC-3192 Refs DDC-2494 This is essentially a fix from DDC-2494 applied to SQLWalker. The issue: type was not converted to PHP value when the result is fetched by executing DQL query rather than using entity manager's findX(). Similar issue for BasicEntityPersister (which is used when em's findX is executed) was fixed in DDC-2494, but SQLWalker made the issue valid for any custom query. --- lib/Doctrine/ORM/Query/SqlWalker.php | 12 +- .../ORM/Functional/Ticket/DDC3192Test.php | 168 ++++++++++++++++++ 2 files changed, 178 insertions(+), 2 deletions(-) create mode 100644 tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3192Test.php diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index 7164f441f..498ac791d 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -753,12 +753,20 @@ class SqlWalker implements TreeWalker $owningClass = (isset($assoc['inherited'])) ? $this->em->getClassMetadata($assoc['inherited']) : $class; $sqlTableAlias = $this->getSQLTableAlias($owningClass->getTableName(), $dqlAlias); - foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) { + $targetClass = $this->em->getClassMetadata($assoc['targetEntity']); + + foreach ($assoc['targetToSourceKeyColumns'] as $targetColumn => $srcColumn) { $columnAlias = $this->getSQLColumnAlias($srcColumn); + $type = null; + $isIdentifier = (isset($assoc['id']) && $assoc['id'] === true); $sqlSelectExpressions[] = $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias; - $this->rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn, (isset($assoc['id']) && $assoc['id'] === true)); + if (isset($targetClass->fieldNames[$targetColumn])) { + $type = $targetClass->fieldMappings[$targetClass->fieldNames[$targetColumn]]['type']; + } + + $this->rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn, $isIdentifier, $type); } } diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3192Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3192Test.php new file mode 100644 index 000000000..da6a8de1d --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3192Test.php @@ -0,0 +1,168 @@ +fail( + 'Type ddc3192_currency_code exists for testing DDC-3192 only, ' . + 'but it has already been registered for some reason' + ); + } + + Type::addType('ddc3192_currency_code', __NAMESPACE__ . '\DDC3192CurrencyCode'); + + $this->_schemaTool->createSchema(array( + $this->_em->getClassMetadata(DDC3192Currency::CLASSNAME), + $this->_em->getClassMetadata(DDC3192Transaction::CLASSNAME), + )); + } + + public function testIssue() + { + $currency = new DDC3192Currency('BYR'); + + $this->_em->persist($currency); + $this->_em->flush(); + + $amount = 50; + $transaction = new DDC3192Transaction($amount, $currency); + + $this->_em->persist($transaction); + $this->_em->flush(); + $this->_em->close(); + + $resultByPersister = $this->_em->find(DDC3192Transaction::CLASSNAME, $transaction->id); + + // This works: DDC2494 makes persister set type mapping info to ResultSetMapping + $this->assertEquals('BYR', $resultByPersister->currency->code); + + $this->_em->close(); + + $query = $this->_em->createQuery(); + $query->setDQL('SELECT t FROM ' . DDC3192Transaction::CLASSNAME . ' t WHERE t.id = ?1'); + $query->setParameter(1, $transaction->id); + + $resultByQuery = $query->getSingleResult(); + + // This is fixed here: before the fix it used to return 974. + // because unlike the BasicEntityPersister, SQLWalker doesn't set type info + $this->assertEquals('BYR', $resultByQuery->currency->code); + } +} + +/** + * @Table(name="ddc3192_currency") + * @Entity + */ +class DDC3192Currency +{ + const CLASSNAME = __CLASS__; + + /** + * @Id + * @Column(type="ddc3192_currency_code") + */ + public $code; + + /** + * @var \Doctrine\Common\Collections\Collection + * + * @OneToMany(targetEntity="DDC3192Transaction", mappedBy="currency") + */ + public $transactions; + + public function __construct($code) + { + $this->code = $code; + } +} + +/** + * @Table(name="ddc3192_transaction") + * @Entity + */ +class DDC3192Transaction +{ + const CLASSNAME = __CLASS__; + + /** + * @Id + * @GeneratedValue + * @Column(type="integer") + */ + public $id; + + /** + * @var int + * + * @Column(type="integer") + */ + public $amount; + + /** + * @var \Doctrine\Tests\ORM\Functional\Ticket\DDC3192Currency + * + * @ManyToOne(targetEntity="DDC3192Currency", inversedBy="transactions") + * @JoinColumn(name="currency_id", referencedColumnName="code", nullable=false) + */ + public $currency; + + public function __construct($amount, DDC3192Currency $currency) + { + $this->amount = $amount; + $this->currency = $currency; + } +} + +class DDC3192CurrencyCode extends Type +{ + private static $map = array( + 'BYR' => 974, + ); + + /** + * {@inheritdoc} + */ + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) + { + return $platform->getSmallIntTypeDeclarationSQL($fieldDeclaration); + } + + /** + * {@inheritdoc} + */ + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + return self::$map[$value]; + } + + /** + * {@inheritdoc} + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + return array_search($value, self::$map); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'ddc3192_currency_code'; + } +}