From a3018340578629ba23e5814e761cf24d0eb24826 Mon Sep 17 00:00:00 2001 From: romanb Date: Mon, 20 Jul 2009 15:30:54 +0000 Subject: [PATCH] [2.0] First part of cleanup for changeset 6120. More to follow. --- .../Internal/Hydration/AbstractHydrator.php | 24 ++++++------------- .../ORM/Internal/Hydration/ObjectHydrator.php | 13 ++++------ lib/Doctrine/ORM/Mapping/ClassMetadata.php | 19 +++------------ .../Mapping/Driver/DoctrineAnnotations.php | 2 ++ lib/Doctrine/ORM/Mapping/OneToOneMapping.php | 4 ++++ .../Persisters/StandardEntityPersister.php | 18 ++++++++++---- lib/Doctrine/ORM/Query/ResultSetMapping.php | 19 +++++++++++++++ lib/Doctrine/ORM/Query/SqlWalker.php | 17 +++++++++---- .../StandardEntityPersisterTest.php | 2 ++ .../ORM/Hydration/ObjectHydratorTest.php | 2 +- .../ORM/Mapping/ClassMetadataFactoryTest.php | 1 - .../Tests/ORM/Mapping/ClassMetadataTest.php | 2 +- 12 files changed, 69 insertions(+), 54 deletions(-) diff --git a/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php b/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php index 4afd36beb..358f53994 100644 --- a/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php +++ b/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php @@ -38,8 +38,6 @@ use Doctrine\Common\DoctrineException; */ abstract class AbstractHydrator { - const TYPES_JOINCOLUMN = 'join_column'; - /** The ResultSetMapping. */ protected $_rsm; @@ -186,23 +184,19 @@ abstract class AbstractHydrator } else if (isset($this->_rsm->fieldMappings[$key])) { $classMetadata = $this->_em->getClassMetadata($this->_rsm->getOwningClass($key)); $fieldName = $this->_rsm->fieldMappings[$key]; - if ( ! isset($classMetadata->reflFields[$fieldName]) && ! in_array($fieldName, $classMetadata->joinColumnNames)) { + if ( ! isset($classMetadata->reflFields[$fieldName])) { $classMetadata = $this->_lookupDeclaringClass($classMetadata, $fieldName); } $cache[$key]['fieldName'] = $fieldName; $cache[$key]['isScalar'] = false; - if (isset($classMetadata->fieldMappings[$fieldName])) { - $cache[$key]['type'] = Type::getType($classMetadata->fieldMappings[$fieldName]['type']); - } else { - $cache[$key]['type'] = self::TYPES_JOINCOLUMN; - } + $cache[$key]['type'] = Type::getType($classMetadata->fieldMappings[$fieldName]['type']); $cache[$key]['isIdentifier'] = $classMetadata->isIdentifier($fieldName); $cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key]; } else { - // Discriminator column - $cache[$key]['isDiscriminator'] = true; + // Meta column (has meaning in relational schema only, i.e. foreign keys or discriminator columns). + $cache[$key]['isMetaColumn'] = true; $cache[$key]['isScalar'] = false; - $cache[$key]['fieldName'] = $key; + $cache[$key]['fieldName'] = $this->_rsm->metaMappings[$key]; $cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key]; } } @@ -214,7 +208,7 @@ abstract class AbstractHydrator $dqlAlias = $cache[$key]['dqlAlias']; - if (isset($cache[$key]['isDiscriminator'])) { + if (isset($cache[$key]['isMetaColumn'])) { $rowData[$dqlAlias][$cache[$key]['fieldName']] = $value; continue; } @@ -223,11 +217,7 @@ abstract class AbstractHydrator $id[$dqlAlias] .= '|' . $value; } - if ($cache[$key]['type'] == self::TYPES_JOINCOLUMN) { - $rowData[$dqlAlias][$cache[$key]['fieldName']] = $value; - } else { - $rowData[$dqlAlias][$cache[$key]['fieldName']] = $cache[$key]['type']->convertToPHPValue($value, $this->_platform); - } + $rowData[$dqlAlias][$cache[$key]['fieldName']] = $cache[$key]['type']->convertToPHPValue($value, $this->_platform); if ( ! isset($nonemptyComponents[$dqlAlias]) && $value !== null) { $nonemptyComponents[$dqlAlias] = true; diff --git a/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php b/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php index 3c1bf75d7..da38eb8a8 100644 --- a/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php +++ b/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php @@ -230,25 +230,22 @@ class ObjectHydrator extends AbstractHydrator { $className = $this->_rsm->aliasMap[$dqlAlias]; if (isset($this->_rsm->discriminatorColumns[$dqlAlias])) { - $discrColumn = $this->_rsm->discriminatorColumns[$dqlAlias]; + $discrColumn = $this->_rsm->metaMappings[$this->_rsm->discriminatorColumns[$dqlAlias]]; $className = $this->_discriminatorMap[$className][$data[$discrColumn]]; unset($data[$discrColumn]); } $entity = $this->_uow->createEntity($className, $data); - $joinColumnsValues = array(); - foreach ($this->_ce[$className]->joinColumnNames as $name) { - if (isset($data[$name])) { - $joinColumnsValues[$name] = $data[$name]; - } - } - // Properly initialize any unfetched associations, if partial objects are not allowed. if ( ! $this->_allowPartialObjects) { foreach ($this->_ce[$className]->associationMappings as $field => $assoc) { if ( ! isset($this->_fetchedAssociations[$className][$field])) { if ($assoc->isOneToOne()) { if ($assoc->isLazilyFetched()) { + $joinColumnsValues = array(); + foreach ($assoc->targetToSourceKeyColumns as $srcColumn) { + $joinColumnsValues[$srcColumn] = $data[$assoc->joinColumnFieldNames[$srcColumn]]; + } // Inject proxy $proxy = $this->_em->getProxyFactory()->getAssociationProxy($entity, $assoc, $joinColumnsValues); $this->_ce[$className]->reflFields[$field]->setValue($entity, $proxy); diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadata.php b/lib/Doctrine/ORM/Mapping/ClassMetadata.php index 812414a3d..f90134fac 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadata.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadata.php @@ -254,12 +254,6 @@ final class ClassMetadata */ public $columnNames = array(); - /** - * Array of all column names that does not map to a field. - * Foreign keys are here. - */ - public $joinColumnNames = array(); - /** * Whether to automatically OUTER JOIN subtypes when a basetype is queried. * @@ -499,11 +493,6 @@ final class ClassMetadata $this->reflFields[$propName] = $property; } - public function addJoinColumn($name) - { - $this->joinColumnNames[] = $name; - } - /** * Gets a ReflectionProperty for a specific field of the mapped class. * @@ -1337,11 +1326,6 @@ final class ClassMetadata if (isset($mapping['targetEntity']) && strpos($mapping['targetEntity'], '\\') === false) { $mapping['targetEntity'] = $this->namespace . '\\' . $mapping['targetEntity']; } - if (isset($mapping['joinColumns'])) { - foreach ($mapping['joinColumns'] as $columns) { - $this->addJoinColumn($columns['name']); - } - } return $mapping; } @@ -1582,6 +1566,9 @@ final class ClassMetadata public function setDiscriminatorColumn($columnDef) { $this->discriminatorColumn = $columnDef; + if ( ! isset($columnDef['fieldName'])) { + $this->discriminatorColumn['fieldName'] = $columnDef['name']; + } } /** diff --git a/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php b/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php index 117e6dc2f..9de82de30 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php +++ b/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php @@ -29,6 +29,7 @@ final class Entity extends \Doctrine\Common\Annotations\Annotation { final class InheritanceType extends \Doctrine\Common\Annotations\Annotation {} final class DiscriminatorColumn extends \Doctrine\Common\Annotations\Annotation { public $name; + //public $fieldName; // field name used in non-object hydration (array/scalar) public $type; public $length; } @@ -42,6 +43,7 @@ final class GeneratedValue extends \Doctrine\Common\Annotations\Annotation { final class Version extends \Doctrine\Common\Annotations\Annotation {} final class JoinColumn extends \Doctrine\Common\Annotations\Annotation { public $name; + //public $fieldName; // field name used in non-object hydration (array/scalar) public $referencedColumnName; public $unique = false; public $nullable = true; diff --git a/lib/Doctrine/ORM/Mapping/OneToOneMapping.php b/lib/Doctrine/ORM/Mapping/OneToOneMapping.php index dbfe9e646..02eb7d2d4 100644 --- a/lib/Doctrine/ORM/Mapping/OneToOneMapping.php +++ b/lib/Doctrine/ORM/Mapping/OneToOneMapping.php @@ -67,6 +67,8 @@ class OneToOneMapping extends AssociationMapping */ public $joinColumns = array(); + public $joinColumnFieldNames = array(); + /** * Creates a new OneToOneMapping. * @@ -99,6 +101,8 @@ class OneToOneMapping extends AssociationMapping $this->joinColumns = $mapping['joinColumns']; foreach ($mapping['joinColumns'] as $joinColumn) { $this->sourceToTargetKeyColumns[$joinColumn['name']] = $joinColumn['referencedColumnName']; + $this->joinColumnFieldNames[$joinColumn['name']] = isset($joinColumn['fieldName']) + ? $joinColumn['fieldName'] : $joinColumn['name']; } $this->targetToSourceKeyColumns = array_flip($this->sourceToTargetKeyColumns); } diff --git a/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php b/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php index 5dcc96f40..83390497f 100644 --- a/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php @@ -21,6 +21,7 @@ namespace Doctrine\ORM\Persisters; +use Doctrine\Common\DoctrineException; use Doctrine\DBAL\Connection; use Doctrine\DBAL\Types\Type; use Doctrine\ORM\EntityManager; @@ -477,9 +478,16 @@ class StandardEntityPersister if ($columnList != '') $columnList .= ', '; $columnList .= $this->_conn->quoteIdentifier($column); } - if (!$this->_em->getConfiguration()->getAllowPartialObjects()) { - foreach ($this->_class->joinColumnNames as $column) { - $columnList .= ', ' . $this->_conn->quoteIdentifier($column); + + $joinColumnNames = array(); + if ( ! $this->_em->getConfiguration()->getAllowPartialObjects()) { + foreach ($this->_class->associationMappings as $assoc) { + if ($assoc->isOwningSide && $assoc->isOneToOne()) { + foreach ($assoc->targetToSourceKeyColumns as $srcColumn) { + $joinColumnNames[] = $srcColumn; + $columnList .= ', ' . $this->_conn->quoteIdentifier($srcColumn); + } + } } } @@ -488,10 +496,10 @@ class StandardEntityPersister if ($conditionSql != '') $conditionSql .= ' AND '; if (isset($this->_class->columnNames[$field])) { $columnName = $this->_class->columnNames[$field]; - } else if (in_array($field, $this->_class->joinColumnNames)) { + } else if (in_array($field, $joinColumnNames)) { $columnName = $field; } else { - throw new Exception("Unrecognized field: $field"); + throw DoctrineException::unrecognizedField($field); } $conditionSql .= $this->_conn->quoteIdentifier($columnName) . ' = ?'; } diff --git a/lib/Doctrine/ORM/Query/ResultSetMapping.php b/lib/Doctrine/ORM/Query/ResultSetMapping.php index 4877bb50b..f44d72611 100644 --- a/lib/Doctrine/ORM/Query/ResultSetMapping.php +++ b/lib/Doctrine/ORM/Query/ResultSetMapping.php @@ -45,6 +45,8 @@ class ResultSetMapping public $fieldMappings = array(); /** Maps column names in the result set to the alias to use in the mapped result. */ public $scalarMappings = array(); + /** Maps column names of meta columns (foreign keys, discriminator columns, ...) to field names. */ + public $metaMappings = array(); /** Maps column names in the result set to the alias they belong to. */ public $columnOwnerMap = array(); /** List of columns in the result set that are used as discriminator columns. */ @@ -286,6 +288,10 @@ class ResultSetMapping } /** + * Checks whether this ResultSetMapping defines a mixed result. + * Mixed results can only occur in object and array (graph) hydration. In such a + * case a mixed result means that scalar values are mixed with objects/array in + * the result. * * @return boolean */ @@ -293,6 +299,19 @@ class ResultSetMapping { return $this->isMixed; } + + /** + * + * @param $alias + * @param $columnName + * @param $fieldName + * @return unknown_type + */ + public function addMetaResult($alias, $columnName, $fieldName) + { + $this->metaMappings[$columnName] = $fieldName; + $this->columnOwnerMap[$columnName] = $alias; + } /** * Adds a column name that will be ignored during hydration. diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index 049ad9a74..b53a1ad9d 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -171,6 +171,7 @@ class SqlWalker implements TreeWalker $columnAlias = $this->getSqlColumnAlias($discrColumn['name']); $sql .= ", $tblAlias." . $discrColumn['name'] . ' AS ' . $columnAlias; $this->_rsm->setDiscriminatorColumn($dqlAlias, $columnAlias); + $this->_rsm->addMetaResult($dqlAlias, $columnAlias, $discrColumn['fieldName']); } //} } @@ -470,13 +471,19 @@ class SqlWalker implements TreeWalker $sql .= $sqlTableAlias . '.' . $this->_conn->quoteIdentifier($mapping['columnName']) . ' AS ' . $columnAlias; $this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName); } - if (!$this->_em->getConfiguration()->getAllowPartialObjects()) { - foreach ($class->joinColumnNames as $name) { - $columnAlias = $this->getSqlColumnAlias($name); - $sql .= ', ' . $sqlTableAlias . '.' . $this->_conn->quoteIdentifier($name) . ' AS ' . $columnAlias; - $this->_rsm->addFieldResult($dqlAlias, $columnAlias, $name); + + if ( ! $this->_em->getConfiguration()->getAllowPartialObjects()) { + foreach ($class->associationMappings as $assoc) { + if ($assoc->isOwningSide && $assoc->isOneToOne()) { + foreach ($assoc->targetToSourceKeyColumns as $srcColumn) { + $columnAlias = $this->getSqlColumnAlias($srcColumn); + $sql .= ', ' . $sqlTableAlias . '.' . $this->_conn->quoteIdentifier($srcColumn) . ' AS ' . $columnAlias; + $this->_rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn); + } + } } } + } } diff --git a/tests/Doctrine/Tests/ORM/Functional/StandardEntityPersisterTest.php b/tests/Doctrine/Tests/ORM/Functional/StandardEntityPersisterTest.php index 11ab6c6e5..38efdef38 100644 --- a/tests/Doctrine/Tests/ORM/Functional/StandardEntityPersisterTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/StandardEntityPersisterTest.php @@ -21,6 +21,8 @@ class StandardEntityPersisterTest extends \Doctrine\Tests\OrmFunctionalTestCase } public function testAcceptsForeignKeysAsCriteria() { + $this->_em->getConfiguration()->setAllowPartialObjects(false); + $customer = new ECommerceCustomer(); $customer->setName('John Doe'); $cart = new ECommerceCart(); diff --git a/tests/Doctrine/Tests/ORM/Hydration/ObjectHydratorTest.php b/tests/Doctrine/Tests/ORM/Hydration/ObjectHydratorTest.php index 91ec7c4eb..c06ae69f2 100644 --- a/tests/Doctrine/Tests/ORM/Hydration/ObjectHydratorTest.php +++ b/tests/Doctrine/Tests/ORM/Hydration/ObjectHydratorTest.php @@ -109,7 +109,7 @@ class ObjectHydratorTest extends HydrationTestCase $rsm->addEntityResult('Doctrine\Tests\Models\ECommerce\ECommerceProduct', 'p'); $rsm->addFieldResult('p', 'p__id', 'id'); $rsm->addFieldResult('p', 'p__name', 'name'); - $rsm->addFieldResult('p', 'p__shipping_id', 'shipping_id'); + $rsm->addMetaResult('p', 'p__shipping_id', 'shipping_id'); // Faked result set $resultSet = array( diff --git a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php index 357976976..6d3de5901 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php @@ -60,7 +60,6 @@ class ClassMetadataFactoryTest extends \Doctrine\Tests\OrmTestCase $cm1 = $cmf->getMetadataFor('Doctrine\Tests\ORM\Mapping\TestEntity1'); $this->assertEquals(array(), $cm1->parentClasses); - $this->assertEquals(array('other_id'), $cm1->joinColumnNames); $this->assertTrue($cm1->hasField('name')); $this->assertEquals(ClassMetadata::GENERATOR_TYPE_SEQUENCE, $cm1->generatorType); } diff --git a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php index 32c02f59a..f8835254b 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php @@ -41,7 +41,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase $this->assertEquals(array('One', 'Two', 'Three'), $cm->subClasses); $this->assertEquals(array('UserParent'), $cm->parentClasses); $this->assertEquals('UserRepository', $cm->getCustomRepositoryClass()); - $this->assertEquals(array('name' => 'disc', 'type' => 'integer'), $cm->discriminatorColumn); + $this->assertEquals(array('name' => 'disc', 'type' => 'integer', 'fieldName' => 'disc'), $cm->discriminatorColumn); $this->assertTrue($cm->getAssociationMapping('phonenumbers') instanceof \Doctrine\ORM\Mapping\OneToOneMapping); $this->assertEquals(1, count($cm->associationMappings)); $oneOneMapping = $cm->getAssociationMapping('phonenumbers');