From ada2c5c5a7b4fa54046ed6f5ac071dda48383150 Mon Sep 17 00:00:00 2001 From: jwage Date: Sat, 20 Jun 2009 12:59:33 +0000 Subject: [PATCH] [2.0] Work on datetime dbal type and date portability --- .../DBAL/Platforms/AbstractPlatform.php | 43 +++++++++++++++++++ lib/Doctrine/DBAL/Platforms/MockPlatform.php | 18 -------- lib/Doctrine/DBAL/Platforms/MsSqlPlatform.php | 8 ++++ lib/Doctrine/DBAL/Platforms/MySqlPlatform.php | 8 ++++ .../DBAL/Platforms/OraclePlatform.php | 8 ++++ .../DBAL/Platforms/PostgreSqlPlatform.php | 8 ++++ .../DBAL/Platforms/SqlitePlatform.php | 8 +++- lib/Doctrine/DBAL/Types/BooleanType.php | 2 +- lib/Doctrine/DBAL/Types/DateTimeType.php | 12 ++++-- lib/Doctrine/DBAL/Types/DecimalType.php | 2 +- lib/Doctrine/DBAL/Types/IntegerType.php | 2 +- lib/Doctrine/DBAL/Types/SmallIntType.php | 2 +- lib/Doctrine/DBAL/Types/Type.php | 2 +- .../Internal/Hydration/AbstractHydrator.php | 7 +-- .../Persisters/StandardEntityPersister.php | 3 +- .../AST/Functions/CurrentDateFunction.php | 12 ++---- .../AST/Functions/CurrentTimeFunction.php | 3 +- tests/Doctrine/Tests/DBAL/AllTests.php | 2 + .../Tests/DBAL/Mocks/MockPlatform.php | 18 ++++++++ .../Tests/DBAL/Types/DateTimeTest.php | 37 ++++++++++++++++ .../Tests/Models/Generic/DateTimeModel.php | 20 +++++++++ .../ORM/Query/SelectSqlGenerationTest.php | 6 +++ .../Doctrine/Tests/OrmFunctionalTestCase.php | 9 +++- 23 files changed, 196 insertions(+), 44 deletions(-) delete mode 100644 lib/Doctrine/DBAL/Platforms/MockPlatform.php create mode 100644 tests/Doctrine/Tests/DBAL/Mocks/MockPlatform.php create mode 100644 tests/Doctrine/Tests/DBAL/Types/DateTimeTest.php create mode 100644 tests/Doctrine/Tests/Models/Generic/DateTimeModel.php diff --git a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php index 230d99095..627d66655 100644 --- a/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php +++ b/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php @@ -1236,6 +1236,28 @@ abstract class AbstractPlatform return 'SET NAMES ' . $this->quote($charset); } + /** + * Gets the SQL specific for the platform to get the current date. + * + * @return string + */ + public function getCurrentDateSql() + { + return 'CURRENT_DATE'; + } + + /** + * Gets the SQL specific for the platform to get the current time. + * + * @return string + */ + public function getCurrentTimeSql() + { + return 'CURRENT_TIME'; + } + + + /** * Get sql for transaction isolation level Connection constant * @@ -1360,6 +1382,18 @@ abstract class AbstractPlatform throw DoctrineException::updateMe('Get charset field declaration not supported by this platform.'); } + /** + * Obtain DBMS specific SQL to be used to create datetime fields in + * statements like CREATE TABLE + * + * @param array $fieldDeclaration + * @return string + */ + public function getDateTimeTypeDeclarationSql(array $fieldDeclaration) + { + throw DoctrineException::updateMe('Get datetime type declaration not supported by this platform.'); + } + /** * Gets the default transaction isolation level of the platform. * @@ -1461,6 +1495,15 @@ abstract class AbstractPlatform return ""; } + /** + * TODO: We need to get the specific format for each dbms and override this + * function for each platform + */ + public function getDateTimeFormatString() + { + return 'Y-m-d H:i:s'; + } + /** * Gets the SQL snippet used to declare a VARCHAR column type. * diff --git a/lib/Doctrine/DBAL/Platforms/MockPlatform.php b/lib/Doctrine/DBAL/Platforms/MockPlatform.php deleted file mode 100644 index 38e959e7a..000000000 --- a/lib/Doctrine/DBAL/Platforms/MockPlatform.php +++ /dev/null @@ -1,18 +0,0 @@ -_getCommonIntegerTypeDeclarationSql($field); } + /** @override */ + public function getDateTimeTypeDeclarationSql(array $fieldDeclaration) + { + return 'DATETIME'; + } + /** @override */ protected function _getCommonIntegerTypeDeclarationSql(array $columnDef) { $autoinc = ! empty($columnDef['autoincrement']) ? ' AUTOINCREMENT' : ''; $pk = ! empty($columnDef['primary']) && ! empty($autoinc) ? ' PRIMARY KEY' : ''; - return "INTEGER" . $pk . $autoinc; + return 'INTEGER' . $pk . $autoinc; } /** diff --git a/lib/Doctrine/DBAL/Types/BooleanType.php b/lib/Doctrine/DBAL/Types/BooleanType.php index 79df0dae4..ec50c98a3 100644 --- a/lib/Doctrine/DBAL/Types/BooleanType.php +++ b/lib/Doctrine/DBAL/Types/BooleanType.php @@ -24,7 +24,7 @@ class BooleanType extends Type * * @override */ - public function convertToPHPValue($value) + public function convertToPHPValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform) { return (bool) $value; } diff --git a/lib/Doctrine/DBAL/Types/DateTimeType.php b/lib/Doctrine/DBAL/Types/DateTimeType.php index 3ef6a9e33..bd99218c4 100644 --- a/lib/Doctrine/DBAL/Types/DateTimeType.php +++ b/lib/Doctrine/DBAL/Types/DateTimeType.php @@ -9,6 +9,11 @@ namespace Doctrine\DBAL\Types; */ class DateTimeType extends Type { + public function getName() + { + return 'DateTime'; + } + /** * {@inheritdoc} */ @@ -24,8 +29,7 @@ class DateTimeType extends Type */ public function convertToDatabaseValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform) { - //TODO: howto? dbms specific? delegate to platform? - return $value; + return $value->format($platform->getDateTimeFormatString()); } /** @@ -33,8 +37,8 @@ class DateTimeType extends Type * * @override */ - public function convertToObjectValue($value) + public function convertToPHPValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform) { - return new \DateTime($value); + return \DateTime::createFromFormat($platform->getDateTimeFormatString(), $value); } } \ No newline at end of file diff --git a/lib/Doctrine/DBAL/Types/DecimalType.php b/lib/Doctrine/DBAL/Types/DecimalType.php index f5448c42c..868773cc0 100644 --- a/lib/Doctrine/DBAL/Types/DecimalType.php +++ b/lib/Doctrine/DBAL/Types/DecimalType.php @@ -19,7 +19,7 @@ class DecimalType extends Type return $platform->getDecimalTypeDeclarationSql($fieldDeclaration); } - public function convertToPHPValue($value) + public function convertToPHPValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform) { return (double) $value; } diff --git a/lib/Doctrine/DBAL/Types/IntegerType.php b/lib/Doctrine/DBAL/Types/IntegerType.php index 5abd06a8d..7bfd8dd2a 100644 --- a/lib/Doctrine/DBAL/Types/IntegerType.php +++ b/lib/Doctrine/DBAL/Types/IntegerType.php @@ -18,7 +18,7 @@ class IntegerType extends Type return $platform->getIntegerTypeDeclarationSql($fieldDeclaration); } - public function convertToPHPValue($value) + public function convertToPHPValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform) { return (int) $value; } diff --git a/lib/Doctrine/DBAL/Types/SmallIntType.php b/lib/Doctrine/DBAL/Types/SmallIntType.php index 3390bc16f..feebe359c 100644 --- a/lib/Doctrine/DBAL/Types/SmallIntType.php +++ b/lib/Doctrine/DBAL/Types/SmallIntType.php @@ -19,7 +19,7 @@ class SmallIntType return $platform->getSmallIntTypeDeclarationSql($fieldDeclaration); } - public function convertToPHPValue($value) + public function convertToPHPValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform) { return (int) $value; } diff --git a/lib/Doctrine/DBAL/Types/Type.php b/lib/Doctrine/DBAL/Types/Type.php index 0eacc6f13..8c89ca708 100644 --- a/lib/Doctrine/DBAL/Types/Type.php +++ b/lib/Doctrine/DBAL/Types/Type.php @@ -45,7 +45,7 @@ abstract class Type return $value; } - public function convertToPHPValue($value) + public function convertToPHPValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform) { return $value; } diff --git a/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php b/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php index 4127a9626..3c99d3538 100644 --- a/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php +++ b/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php @@ -61,6 +61,7 @@ abstract class AbstractHydrator public function __construct(\Doctrine\ORM\EntityManager $em) { $this->_em = $em; + $this->_platform = $em->getConnection()->getDatabasePlatform(); $this->_uow = $em->getUnitOfWork(); } @@ -213,7 +214,7 @@ abstract class AbstractHydrator $id[$dqlAlias] .= '|' . $value; } - $rowData[$dqlAlias][$cache[$key]['fieldName']] = $cache[$key]['type']->convertToPHPValue($value); + $rowData[$dqlAlias][$cache[$key]['fieldName']] = $cache[$key]['type']->convertToPHPValue($value, $this->_platform); if ( ! isset($nonemptyComponents[$dqlAlias]) && $value !== null) { $nonemptyComponents[$dqlAlias] = true; @@ -221,7 +222,7 @@ abstract class AbstractHydrator /* TODO: Consider this instead of the above 4 lines. */ /*if ($value !== null) { - $rowData[$dqlAlias][$fieldName] = $cache[$key]['type']->convertToPHPValue($value); + $rowData[$dqlAlias][$fieldName] = $cache[$key]['type']->convertToPHPValue($value, $this->_platform); }*/ } @@ -268,7 +269,7 @@ abstract class AbstractHydrator $rowData[/*$dqlAlias . '_' . */$fieldName] = $value; } else { $dqlAlias = $cache[$key]['dqlAlias']; - $rowData[$dqlAlias . '_' . $fieldName] = $cache[$key]['type']->convertToPHPValue($value); + $rowData[$dqlAlias . '_' . $fieldName] = $cache[$key]['type']->convertToPHPValue($value, $this->_platform); } } diff --git a/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php b/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php index 5fd0e85d0..f04aaec2b 100644 --- a/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php @@ -90,6 +90,7 @@ class StandardEntityPersister public function __construct(EntityManager $em, ClassMetadata $class) { $this->_em = $em; + $this->_platform = $em->getConnection()->getDatabasePlatform(); $this->_evm = $em->getEventManager(); $this->_entityName = $class->name; $this->_conn = $em->getConnection(); @@ -343,7 +344,7 @@ class StandardEntityPersister foreach ($stmt->fetch(Connection::FETCH_ASSOC) as $column => $value) { $fieldName = $this->_class->fieldNames[$column]; $data[$fieldName] = Type::getType($this->_class->getTypeOfField($fieldName)) - ->convertToPHPValue($value); + ->convertToPHPValue($value, $this->_platform); } $stmt->closeCursor(); diff --git a/lib/Doctrine/ORM/Query/AST/Functions/CurrentDateFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/CurrentDateFunction.php index 8d75d97a3..ec886e5ec 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/CurrentDateFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/CurrentDateFunction.php @@ -1,8 +1,4 @@ getConnection()->getDatabasePlatform()->getCurrentDateSql(); } /** @@ -29,6 +24,7 @@ class CurrentDateFunction extends FunctionNode { $lexer = $parser->getLexer(); $parser->match($lexer->lookahead['value']); + $parser->match('('); + $parser->match(')'); } -} - +} \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/AST/Functions/CurrentTimeFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/CurrentTimeFunction.php index 1f54d449c..8141f49cd 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/CurrentTimeFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/CurrentTimeFunction.php @@ -18,8 +18,7 @@ class CurrentTimeFunction extends FunctionNode */ public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) { - //TODO: Use platform to get SQL - return 'CURRENT_TIME'; + return $sqlWalker->getConnection()->getDatabasePlatform()->getCurrentTimeSql(); } /** diff --git a/tests/Doctrine/Tests/DBAL/AllTests.php b/tests/Doctrine/Tests/DBAL/AllTests.php index 66a335791..5e5db3d1c 100644 --- a/tests/Doctrine/Tests/DBAL/AllTests.php +++ b/tests/Doctrine/Tests/DBAL/AllTests.php @@ -28,6 +28,8 @@ class AllTests $suite->addTestSuite('Doctrine\Tests\DBAL\Platforms\PostgreSqlPlatformTest'); $suite->addTestSuite('Doctrine\Tests\DBAL\Platforms\MsSqlPlatformTest'); + $suite->addTestSuite('Doctrine\Tests\DBAL\Types\DateTimeTest'); + $suite->addTest(Functional\AllTests::suite()); return $suite; diff --git a/tests/Doctrine/Tests/DBAL/Mocks/MockPlatform.php b/tests/Doctrine/Tests/DBAL/Mocks/MockPlatform.php new file mode 100644 index 000000000..388dc2ba0 --- /dev/null +++ b/tests/Doctrine/Tests/DBAL/Mocks/MockPlatform.php @@ -0,0 +1,18 @@ +_platform = new \Doctrine\Tests\DBAL\Mocks\MockPlatform(); + $this->_type = Type::getType('datetime'); + } + + public function testDateTimeConvertsToDatabaseValue() + { + $this->assertTrue( + is_string($this->_type->convertToDatabaseValue(new \DateTime(), $this->_platform)) + ); + } + + public function testDateTimeConvertsToPHPValue() + { + // Birthday of jwage and also birthday of Doctrine. Send him a present ;) + $this->assertTrue( + $this->_type->convertToPHPValue('1985-09-01 00:00:00', $this->_platform) + instanceof \DateTime + ); + } +} \ No newline at end of file diff --git a/tests/Doctrine/Tests/Models/Generic/DateTimeModel.php b/tests/Doctrine/Tests/Models/Generic/DateTimeModel.php new file mode 100644 index 000000000..68e7992eb --- /dev/null +++ b/tests/Doctrine/Tests/Models/Generic/DateTimeModel.php @@ -0,0 +1,20 @@ +_em->createQuery('SELECT d.id FROM Doctrine\Tests\Models\Generic\DateTimeModel d WHERE d.datetime > current_date()'); + $this->assertEquals('SELECT d0_.id AS id0 FROM date_time_model d0_ WHERE d0_.datetime > CURRENT_DATE', $q->getSql()); + } + /*public function testExistsExpressionInWhereCorrelatedSubqueryAssocCondition() { $this->assertSqlGeneration( diff --git a/tests/Doctrine/Tests/OrmFunctionalTestCase.php b/tests/Doctrine/Tests/OrmFunctionalTestCase.php index b1c1706b6..f20718ecf 100644 --- a/tests/Doctrine/Tests/OrmFunctionalTestCase.php +++ b/tests/Doctrine/Tests/OrmFunctionalTestCase.php @@ -44,7 +44,10 @@ class OrmFunctionalTestCase extends OrmTestCase 'Doctrine\Tests\Models\Company\CompanyEmployee', 'Doctrine\Tests\Models\Company\CompanyManager' ), - 'ecommerce' => array() + 'ecommerce' => array(), + 'generic' => array( + 'Doctrine\Tests\Models\Generic\DateTimeModel' + ) ); protected function useModelSet($setName) @@ -72,7 +75,9 @@ class OrmFunctionalTestCase extends OrmTestCase $conn->exec('DELETE FROM company_employees'); $conn->exec('DELETE FROM company_persons'); } - + if (isset($this->_usedModelSets['generic'])) { + $conn->exec('DELETE FROM date_time_model'); + } $this->_em->clear(); }