[2.0][DDC-168] Moved INSERT SQL generation to persisters during runtime.
This commit is contained in:
parent
a4d41d09ef
commit
3d14da4105
@ -36,6 +36,8 @@ use Doctrine\Common\EventManager,
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @todo Remove flush modes. They dont seem to be of much use. Manual flushing should
|
||||
* be enough.
|
||||
*/
|
||||
class EntityManager
|
||||
{
|
||||
|
@ -333,7 +333,7 @@ final class ClassMetadata extends ClassMetadataInfo
|
||||
'idGenerator',
|
||||
'inheritanceType',
|
||||
'inheritedAssociationFields',
|
||||
'insertSql',
|
||||
//'insertSql',
|
||||
'inverseMappings', //TODO: Remove!
|
||||
'isIdentifierComposite',
|
||||
'isMappedSuperclass',
|
||||
|
@ -254,10 +254,6 @@ class ClassMetadataFactory
|
||||
$eventArgs = new \Doctrine\ORM\Event\LoadClassMetadataEventArgs($class);
|
||||
$this->_evm->dispatchEvent(Events::loadClassMetadata, $eventArgs);
|
||||
}
|
||||
|
||||
if ( ! $class->isMappedSuperclass) {
|
||||
$this->_generateStaticSql($class);
|
||||
}
|
||||
|
||||
$this->_loadedMetadata[$className] = $class;
|
||||
|
||||
@ -324,82 +320,6 @@ class ClassMetadataFactory
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates any static SQL strings for a class and stores them in the descriptor.
|
||||
*
|
||||
* @param ClassMetadata $class
|
||||
*/
|
||||
private function _generateStaticSql($class)
|
||||
{
|
||||
if ($versioned = $class->isVersioned) {
|
||||
$versionField = $class->versionField;
|
||||
}
|
||||
|
||||
// Generate INSERT SQL
|
||||
$columns = $values = array();
|
||||
if ($class->inheritanceType == ClassMetadata::INHERITANCE_TYPE_JOINED) {
|
||||
// Generate INSERT SQL for inheritance type JOINED
|
||||
foreach ($class->reflFields as $name => $field) {
|
||||
if (isset($class->fieldMappings[$name]['inherited']) && ! isset($class->fieldMappings[$name]['id'])
|
||||
|| isset($class->inheritedAssociationFields[$name])
|
||||
|| ($versioned && $versionField == $name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($class->associationMappings[$name])) {
|
||||
$assoc = $class->associationMappings[$name];
|
||||
if ($assoc->isOneToOne() && $assoc->isOwningSide) {
|
||||
foreach ($assoc->targetToSourceKeyColumns as $sourceCol) {
|
||||
$columns[] = $assoc->getQuotedJoinColumnName($sourceCol, $this->_targetPlatform);
|
||||
}
|
||||
}
|
||||
} else if ($class->name != $class->rootEntityName || ! $class->isIdGeneratorIdentity() || $class->identifier[0] != $name) {
|
||||
$columns[] = $class->getQuotedColumnName($name, $this->_targetPlatform);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Generate INSERT SQL for inheritance types NONE, SINGLE_TABLE, TABLE_PER_CLASS
|
||||
foreach ($class->reflFields as $name => $field) {
|
||||
if ($versioned && $versionField == $name) {
|
||||
continue;
|
||||
}
|
||||
if (isset($class->associationMappings[$name])) {
|
||||
$assoc = $class->associationMappings[$name];
|
||||
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
|
||||
foreach ($assoc->targetToSourceKeyColumns as $sourceCol) {
|
||||
$columns[] = $assoc->getQuotedJoinColumnName($sourceCol, $this->_targetPlatform);
|
||||
}
|
||||
}
|
||||
} else if ($class->generatorType != ClassMetadata::GENERATOR_TYPE_IDENTITY || $class->identifier[0] != $name) {
|
||||
$columns[] = $class->getQuotedColumnName($name, $this->_targetPlatform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add discriminator column to the INSERT SQL if necessary
|
||||
if (isset($class->discriminatorColumn['name'])) {
|
||||
if ($class->isInheritanceTypeSingleTable() || $class->isInheritanceTypeJoined()
|
||||
&& $class->name == $class->rootEntityName) {
|
||||
$columns[] = $class->getQuotedDiscriminatorColumnName($this->_targetPlatform);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($columns)) {
|
||||
$class->insertSql = $this->_targetPlatform->getEmptyIdentityInsertSql(
|
||||
$class->getQuotedTableName($this->_targetPlatform),
|
||||
$class->getQuotedColumnName($class->identifier[0], $this->_targetPlatform)
|
||||
);
|
||||
} else {
|
||||
$columns = array_unique($columns);
|
||||
$values = array_fill(0, count($columns), '?');
|
||||
|
||||
$class->insertSql = 'INSERT INTO ' .
|
||||
$class->getQuotedTableName($this->_targetPlatform)
|
||||
. ' (' . implode(', ', $columns) . ') '
|
||||
. 'VALUES (' . implode(', ', $values) . ')';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Completes the ID generator mapping. If "auto" is specified we choose the generator
|
||||
* most appropriate for the targeted database platform.
|
||||
|
@ -374,7 +374,7 @@ class ClassMetadataInfo
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $insertSql;
|
||||
//public $insertSql;
|
||||
|
||||
/**
|
||||
* A map of field names to class names, where the field names are association
|
||||
|
@ -60,7 +60,7 @@ class JoinedSubclassPersister extends StandardEntityPersister
|
||||
* This function finds the ClassMetadata instance in a inheritance hierarchy
|
||||
* that is responsible for enabling versioning.
|
||||
*
|
||||
* @return mixed $versionedClass ClassMetadata instance or false if versioning is not enabled
|
||||
* @return mixed ClassMetadata instance or false if versioning is not enabled.
|
||||
*/
|
||||
private function _getVersionedClassMetadata()
|
||||
{
|
||||
@ -90,13 +90,15 @@ class JoinedSubclassPersister extends StandardEntityPersister
|
||||
if (isset($this->_class->associationMappings[$fieldName])) {
|
||||
if (isset($this->_class->inheritedAssociationFields[$fieldName])) {
|
||||
$this->_owningTableMap[$fieldName] = $this->_em->getClassMetadata(
|
||||
$this->_class->inheritedAssociationFields[$fieldName])->primaryTable['name'];
|
||||
$this->_class->inheritedAssociationFields[$fieldName]
|
||||
)->primaryTable['name'];
|
||||
} else {
|
||||
$this->_owningTableMap[$fieldName] = $this->_class->primaryTable['name'];
|
||||
}
|
||||
} else if (isset($this->_class->fieldMappings[$fieldName]['inherited'])) {
|
||||
$this->_owningTableMap[$fieldName] = $this->_em->getClassMetadata(
|
||||
$this->_class->fieldMappings[$fieldName]['inherited'])->primaryTable['name'];
|
||||
$this->_class->fieldMappings[$fieldName]['inherited']
|
||||
)->primaryTable['name'];
|
||||
} else {
|
||||
$this->_owningTableMap[$fieldName] = $this->_class->primaryTable['name'];
|
||||
}
|
||||
@ -122,16 +124,20 @@ class JoinedSubclassPersister extends StandardEntityPersister
|
||||
$postInsertIds = array();
|
||||
$idGen = $this->_class->idGenerator;
|
||||
$isPostInsertId = $idGen->isPostInsertGenerator();
|
||||
$sqlLogger = $this->_conn->getConfiguration()->getSqlLogger();
|
||||
|
||||
// Prepare statements for all tables
|
||||
$stmts = $classes = array();
|
||||
$stmts[$this->_class->primaryTable['name']] = $this->_conn->prepare($this->_class->insertSql);
|
||||
$sql[$this->_class->primaryTable['name']] = $this->_class->insertSql;
|
||||
foreach ($this->_class->parentClasses as $parentClass) {
|
||||
$parentClass = $this->_em->getClassMetadata($parentClass);
|
||||
$sql[$parentClass->primaryTable['name']] = $parentClass->insertSql;
|
||||
$stmts[$parentClass->primaryTable['name']] = $this->_conn->prepare($parentClass->insertSql);
|
||||
$stmts[$this->_class->primaryTable['name']] = $this->_conn->prepare($this->getInsertSql());
|
||||
if ($this->_sqlLogger !== null) {
|
||||
$sql[$this->_class->primaryTable['name']] = $this->getInsertSql();
|
||||
}
|
||||
foreach ($this->_class->parentClasses as $parentClassName) {
|
||||
$parentClass = $this->_em->getClassMetadata($parentClassName);
|
||||
$parentPersister = $this->_em->getUnitOfWork()->getEntityPersister($parentClassName);
|
||||
$stmts[$parentClass->primaryTable['name']] = $this->_conn->prepare($parentPersister->getInsertSql());
|
||||
if ($this->_sqlLogger !== null) {
|
||||
$sql[$parentClass->primaryTable['name']] = $parentPersister->getInsertSql();
|
||||
}
|
||||
}
|
||||
$rootTableName = $this->_em->getClassMetadata($this->_class->rootEntityName)->primaryTable['name'];
|
||||
|
||||
@ -142,13 +148,13 @@ class JoinedSubclassPersister extends StandardEntityPersister
|
||||
// Execute insert on root table
|
||||
$stmt = $stmts[$rootTableName];
|
||||
$paramIndex = 1;
|
||||
if ($sqlLogger) {
|
||||
if ($this->_sqlLogger !== null) {
|
||||
$params = array();
|
||||
foreach ($insertData[$rootTableName] as $columnName => $value) {
|
||||
$params[$paramIndex] = $value;
|
||||
$stmt->bindValue($paramIndex++, $value);
|
||||
}
|
||||
$sqlLogger->logSql($sql[$rootTableName], $params);
|
||||
$this->_sqlLogger->logSql($sql[$rootTableName], $params);
|
||||
} else {
|
||||
foreach ($insertData[$rootTableName] as $columnName => $value) {
|
||||
$stmt->bindValue($paramIndex++, $value);
|
||||
@ -168,7 +174,7 @@ class JoinedSubclassPersister extends StandardEntityPersister
|
||||
foreach ($insertData as $tableName => $data) {
|
||||
$stmt = $stmts[$tableName];
|
||||
$paramIndex = 1;
|
||||
if ($sqlLogger) {
|
||||
if ($this->_sqlLogger !== null) {
|
||||
$params = array();
|
||||
foreach ((array) $id as $idVal) {
|
||||
$params[$paramIndex] = $idVal;
|
||||
@ -178,7 +184,7 @@ class JoinedSubclassPersister extends StandardEntityPersister
|
||||
$params[$paramIndex] = $value;
|
||||
$stmt->bindValue($paramIndex++, $value);
|
||||
}
|
||||
$sqlLogger->logSql($sql[$tableName], $params);
|
||||
$this->_sqlLogger->logSql($sql[$tableName], $params);
|
||||
} else {
|
||||
foreach ((array) $id as $idVal) {
|
||||
$stmt->bindValue($paramIndex++, $idVal);
|
||||
@ -406,4 +412,38 @@ class JoinedSubclassPersister extends StandardEntityPersister
|
||||
{
|
||||
return $this->_processSqlResultInheritanceAware($sqlResult);
|
||||
}
|
||||
|
||||
/** @override */
|
||||
protected function _getInsertColumnList()
|
||||
{
|
||||
// Identifier columns must always come first in the column list of subclasses.
|
||||
$columns = $this->_class->parentClasses ? $this->_class->getIdentifierColumnNames() : array();
|
||||
|
||||
foreach ($this->_class->reflFields as $name => $field) {
|
||||
if (isset($this->_class->fieldMappings[$name]['inherited']) && ! isset($this->_class->fieldMappings[$name]['id'])
|
||||
|| isset($this->_class->inheritedAssociationFields[$name])
|
||||
|| ($this->_class->isVersioned && $this->_class->versionField == $name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($this->_class->associationMappings[$name])) {
|
||||
$assoc = $this->_class->associationMappings[$name];
|
||||
if ($assoc->isOneToOne() && $assoc->isOwningSide) {
|
||||
foreach ($assoc->targetToSourceKeyColumns as $sourceCol) {
|
||||
$columns[] = $assoc->getQuotedJoinColumnName($sourceCol, $this->_platform);
|
||||
}
|
||||
}
|
||||
} else if ($this->_class->name != $this->_class->rootEntityName ||
|
||||
! $this->_class->isIdGeneratorIdentity() || $this->_class->identifier[0] != $name) {
|
||||
$columns[] = $this->_class->getQuotedColumnName($name, $this->_platform);
|
||||
}
|
||||
}
|
||||
|
||||
// Add discriminator column if it is the topmost class.
|
||||
if ($this->_class->name == $this->_class->rootEntityName) {
|
||||
$columns[] = $this->_class->getQuotedDiscriminatorColumnName($this->_platform);
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
}
|
||||
|
@ -91,6 +91,16 @@ class SingleTablePersister extends StandardEntityPersister
|
||||
return $columnList;
|
||||
}
|
||||
|
||||
/** @override */
|
||||
protected function _getInsertColumnList()
|
||||
{
|
||||
$columns = parent::_getInsertColumnList();
|
||||
// Add discriminator column to the INSERT SQL
|
||||
$columns[] = $this->_class->getQuotedDiscriminatorColumnName($this->_platform);
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/** @override */
|
||||
protected function _processSqlResult(array $sqlResult)
|
||||
{
|
||||
|
@ -87,7 +87,20 @@ class StandardEntityPersister
|
||||
*/
|
||||
protected $_queuedInserts = array();
|
||||
|
||||
/**
|
||||
* Mappings of column names as they appear in an SQL result set to
|
||||
* column names as they are defined in the mapping.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_resultColumnNames = array();
|
||||
|
||||
/**
|
||||
* The INSERT SQL statement used for entities handled by this persister.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $_insertSql;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of a class derived from AbstractEntityPersister
|
||||
@ -100,14 +113,15 @@ class StandardEntityPersister
|
||||
public function __construct(EntityManager $em, ClassMetadata $class)
|
||||
{
|
||||
$this->_em = $em;
|
||||
$this->_conn = $em->getConnection();
|
||||
$this->_sqlLogger = $em->getConfiguration()->getSqlLogger();
|
||||
$this->_platform = $this->_conn->getDatabasePlatform();
|
||||
$this->_class = $class;
|
||||
$this->_conn = $em->getConnection();
|
||||
$this->_sqlLogger = $this->_conn->getConfiguration()->getSqlLogger();
|
||||
$this->_platform = $this->_conn->getDatabasePlatform();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an entity to the queued insertions.
|
||||
* The entity remains queued until {@link executeInserts()} is invoked.
|
||||
*
|
||||
* @param object $entity The entitiy to queue for insertion.
|
||||
*/
|
||||
@ -133,24 +147,22 @@ class StandardEntityPersister
|
||||
$idGen = $this->_class->idGenerator;
|
||||
$isPostInsertId = $idGen->isPostInsertGenerator();
|
||||
|
||||
$stmt = $this->_conn->prepare($this->_class->insertSql);
|
||||
$stmt = $this->_conn->prepare($this->getInsertSql());
|
||||
$primaryTableName = $this->_class->primaryTable['name'];
|
||||
|
||||
$sqlLogger = $this->_conn->getConfiguration()->getSqlLogger();
|
||||
|
||||
foreach ($this->_queuedInserts as $entity) {
|
||||
$insertData = array();
|
||||
$this->_prepareData($entity, $insertData, true);
|
||||
|
||||
if (isset($insertData[$primaryTableName])) {
|
||||
$paramIndex = 1;
|
||||
if ($sqlLogger) {
|
||||
if ($this->_sqlLogger !== null) {
|
||||
$params = array();
|
||||
foreach ($insertData[$primaryTableName] as $value) {
|
||||
$params[$paramIndex] = $value;
|
||||
$stmt->bindValue($paramIndex++, $value);
|
||||
}
|
||||
$sqlLogger->logSql($this->_class->insertSql, $params);
|
||||
$this->_sqlLogger->logSql($this->getInsertSql(), $params);
|
||||
} else {
|
||||
foreach ($insertData[$primaryTableName] as $value) {
|
||||
$stmt->bindValue($paramIndex++, $value);
|
||||
@ -787,6 +799,74 @@ class StandardEntityPersister
|
||||
return array($entityName, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the INSERT SQL used by the persister to persist entities.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getInsertSql()
|
||||
{
|
||||
if ($this->_insertSql === null) {
|
||||
$this->_insertSql = $this->_generateInsertSql();
|
||||
}
|
||||
|
||||
return $this->_insertSql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of columns to put in the INSERT SQL statement.
|
||||
*
|
||||
* @return array The list of columns.
|
||||
*/
|
||||
protected function _getInsertColumnList()
|
||||
{
|
||||
$columns = array();
|
||||
foreach ($this->_class->reflFields as $name => $field) {
|
||||
if ($this->_class->isVersioned && $this->_class->versionField == $name) {
|
||||
continue;
|
||||
}
|
||||
if (isset($this->_class->associationMappings[$name])) {
|
||||
$assoc = $this->_class->associationMappings[$name];
|
||||
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
|
||||
foreach ($assoc->targetToSourceKeyColumns as $sourceCol) {
|
||||
$columns[] = $assoc->getQuotedJoinColumnName($sourceCol, $this->_platform);
|
||||
}
|
||||
}
|
||||
} else if ($this->_class->generatorType != ClassMetadata::GENERATOR_TYPE_IDENTITY ||
|
||||
$this->_class->identifier[0] != $name) {
|
||||
$columns[] = $this->_class->getQuotedColumnName($name, $this->_platform);
|
||||
}
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the INSERT SQL used by the persister to persist entities.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _generateInsertSql()
|
||||
{
|
||||
$insertSql = '';
|
||||
$columns = $this->_getInsertColumnList();
|
||||
if (empty($columns)) {
|
||||
$insertSql = $this->_platform->getEmptyIdentityInsertSql(
|
||||
$this->_class->getQuotedTableName($this->_platform),
|
||||
$this->_class->getQuotedColumnName($this->_class->identifier[0], $this->_platform)
|
||||
);
|
||||
} else {
|
||||
$columns = array_unique($columns);
|
||||
$values = array_fill(0, count($columns), '?');
|
||||
|
||||
$insertSql = 'INSERT INTO ' . $this->_class->getQuotedTableName($this->_platform)
|
||||
. ' (' . implode(', ', $columns) . ') '
|
||||
. 'VALUES (' . implode(', ', $values) . ')';
|
||||
}
|
||||
|
||||
return $insertSql;
|
||||
}
|
||||
|
||||
private function _findDeclaringClass($column)
|
||||
{
|
||||
static $cache = array();
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\Tests\Models\Company\CompanyEmployee;
|
||||
|
||||
require_once __DIR__ . '/../../../TestInit.php';
|
||||
|
||||
class DDC168Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
@ -16,13 +18,17 @@ class DDC168Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
*/
|
||||
public function testJoinedSubclassPersisterRequiresSpecificOrderOfMetadataReflFieldsArray()
|
||||
{
|
||||
//$this->_em->getConnection()->getConfiguration()->setSqlLogger(new \Doctrine\DBAL\Logging\EchoSqlLogger);
|
||||
|
||||
$metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\Company\CompanyEmployee');
|
||||
ksort($metadata->reflFields);
|
||||
|
||||
$spouse = new \Doctrine\Tests\Models\Company\CompanyEmployee();
|
||||
$spouse = new CompanyEmployee;
|
||||
$spouse->setName("Blub");
|
||||
$spouse->setDepartment("Accounting");
|
||||
$spouse->setSalary(500);
|
||||
|
||||
$employee = new \Doctrine\Tests\Models\Company\CompanyEmployee();
|
||||
$employee = new CompanyEmployee;
|
||||
$employee->setName("Foo");
|
||||
$employee->setDepartment("bar");
|
||||
$employee->setSalary(1000);
|
||||
@ -39,5 +45,9 @@ class DDC168Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$theEmployee = $q->getSingleResult();
|
||||
|
||||
$this->assertEquals("bar", $theEmployee->getDepartment());
|
||||
$this->assertEquals("Foo", $theEmployee->getName());
|
||||
$this->assertEquals(1000, $theEmployee->getSalary());
|
||||
$this->assertTrue($theEmployee instanceof CompanyEmployee);
|
||||
$this->assertTrue($theEmployee->getSpouse() instanceof CompanyEmployee);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user