Commit 561236bd authored by Roman S. Borschel's avatar Roman S. Borschel

[DDC-576] Fixed.

parent 20c6259f
<?php <?php
/* /*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
......
<?php <?php
/* /*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
...@@ -21,17 +19,17 @@ ...@@ -21,17 +19,17 @@
namespace Doctrine\DBAL\Driver\PDOMsSql; namespace Doctrine\DBAL\Driver\PDOMsSql;
use PDO, Doctrine\DBAL\Driver\Connection as DriverConnection;
/** /**
* MsSql Connection implementation. * MsSql Connection implementation.
* *
* @since 2.0 * @since 2.0
*/ */
class Connection extends \PDO implements \Doctrine\DBAL\Driver\Connection class Connection extends PDO implements DriverConnection
{ {
/** /**
* Performs the rollback. * {@inheritdoc}
*
* @override
*/ */
public function rollback() public function rollback()
{ {
...@@ -39,9 +37,7 @@ class Connection extends \PDO implements \Doctrine\DBAL\Driver\Connection ...@@ -39,9 +37,7 @@ class Connection extends \PDO implements \Doctrine\DBAL\Driver\Connection
} }
/** /**
* Performs the commit. * {@inheritdoc}
*
* @override
*/ */
public function commit() public function commit()
{ {
...@@ -49,12 +45,21 @@ class Connection extends \PDO implements \Doctrine\DBAL\Driver\Connection ...@@ -49,12 +45,21 @@ class Connection extends \PDO implements \Doctrine\DBAL\Driver\Connection
} }
/** /**
* Begins a database transaction. * {@inheritdoc}
*
* @override
*/ */
public function beginTransaction() public function beginTransaction()
{ {
$this->exec('BEGIN TRANSACTION'); $this->exec('BEGIN TRANSACTION');
} }
/**
* {@inheritdoc}
*/
public function lastInsertId($name = null)
{
$stmt = $this->query('SELECT SCOPE_IDENTITY()');
$id = $stmt->fetchColumn();
$stmt->closeCursor();
return $id;
}
} }
\ No newline at end of file
...@@ -21,23 +21,36 @@ namespace Doctrine\ORM\Id; ...@@ -21,23 +21,36 @@ namespace Doctrine\ORM\Id;
use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManager;
/**
* Id generator that obtains IDs from special "identity" columns. These are columns
* that automatically get a database-generated, auto-incremented identifier on INSERT.
* This generator obtains the last insert id after such an insert.
*/
class IdentityGenerator extends AbstractIdGenerator class IdentityGenerator extends AbstractIdGenerator
{ {
/** @var string The name of the sequence to pass to lastInsertId(), if any. */
private $_seqName;
/**
* @param string $seqName The name of the sequence to pass to lastInsertId()
* to obtain the last generated identifier within the current
* database session/connection, if any.
*/
public function __construct($seqName = null)
{
$this->_seqName = $seqName;
}
/** /**
* Generates an ID for the given entity. * {@inheritdoc}
*
* @param object $entity
* @return integer|float
* @override
*/ */
public function generate(EntityManager $em, $entity) public function generate(EntityManager $em, $entity)
{ {
return $em->getConnection()->lastInsertId(); return $em->getConnection()->lastInsertId($this->_seqName);
} }
/** /**
* @return boolean * {@inheritdoc}
* @override
*/ */
public function isPostInsertGenerator() public function isPostInsertGenerator()
{ {
......
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Id;
use Doctrine\ORM\EntityManager;
class SequenceIdentityGenerator extends IdentityGenerator
{
private $_sequenceName;
public function __construct($sequenceName)
{
$this->_sequenceName = $sequenceName;
}
public function generate(EntityManager $em, $entity)
{
return $em->getConnection()->lastInsertId($this->_sequenceName);
}
/**
* @return boolean
* @override
*/
public function isPostInsertGenerator()
{
return true;
}
}
\ No newline at end of file
...@@ -19,8 +19,10 @@ ...@@ -19,8 +19,10 @@
namespace Doctrine\ORM\Mapping; namespace Doctrine\ORM\Mapping;
use Doctrine\ORM\ORMException, use ReflectionException,
Doctrine\DBAL\Platforms\AbstractPlatform, Doctrine\ORM\ORMException,
Doctrine\ORM\EntityManager,
Doctrine\DBAL\Platforms,
Doctrine\ORM\Events; Doctrine\ORM\Events;
/** /**
...@@ -53,7 +55,7 @@ class ClassMetadataFactory ...@@ -53,7 +55,7 @@ class ClassMetadataFactory
* *
* @param $driver The metadata driver to use. * @param $driver The metadata driver to use.
*/ */
public function __construct(\Doctrine\ORM\EntityManager $em) public function __construct(EntityManager $em)
{ {
$this->_em = $em; $this->_em = $em;
} }
...@@ -94,15 +96,15 @@ class ClassMetadataFactory ...@@ -94,15 +96,15 @@ class ClassMetadataFactory
if ( ! $this->_initialized) { if ( ! $this->_initialized) {
$this->_initialize(); $this->_initialize();
} }
$metadata = array(); $metadata = array();
foreach ($this->_driver->getAllClassNames() as $className) { foreach ($this->_driver->getAllClassNames() as $className) {
$metadata[] = $this->getMetadataFor($className); $metadata[] = $this->getMetadataFor($className);
} }
return $metadata; return $metadata;
} }
/** /**
* Lazy initialization of this stuff, especially the metadata driver, * Lazy initialization of this stuff, especially the metadata driver,
* since these are not needed at all when a metadata cache is active. * since these are not needed at all when a metadata cache is active.
...@@ -252,7 +254,7 @@ class ClassMetadataFactory ...@@ -252,7 +254,7 @@ class ClassMetadataFactory
// Invoke driver // Invoke driver
try { try {
$this->_driver->loadMetadataForClass($className, $class); $this->_driver->loadMetadataForClass($className, $class);
} catch(\ReflectionException $e) { } catch(ReflectionException $e) {
throw MappingException::reflectionFailure($className, $e); throw MappingException::reflectionFailure($className, $e);
} }
...@@ -376,7 +378,13 @@ class ClassMetadataFactory ...@@ -376,7 +378,13 @@ class ClassMetadataFactory
// Create & assign an appropriate ID generator instance // Create & assign an appropriate ID generator instance
switch ($class->generatorType) { switch ($class->generatorType) {
case ClassMetadata::GENERATOR_TYPE_IDENTITY: case ClassMetadata::GENERATOR_TYPE_IDENTITY:
$class->setIdGenerator(new \Doctrine\ORM\Id\IdentityGenerator()); // For PostgreSQL IDENTITY (SERIAL) we need a sequence name. It defaults to
// <table>_<column>_seq in PostgreSQL for SERIAL columns.
// Not pretty but necessary and the simplest solution that currently works.
$seqName = $this->_targetPlatform instanceof Platforms\PostgreSQLPlatform ?
$class->table['name'] . '_' . $class->columnNames[$class->identifier[0]] . '_seq' :
null;
$class->setIdGenerator(new \Doctrine\ORM\Id\IdentityGenerator($seqName));
break; break;
case ClassMetadata::GENERATOR_TYPE_SEQUENCE: case ClassMetadata::GENERATOR_TYPE_SEQUENCE:
// If there is no sequence definition yet, create a default definition // If there is no sequence definition yet, create a default definition
......
...@@ -317,7 +317,7 @@ class ClassMetadataInfo ...@@ -317,7 +317,7 @@ class ClassMetadataInfo
* READ-ONLY: The ID generator used for generating IDs for this class. * READ-ONLY: The ID generator used for generating IDs for this class.
* *
* @var AbstractIdGenerator * @var AbstractIdGenerator
* @todo Remove * @todo Remove!
*/ */
public $idGenerator; public $idGenerator;
...@@ -335,6 +335,7 @@ class ClassMetadataInfo ...@@ -335,6 +335,7 @@ class ClassMetadataInfo
* </code> * </code>
* *
* @var array * @var array
* @todo Merge with tableGeneratorDefinition into generic generatorDefinition
*/ */
public $sequenceGeneratorDefinition; public $sequenceGeneratorDefinition;
...@@ -343,6 +344,7 @@ class ClassMetadataInfo ...@@ -343,6 +344,7 @@ class ClassMetadataInfo
* TABLE generation strategy. * TABLE generation strategy.
* *
* @var array * @var array
* @todo Merge with tableGeneratorDefinition into generic generatorDefinition
*/ */
public $tableGeneratorDefinition; public $tableGeneratorDefinition;
......
<?php
namespace Doctrine\Tests\ORM\Functional;
use Doctrine\ORM\Event\PreUpdateEventArgs;
require_once __DIR__ . '/../../TestInit.php';
class PostgreSQLIdentityStrategyTest extends \Doctrine\Tests\OrmFunctionalTestCase
{
protected function setUp() {
parent::setUp();
if ($this->_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.
}
}
}
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;}
}
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