From 337857dc8a77b443d9f93f8f74f728eceb96421b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steve=20M=C3=BCller?= Date: Sun, 29 Dec 2013 02:11:47 +0100 Subject: [PATCH] add general IDENTITY generator type support for sequence emulating platforms --- .../ORM/Mapping/ClassMetadataFactory.php | 20 +++-- .../PostgreSQLIdentityStrategyTest.php | 53 ------------ .../SequenceEmulatedIdentityStrategyTest.php | 86 +++++++++++++++++++ 3 files changed, 97 insertions(+), 62 deletions(-) delete mode 100644 tests/Doctrine/Tests/ORM/Functional/PostgreSQLIdentityStrategyTest.php create mode 100644 tests/Doctrine/Tests/ORM/Functional/SequenceEmulatedIdentityStrategyTest.php diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php index dc2a80a0d..3df3f2ea9 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php @@ -448,17 +448,15 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory // Create & assign an appropriate ID generator instance switch ($class->generatorType) { case ClassMetadata::GENERATOR_TYPE_IDENTITY: - // For PostgreSQL IDENTITY (SERIAL) we need a sequence name. It defaults to - // __seq in PostgreSQL for SERIAL columns. - // Not pretty but necessary and the simplest solution that currently works. $sequenceName = null; $fieldName = $class->identifier ? $class->getSingleIdentifierFieldName() : null; - if ($this->targetPlatform instanceof Platforms\PostgreSqlPlatform) { - $columnName = $class->getSingleIdentifierColumnName(); - $quoted = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']); - $sequenceName = $class->getTableName() . '_' . $columnName . '_seq'; - $definition = array( + // Platforms that do not have native IDENTITY support need a sequence to emulate this behaviour. + if ($this->targetPlatform->usesSequenceEmulatedIdentityColumns()) { + $columnName = $class->getSingleIdentifierColumnName(); + $quoted = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']); + $sequenceName = $this->targetPlatform->getIdentitySequenceName($class->getTableName(), $columnName); + $definition = array( 'sequenceName' => $this->targetPlatform->fixSchemaElementName($sequenceName) ); @@ -466,7 +464,11 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory $definition['quoted'] = true; } - $sequenceName = $this->em->getConfiguration()->getQuoteStrategy()->getSequenceName($definition, $class, $this->targetPlatform); + $sequenceName = $this + ->em + ->getConfiguration() + ->getQuoteStrategy() + ->getSequenceName($definition, $class, $this->targetPlatform); } $generator = ($fieldName && $class->fieldMappings[$fieldName]['type'] === 'bigint') diff --git a/tests/Doctrine/Tests/ORM/Functional/PostgreSQLIdentityStrategyTest.php b/tests/Doctrine/Tests/ORM/Functional/PostgreSQLIdentityStrategyTest.php deleted file mode 100644 index 4ee7b7c9b..000000000 --- a/tests/Doctrine/Tests/ORM/Functional/PostgreSQLIdentityStrategyTest.php +++ /dev/null @@ -1,53 +0,0 @@ -_em->getConnection()->getDatabasePlatform()->getName() != 'postgresql') { - $this->markTestSkipped('This test is special to the PostgreSQL IDENTITY key generation strategy.'); - } else { - try { - $this->_schemaTool->createSchema(array( - $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\PostgreSQLIdentityEntity'), - )); - } catch (\Exception $e) { - // Swallow all exceptions. We do not test the schema tool here. - } - } - } - - protected function tearDown() { - parent::tearDown(); - // drop sequence manually due to dependency - $this->_em->getConnection()->exec('DROP SEQUENCE postgresqlidentityentity_id_seq CASCADE'); - } - - public function testPreSavePostSaveCallbacksAreInvoked() - { - $entity = new PostgreSQLIdentityEntity(); - $entity->setValue('hello'); - $this->_em->persist($entity); - $this->_em->flush(); - $this->assertTrue(is_numeric($entity->getId())); - $this->assertTrue($entity->getId() > 0); - $this->assertTrue($this->_em->contains($entity)); - } -} - -/** @Entity */ -class PostgreSQLIdentityEntity { - /** @Id @Column(type="integer") @GeneratedValue(strategy="IDENTITY") */ - private $id; - /** @Column(type="string") */ - private $value; - public function getId() {return $this->id;} - public function getValue() {return $this->value;} - public function setValue($value) {$this->value = $value;} -} diff --git a/tests/Doctrine/Tests/ORM/Functional/SequenceEmulatedIdentityStrategyTest.php b/tests/Doctrine/Tests/ORM/Functional/SequenceEmulatedIdentityStrategyTest.php new file mode 100644 index 000000000..adaa2cd21 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/SequenceEmulatedIdentityStrategyTest.php @@ -0,0 +1,86 @@ +_em->getConnection()->getDatabasePlatform()->usesSequenceEmulatedIdentityColumns()) { + $this->markTestSkipped( + 'This test is special to platforms emulating IDENTITY key generation strategy through sequences.' + ); + } else { + try { + $this->_schemaTool->createSchema( + array($this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\SequenceEmulatedIdentityEntity')) + ); + } catch (\Exception $e) { + // Swallow all exceptions. We do not test the schema tool here. + } + } + } + + /** + * {@inheritdoc} + */ + protected function tearDown() + { + parent::tearDown(); + + $connection = $this->_em->getConnection(); + $platform = $connection->getDatabasePlatform(); + + // drop sequence manually due to dependency + $connection->exec( + $platform->getDropSequenceSQL( + new Sequence($platform->getIdentitySequenceName('seq_identity', 'id')) + ) + ); + } + + public function testPreSavePostSaveCallbacksAreInvoked() + { + $entity = new SequenceEmulatedIdentityEntity(); + $entity->setValue('hello'); + $this->_em->persist($entity); + $this->_em->flush(); + $this->assertTrue(is_numeric($entity->getId())); + $this->assertTrue($entity->getId() > 0); + $this->assertTrue($this->_em->contains($entity)); + } +} + +/** @Entity @Table(name="seq_identity") */ +class SequenceEmulatedIdentityEntity +{ + /** @Id @Column(type="integer") @GeneratedValue(strategy="IDENTITY") */ + private $id; + + /** @Column(type="string") */ + private $value; + + public function getId() + { + return $this->id; + } + + public function getValue() + { + return $this->value; + } + + public function setValue($value) + { + $this->value = $value; + } +}