From 96ef7eca13a35051a7a51ebaac574f83322b9eef Mon Sep 17 00:00:00 2001 From: romanb Date: Thu, 14 May 2009 18:34:12 +0000 Subject: [PATCH] [2.0] More small internal perf. improvements. --- .../Internal/Hydration/AbstractHydrator.php | 40 +++--- .../ORM/Internal/Hydration/ArrayHydrator.php | 16 +-- .../ORM/Internal/Hydration/ObjectHydrator.php | 114 ++++++++++-------- .../Hydration/SingleScalarHydrator.php | 23 +++- .../ORM/Mapping/AssociationMapping.php | 98 +++++++-------- lib/Doctrine/ORM/Mapping/ClassMetadata.php | 2 - .../ORM/Mapping/ManyToManyMapping.php | 40 +++--- lib/Doctrine/ORM/Mapping/OneToManyMapping.php | 14 ++- lib/Doctrine/ORM/Mapping/OneToOneMapping.php | 46 ++++--- .../Persisters/AbstractEntityPersister.php | 18 ++- lib/Doctrine/ORM/Query/ResultSetMapping.php | 91 +++++++++++++- .../Performance/HydrationPerformanceTest.php | 6 +- 12 files changed, 319 insertions(+), 189 deletions(-) diff --git a/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php b/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php index d9b1e201c..beec52fab 100644 --- a/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php +++ b/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php @@ -39,7 +39,7 @@ use \PDO; abstract class AbstractHydrator { /** The ResultSetMapping. */ - protected $_resultSetMapping; + protected $_rsm; /** @var EntityManager The EntityManager instance. */ protected $_em; @@ -74,7 +74,7 @@ abstract class AbstractHydrator public function iterate($stmt, $resultSetMapping) { $this->_stmt = $stmt; - $this->_resultSetMapping = $resultSetMapping; + $this->_rsm = $resultSetMapping; $this->_prepare(); return new IterableResult($this); } @@ -89,7 +89,7 @@ abstract class AbstractHydrator public function hydrateAll($stmt, $resultSetMapping) { $this->_stmt = $stmt; - $this->_resultSetMapping = $resultSetMapping; + $this->_rsm = $resultSetMapping; $this->_prepare(); $result = $this->_hydrateAll(); $this->_cleanup(); @@ -127,7 +127,7 @@ abstract class AbstractHydrator */ protected function _cleanup() { - $this->_resultSetMapping = null; + $this->_rsm = null; $this->_stmt->closeCursor(); $this->_stmt = null; } @@ -174,26 +174,26 @@ abstract class AbstractHydrator foreach ($data as $key => $value) { // Parse each column name only once. Cache the results. if ( ! isset($cache[$key])) { - if (isset($this->_resultSetMapping->ignoredColumns[$key])) { + if (isset($this->_rsm->ignoredColumns[$key])) { $cache[$key] = false; - } else if (isset($this->_resultSetMapping->scalarMappings[$key])) { - $cache[$key]['fieldName'] = $this->_resultSetMapping->getScalarAlias($key); + } else if (isset($this->_rsm->scalarMappings[$key])) { + $cache[$key]['fieldName'] = $this->_rsm->getScalarAlias($key); $cache[$key]['isScalar'] = true; - } else if (isset($this->_resultSetMapping->fieldMappings[$key])) { - $classMetadata = $this->_resultSetMapping->getOwningClass($key); - $fieldName = $this->_resultSetMapping->fieldMappings[$key]; + } else if (isset($this->_rsm->fieldMappings[$key])) { + $classMetadata = $this->_rsm->getOwningClass($key); + $fieldName = $this->_rsm->fieldMappings[$key]; $classMetadata = $this->_lookupDeclaringClass($classMetadata, $fieldName); $cache[$key]['fieldName'] = $fieldName; $cache[$key]['isScalar'] = false; $cache[$key]['type'] = Type::getType($classMetadata->getTypeOfField($fieldName)); $cache[$key]['isIdentifier'] = $classMetadata->isIdentifier($fieldName); - $cache[$key]['dqlAlias'] = $this->_resultSetMapping->columnOwnerMap[$key]; + $cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key]; } else { // Discriminator column $cache[$key]['isDiscriminator'] = true; $cache[$key]['isScalar'] = false; $cache[$key]['fieldName'] = $key; - $cache[$key]['dqlAlias'] = $this->_resultSetMapping->columnOwnerMap[$key]; + $cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key]; } } @@ -245,20 +245,20 @@ abstract class AbstractHydrator foreach ($data as $key => $value) { // Parse each column name only once. Cache the results. if ( ! isset($cache[$key])) { - if (isset($this->_resultSetMapping->ignoredColumns[$key])) { + if (isset($this->_rsm->ignoredColumns[$key])) { $cache[$key] = false; continue; - } else if (isset($this->_resultSetMapping->scalarMappings[$key])) { - $cache[$key]['fieldName'] = $this->_resultSetMapping->scalarMappings[$key]; + } else if (isset($this->_rsm->scalarMappings[$key])) { + $cache[$key]['fieldName'] = $this->_rsm->scalarMappings[$key]; $cache[$key]['isScalar'] = true; } else { - $classMetadata = $this->_resultSetMapping->getOwningClass($key); - $fieldName = $this->_resultSetMapping->fieldMappings[$key]; + $classMetadata = $this->_rsm->getOwningClass($key); + $fieldName = $this->_rsm->fieldMappings[$key]; $classMetadata = $this->_lookupDeclaringClass($classMetadata, $fieldName); $cache[$key]['fieldName'] = $fieldName; $cache[$key]['isScalar'] = false; $cache[$key]['type'] = Type::getType($classMetadata->getTypeOfField($fieldName)); - $cache[$key]['dqlAlias'] = $this->_resultSetMapping->columnOwnerMap[$key]; + $cache[$key]['dqlAlias'] = $this->_rsm->columnOwnerMap[$key]; } } @@ -283,8 +283,8 @@ abstract class AbstractHydrator */ protected function _getCustomIndexField($alias) { - return isset($this->_resultSetMapping->indexByMap[$alias]) ? - $this->_resultSetMapping->indexByMap[$alias] : null; + return isset($this->_rsm->indexByMap[$alias]) ? + $this->_rsm->indexByMap[$alias] : null; } /** diff --git a/lib/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php b/lib/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php index 16469973a..84830c213 100644 --- a/lib/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php +++ b/lib/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php @@ -40,12 +40,12 @@ class ArrayHydrator extends AbstractHydrator /** @override */ protected function _prepare() { - $this->_isSimpleQuery = $this->_resultSetMapping->getEntityResultCount() <= 1; + $this->_isSimpleQuery = $this->_rsm->getEntityResultCount() <= 1; $this->_identifierMap = array(); $this->_resultPointers = array(); $this->_idTemplate = array(); $this->_resultCounter = 0; - foreach ($this->_resultSetMapping->getAliasMap() as $dqlAlias => $class) { + foreach ($this->_rsm->getAliasMap() as $dqlAlias => $class) { $this->_identifierMap[$dqlAlias] = array(); $this->_resultPointers[$dqlAlias] = array(); $this->_idTemplate[$dqlAlias] = ''; @@ -88,17 +88,17 @@ class ArrayHydrator extends AbstractHydrator foreach ($rowData as $dqlAlias => $data) { $index = false; - if (isset($this->_resultSetMapping->parentAliasMap[$dqlAlias])) { + if (isset($this->_rsm->parentAliasMap[$dqlAlias])) { // It's a joined result - $parent = $this->_resultSetMapping->parentAliasMap[$dqlAlias]; - $relation = $this->_resultSetMapping->relationMap[$dqlAlias]; + $parent = $this->_rsm->parentAliasMap[$dqlAlias]; + $relation = $this->_rsm->relationMap[$dqlAlias]; $relationAlias = $relation->getSourceFieldName(); $path = $parent . '.' . $dqlAlias; // Get a reference to the right element in the result tree. // This element will get the associated element attached. - if ($this->_resultSetMapping->isMixed && isset($this->_rootAliases[$parent])) { + if ($this->_rsm->isMixed && isset($this->_rootAliases[$parent])) { $key = key(reset($this->_resultPointers)); // TODO: Exception if $key === null ? $baseElement =& $this->_resultPointers[$parent][$key]; @@ -155,14 +155,14 @@ class ArrayHydrator extends AbstractHydrator if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) { $element = $rowData[$dqlAlias]; if ($field = $this->_getCustomIndexField($dqlAlias)) { - if ($this->_resultSetMapping->isMixed) { + if ($this->_rsm->isMixed) { $result[] = array($element[$field] => $element); ++$this->_resultCounter; } else { $result[$element[$field]] = $element; } } else { - if ($this->_resultSetMapping->isMixed) { + if ($this->_rsm->isMixed) { $result[] = array($element); ++$this->_resultCounter; } else { diff --git a/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php b/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php index e8561931f..e420f60ef 100644 --- a/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php +++ b/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php @@ -33,55 +33,69 @@ use Doctrine\Common\Collections\Collection; */ class ObjectHydrator extends AbstractHydrator { - /* TODO: Consider unifying _collections and _initializedRelations */ - /** Collections initialized by the hydrator */ - private $_collections = array(); - /** Memory for initialized relations */ - private $_initializedRelations = array(); - + /* + * These two properties maintain their values between hydration runs. + */ private $_classMetadatas = array(); - private $_rootAliases = array(); + private $_discriminatorMap = array(); + + /* + * The following parts are reinitialized on every hydration run. + */ private $_isSimpleQuery = false; private $_allowPartialObjects = false; private $_identifierMap = array(); private $_resultPointers = array(); private $_idTemplate = array(); private $_resultCounter = 0; - private $_discriminatorMap = array(); + private $_rootAliases = array(); private $_fetchedAssociations = array(); + /* TODO: Consider unifying _collections and _initializedRelations */ + /** Collections initialized by the hydrator */ + private $_collections = array(); + /** Memory for initialized relations */ + private $_initializedRelations = array(); /** @override */ protected function _prepare() { - $this->_isSimpleQuery = count($this->_resultSetMapping->aliasMap) <= 1; + $this->_isSimpleQuery = count($this->_rsm->aliasMap) <= 1; $this->_allowPartialObjects = $this->_em->getConfiguration()->getAllowPartialObjects(); $this->_identifierMap = array(); $this->_resultPointers = array(); $this->_idTemplate = array(); $this->_resultCounter = 0; - foreach ($this->_resultSetMapping->aliasMap as $dqlAlias => $class) { + $this->_fetchedAssociations = array(); + + foreach ($this->_rsm->aliasMap as $dqlAlias => $class) { $this->_identifierMap[$dqlAlias] = array(); $this->_resultPointers[$dqlAlias] = array(); $this->_idTemplate[$dqlAlias] = ''; - $this->_classMetadatas[$class->name] = $class; - if ($class->isInheritanceTypeSingleTable() || $class->isInheritanceTypeJoined()) { - $this->_discriminatorMap[$class->name][$class->discriminatorValue] = $class->name; - foreach (array_merge($class->parentClasses, $class->subClasses) as $className) { - $otherClass = $this->_em->getClassMetadata($className); - $value = $otherClass->discriminatorValue; - $this->_classMetadatas[$className] = $otherClass; - $this->_discriminatorMap[$class->name][$value] = $className; + + if ( ! isset($this->_classMetadatas[$class->name])) { + $this->_classMetadatas[$class->name] = $class; + // Gather class descriptors and discriminator values of subclasses, if necessary + if ($class->isInheritanceTypeSingleTable() || $class->isInheritanceTypeJoined()) { + $this->_discriminatorMap[$class->name][$class->discriminatorValue] = $class->name; + foreach (array_merge($class->parentClasses, $class->subClasses) as $className) { + $otherClass = $this->_em->getClassMetadata($className); + $value = $otherClass->discriminatorValue; + $this->_classMetadatas[$className] = $otherClass; + $this->_discriminatorMap[$class->name][$value] = $className; + } } } - if (isset($this->_resultSetMapping->relationMap[$dqlAlias])) { - $assoc = $this->_resultSetMapping->relationMap[$dqlAlias]; - $this->_fetchedAssociations[$assoc->getSourceEntityName()][$assoc->getSourceFieldName()] = true; - if ($mappedByField = $assoc->getMappedByFieldName()) { - $this->_fetchedAssociations[$assoc->getTargetEntityName()][$mappedByField] = true; - } else if ($inverseAssoc = $this->_em->getClassMetadata($assoc->getTargetEntityName()) - ->inverseMappings[$assoc->getSourceFieldName()]) { - $this->_fetchedAssociations[$assoc->getTargetEntityName()][ - $inverseAssoc->getSourceFieldName() + + // Remember which classes are "fetch joined" + if (isset($this->_rsm->relationMap[$dqlAlias])) { + $assoc = $this->_rsm->relationMap[$dqlAlias]; + $this->_fetchedAssociations[$assoc->getSourceEntityName()][$assoc->sourceFieldName] = true; + if ($mappedByField = $assoc->mappedByFieldName) { + $this->_fetchedAssociations[$assoc->targetEntityName][$mappedByField] = true; + } else if ($inverseAssoc = $this->_em->getClassMetadata($assoc->targetEntityName) + ->inverseMappings[$assoc->sourceFieldName]) { + $this->_fetchedAssociations[$assoc->targetEntityName][ + $inverseAssoc->sourceFieldName ] = true; } } @@ -97,7 +111,7 @@ class ObjectHydrator extends AbstractHydrator { $s = microtime(true); - if ($this->_resultSetMapping->isMixed) { + if ($this->_rsm->isMixed) { $result = array(); } else { $result = new Collection; @@ -184,7 +198,7 @@ class ObjectHydrator extends AbstractHydrator $classMetadata = $this->_classMetadatas[get_class($entity)]; $relation = $classMetadata->getAssociationMapping($name); - $relatedClass = $this->_em->getClassMetadata($relation->getTargetEntityName()); + $relatedClass = $this->_em->getClassMetadata($relation->targetEntityName); $coll = $this->getCollection($relatedClass); $coll->setOwner($entity, $relation); @@ -226,8 +240,8 @@ class ObjectHydrator extends AbstractHydrator private function getEntity(array $data, $className) { - if (isset($this->_resultSetMapping->discriminatorColumns[$className])) { - $discrColumn = $this->_resultSetMapping->discriminatorColumns[$className]; + if (isset($this->_rsm->discriminatorColumns[$className])) { + $discrColumn = $this->_rsm->discriminatorColumns[$className]; $className = $this->_discriminatorMap[$className][$data[$discrColumn]]; unset($data[$discrColumn]); } @@ -241,15 +255,16 @@ class ObjectHydrator extends AbstractHydrator if ($assoc->isLazilyFetched()) { // Inject proxy $proxy = $this->_em->getProxyGenerator()->getAssociationProxy($entity, $assoc); - $this->_classMetadatas[$className]->setFieldValue($entity, $field, $proxy); + $this->_classMetadatas[$className]->reflFields[$field]->setValue($entity, $proxy); } else { //TODO: Schedule for eager fetching? } } else { // Inject collection $this->_classMetadatas[$className]->reflFields[$field] - ->setValue($entity, new PersistentCollection($this->_em, - $this->_em->getClassMetadata($assoc->getTargetEntityName()) + ->setValue($entity, new PersistentCollection( + $this->_em, + $this->_em->getClassMetadata($assoc->targetEntityName) )); } } @@ -287,16 +302,16 @@ class ObjectHydrator extends AbstractHydrator $this->_uow->setOriginalEntityProperty(spl_object_hash($entity1), $property, $entity2); $relation = $classMetadata1->getAssociationMapping($property); if ($relation->isOneToOne()) { - $targetClass = $this->_classMetadatas[$relation->getTargetEntityName()]; + $targetClass = $this->_classMetadatas[$relation->targetEntityName]; if ($relation->isOwningSide()) { // If there is an inverse mapping on the target class its bidirectional - if ($targetClass->hasInverseAssociationMapping($property)) { - $sourceProp = $targetClass->inverseMappings[$fieldName]->getSourceFieldName(); + if (isset($targetClass->inverseMappings[$property])) { + $sourceProp = $targetClass->inverseMappings[$fieldName]->sourceFieldName; $targetClass->reflFields[$sourceProp]->setValue($entity2, $entity1); } } else { // For sure bidirectional, as there is no inverse side in unidirectional - $targetClass->reflFields[$relation->getMappedByFieldName()]->setValue($entity2, $entity1); + $targetClass->reflFields[$relation->mappedByFieldName]->setValue($entity2, $entity1); } } } @@ -322,18 +337,18 @@ class ObjectHydrator extends AbstractHydrator // Hydrate the entity data found in the current row. foreach ($rowData as $dqlAlias => $data) { $index = false; - $entityName = $this->_resultSetMapping->aliasMap[$dqlAlias]->name; + $entityName = $this->_rsm->aliasMap[$dqlAlias]->name; - if (isset($this->_resultSetMapping->parentAliasMap[$dqlAlias])) { + if (isset($this->_rsm->parentAliasMap[$dqlAlias])) { // It's a joined result - $parent = $this->_resultSetMapping->parentAliasMap[$dqlAlias]; - $relation = $this->_resultSetMapping->relationMap[$dqlAlias]; - $relationAlias = $relation->getSourceFieldName(); + $parent = $this->_rsm->parentAliasMap[$dqlAlias]; + $relation = $this->_rsm->relationMap[$dqlAlias]; + $relationAlias = $relation->sourceFieldName; // Get a reference to the right element in the result tree. // This element will get the associated element attached. - if ($this->_resultSetMapping->isMixed && isset($this->_rootAliases[$parent])) { + if ($this->_rsm->isMixed && isset($this->_rootAliases[$parent])) { $key = key(reset($this->_resultPointers)); // TODO: Exception if $key === null ? $baseElement =& $this->_resultPointers[$parent][$key]; @@ -363,12 +378,11 @@ class ObjectHydrator extends AbstractHydrator // If it's a bi-directional many-to-many, also initialize the reverse collection. if ($relation->isManyToMany()) { if ($relation->isOwningSide()) { - $reverseAssoc = $this->_classMetadatas[$entityName] - ->inverseMappings[$relationAlias]; + $reverseAssoc = $this->_classMetadatas[$entityName]->inverseMappings[$relationAlias]; if ($reverseAssoc) { - $this->initRelatedCollection($element, $reverseAssoc->getSourceFieldName()); + $this->initRelatedCollection($element, $reverseAssoc->sourceFieldName); } - } else if ($mappedByField = $relation->getMappedByFieldName()) { + } else if ($mappedByField = $relation->mappedByFieldName) { $this->initRelatedCollection($element, $mappedByField); } } @@ -421,7 +435,7 @@ class ObjectHydrator extends AbstractHydrator if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) { $element = $this->getEntity($rowData[$dqlAlias], $entityName); if ($field = $this->_getCustomIndexField($dqlAlias)) { - if ($this->_resultSetMapping->isMixed) { + if ($this->_rsm->isMixed) { $result[] = array( $this->_classMetadatas[$entityName] ->reflFields[$field] @@ -434,7 +448,7 @@ class ObjectHydrator extends AbstractHydrator ->getValue($element)); } } else { - if ($this->_resultSetMapping->isMixed) { + if ($this->_rsm->isMixed) { $result[] = array($element); ++$this->_resultCounter; } else { diff --git a/lib/Doctrine/ORM/Internal/Hydration/SingleScalarHydrator.php b/lib/Doctrine/ORM/Internal/Hydration/SingleScalarHydrator.php index 586e00b70..b0e620920 100644 --- a/lib/Doctrine/ORM/Internal/Hydration/SingleScalarHydrator.php +++ b/lib/Doctrine/ORM/Internal/Hydration/SingleScalarHydrator.php @@ -1,7 +1,22 @@ . */ namespace Doctrine\ORM\Internal\Hydration; @@ -11,7 +26,7 @@ use \PDO; /** * Description of SingleScalarHydrator * - * @author robo + * @author Roman Borschel */ class SingleScalarHydrator extends AbstractHydrator { diff --git a/lib/Doctrine/ORM/Mapping/AssociationMapping.php b/lib/Doctrine/ORM/Mapping/AssociationMapping.php index 5e9e64d9a..f6121bf20 100644 --- a/lib/Doctrine/ORM/Mapping/AssociationMapping.php +++ b/lib/Doctrine/ORM/Mapping/AssociationMapping.php @@ -24,6 +24,14 @@ namespace Doctrine\ORM\Mapping; /** * Base class for association mappings. * + * IMPORTANT NOTE: + * + * The fields of this class are only public for 2 reasons: + * 1) To allow fast, internal READ access. + * 2) To drastically reduce the size of a serialized instance (private/protected members + * get the whole class name, namespace inclusive, prepended to every property in + * the serialized representation). + * * @author Roman Borschel * @since 2.0 */ @@ -47,18 +55,18 @@ abstract class AssociationMapping 'merge' ); - protected $_cascades = array(); - protected $_isCascadeDelete; - protected $_isCascadeSave; - protected $_isCascadeRefresh; - protected $_isCascadeMerge; + public $cascades = array(); + public $isCascadeDelete; + public $isCascadeSave; + public $isCascadeRefresh; + public $isCascadeMerge; /** * The fetch mode used for the association. * * @var integer */ - protected $_fetchMode = self::FETCH_MANUAL; + public $fetchMode = self::FETCH_MANUAL; /** * Flag that indicates whether the class that defines this mapping is @@ -66,7 +74,7 @@ abstract class AssociationMapping * * @var boolean */ - protected $_isOwningSide = true; + public $isOwningSide = true; /** * Whether the association is optional (0..X) or not (1..X). @@ -74,14 +82,14 @@ abstract class AssociationMapping * * @var boolean */ - protected $_isOptional = true; + public $isOptional = true; /** * The name of the source Entity (the Entity that defines this mapping). * * @var string */ - protected $_sourceEntityName; + public $sourceEntityName; /** * The name of the target Entity (the Enitity that is the target of the @@ -89,7 +97,7 @@ abstract class AssociationMapping * * @var string */ - protected $_targetEntityName; + public $targetEntityName; /** * Identifies the field on the source class (the class this AssociationMapping @@ -98,7 +106,7 @@ abstract class AssociationMapping * * @var string */ - protected $_sourceFieldName; + public $sourceFieldName; /** * Identifies the field on the owning side that controls the mapping for the @@ -106,14 +114,14 @@ abstract class AssociationMapping * * @var string */ - protected $_mappedByFieldName; + public $mappedByFieldName; /** * The join table definition, if any. * * @var array */ - protected $_joinTable = array(); + public $joinTable = array(); //protected $_joinTableInsertSql; @@ -138,34 +146,38 @@ abstract class AssociationMapping if ( ! isset($mapping['fieldName'])) { throw MappingException::missingFieldName(); } - $this->_sourceFieldName = $mapping['fieldName']; + $this->sourceFieldName = $mapping['fieldName']; if ( ! isset($mapping['sourceEntity'])) { throw MappingException::missingSourceEntity($mapping['fieldName']); } - $this->_sourceEntityName = $mapping['sourceEntity']; + $this->sourceEntityName = $mapping['sourceEntity']; if ( ! isset($mapping['targetEntity'])) { throw MappingException::missingTargetEntity($mapping['fieldName']); } - $this->_targetEntityName = $mapping['targetEntity']; + $this->targetEntityName = $mapping['targetEntity']; // Mandatory and optional attributes for either side if ( ! isset($mapping['mappedBy'])) { // Optional if (isset($mapping['joinTable'])) { - $this->_joinTable = $mapping['joinTable']; + $this->joinTable = $mapping['joinTable']; } } else { - $this->_isOwningSide = false; - $this->_mappedByFieldName = $mapping['mappedBy']; + $this->isOwningSide = false; + $this->mappedByFieldName = $mapping['mappedBy']; } // Optional attributes for both sides - $this->_isOptional = isset($mapping['optional']) ? + $this->isOptional = isset($mapping['optional']) ? (bool)$mapping['optional'] : true; - $this->_cascades = isset($mapping['cascade']) ? + $this->cascades = isset($mapping['cascade']) ? (array)$mapping['cascade'] : array(); + $this->isCascadeDelete = in_array('delete', $this->cascades); + $this->isCascadeSave = in_array('save', $this->cascades); + $this->isCascadeRefresh = in_array('refresh', $this->cascades); + $this->isCascadeMerge = in_array('merge', $this->cascades); } /** @@ -176,10 +188,7 @@ abstract class AssociationMapping */ public function isCascadeDelete() { - if ($this->_isCascadeDelete === null) { - $this->_isCascadeDelete = in_array('delete', $this->_cascades); - } - return $this->_isCascadeDelete; + return $this->isCascadeDelete; } /** @@ -190,10 +199,7 @@ abstract class AssociationMapping */ public function isCascadeSave() { - if ($this->_isCascadeSave === null) { - $this->_isCascadeSave = in_array('save', $this->_cascades); - } - return $this->_isCascadeSave; + return $this->isCascadeSave; } /** @@ -204,10 +210,7 @@ abstract class AssociationMapping */ public function isCascadeRefresh() { - if ($this->_isCascadeRefresh === null) { - $this->_isCascadeRefresh = in_array('refresh', $this->_cascades); - } - return $this->_isCascadeRefresh; + return $this->isCascadeRefresh; } /** @@ -218,10 +221,7 @@ abstract class AssociationMapping */ public function isCascadeMerge() { - if ($this->_isCascadeMerge === null) { - $this->_isCascadeMerge = in_array('merge', $this->_cascades); - } - return $this->_isCascadeMerge; + return $this->isCascadeMerge; } /** @@ -231,7 +231,7 @@ abstract class AssociationMapping */ public function isEagerlyFetched() { - return $this->_fetchMode == self::FETCH_EAGER; + return $this->fetchMode == self::FETCH_EAGER; } /** @@ -241,7 +241,7 @@ abstract class AssociationMapping */ public function isLazilyFetched() { - return $this->_fetchMode == self::FETCH_LAZY; + return $this->fetchMode == self::FETCH_LAZY; } /** @@ -251,7 +251,7 @@ abstract class AssociationMapping */ public function isManuallyFetched() { - return $this->_fetchMode == self::FETCH_MANUAL; + return $this->fetchMode == self::FETCH_MANUAL; } /** @@ -261,7 +261,7 @@ abstract class AssociationMapping */ public function isOwningSide() { - return $this->_isOwningSide; + return $this->isOwningSide; } /** @@ -271,7 +271,7 @@ abstract class AssociationMapping */ public function isInverseSide() { - return ! $this->_isOwningSide; + return ! $this->isOwningSide; } /** @@ -282,7 +282,7 @@ abstract class AssociationMapping */ public function isOptional() { - return $this->_isOptional; + return $this->isOptional; } /** @@ -292,7 +292,7 @@ abstract class AssociationMapping */ public function getSourceEntityName() { - return $this->_sourceEntityName; + return $this->sourceEntityName; } /** @@ -302,7 +302,7 @@ abstract class AssociationMapping */ public function getTargetEntityName() { - return $this->_targetEntityName; + return $this->targetEntityName; } /** @@ -312,7 +312,7 @@ abstract class AssociationMapping */ public function getJoinTable() { - return $this->_joinTable; + return $this->joinTable; } /** @@ -322,7 +322,7 @@ abstract class AssociationMapping */ public function getSourceFieldName() { - return $this->_sourceFieldName; + return $this->sourceFieldName; } /** @@ -334,7 +334,7 @@ abstract class AssociationMapping */ public function getMappedByFieldName() { - return $this->_mappedByFieldName; + return $this->mappedByFieldName; } /** @@ -374,7 +374,7 @@ abstract class AssociationMapping */ public function usesJoinTable() { - return (bool)$this->_joinTable; + return (bool)$this->joinTable; } /** diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadata.php b/lib/Doctrine/ORM/Mapping/ClassMetadata.php index b1d30a5b7..08e8d56bb 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadata.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadata.php @@ -36,8 +36,6 @@ use Doctrine\Common\DoctrineException; * get the whole class name, namespace inclusive, prepended to every property in * the serialized representation). * - * !! Do NOT write/modify the public properties directly. Go through the public API. !! - * * @author Roman Borschel * @since 2.0 */ diff --git a/lib/Doctrine/ORM/Mapping/ManyToManyMapping.php b/lib/Doctrine/ORM/Mapping/ManyToManyMapping.php index f1df8ae41..83e030ba7 100644 --- a/lib/Doctrine/ORM/Mapping/ManyToManyMapping.php +++ b/lib/Doctrine/ORM/Mapping/ManyToManyMapping.php @@ -25,6 +25,14 @@ namespace Doctrine\ORM\Mapping; * A many-to-many mapping describes the mapping between two collections of * entities. * + * IMPORTANT NOTE: + * + * The fields of this class are only public for 2 reasons: + * 1) To allow fast, internal READ access. + * 2) To drastically reduce the size of a serialized instance (private/protected members + * get the whole class name, namespace inclusive, prepended to every property in + * the serialized representation). + * * @since 2.0 * @author Roman Borschel */ @@ -33,27 +41,27 @@ class ManyToManyMapping extends AssociationMapping /** * The key columns of the source table. */ - private $_sourceKeyColumns = array(); + public $sourceKeyColumns = array(); /** * The key columns of the target table. */ - private $_targetKeyColumns = array(); + public $targetKeyColumns = array(); /** * Maps the columns in the source table to the columns in the relation table. */ - private $_sourceToRelationKeyColumns = array(); + public $sourceToRelationKeyColumns = array(); /** * Maps the columns in the target table to the columns in the relation table. */ - private $_targetToRelationKeyColumns = array(); + public $targetToRelationKeyColumns = array(); /** * The columns on the join table. */ - private $_joinTableColumns = array(); + public $joinTableColumns = array(); /** * Initializes a new ManyToManyMapping. @@ -85,46 +93,46 @@ class ManyToManyMapping extends AssociationMapping throw MappingException::invalidMapping($this->_sourceFieldName); } foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) { - $this->_sourceToRelationKeyColumns[$joinColumn['referencedColumnName']] = $joinColumn['name']; - $this->_joinTableColumns[] = $joinColumn['name']; + $this->sourceToRelationKeyColumns[$joinColumn['referencedColumnName']] = $joinColumn['name']; + $this->joinTableColumns[] = $joinColumn['name']; } - $this->_sourceKeyColumns = array_keys($this->_sourceToRelationKeyColumns); + $this->sourceKeyColumns = array_keys($this->sourceToRelationKeyColumns); // owning side MUST specify inverseJoinColumns if ( ! isset($mapping['joinTable']['inverseJoinColumns'])) { throw MappingException::invalidMapping($this->_sourceFieldName); } foreach ($mapping['joinTable']['inverseJoinColumns'] as $inverseJoinColumn) { - $this->_targetToRelationKeyColumns[$inverseJoinColumn['referencedColumnName']] = $inverseJoinColumn['name']; - $this->_joinTableColumns[] = $inverseJoinColumn['name']; + $this->targetToRelationKeyColumns[$inverseJoinColumn['referencedColumnName']] = $inverseJoinColumn['name']; + $this->joinTableColumns[] = $inverseJoinColumn['name']; } - $this->_targetKeyColumns = array_keys($this->_targetToRelationKeyColumns); + $this->targetKeyColumns = array_keys($this->targetToRelationKeyColumns); } } public function getJoinTableColumns() { - return $this->_joinTableColumns; + return $this->joinTableColumns; } public function getSourceToRelationKeyColumns() { - return $this->_sourceToRelationKeyColumns; + return $this->sourceToRelationKeyColumns; } public function getTargetToRelationKeyColumns() { - return $this->_targetToRelationKeyColumns; + return $this->targetToRelationKeyColumns; } public function getSourceKeyColumns() { - return $this->_sourceKeyColumns; + return $this->sourceKeyColumns; } public function getTargetKeyColumns() { - return $this->_targetKeyColumns; + return $this->targetKeyColumns; } public function lazyLoadFor($entity, $entityManager) diff --git a/lib/Doctrine/ORM/Mapping/OneToManyMapping.php b/lib/Doctrine/ORM/Mapping/OneToManyMapping.php index 6d8c30a0c..47a960db0 100644 --- a/lib/Doctrine/ORM/Mapping/OneToManyMapping.php +++ b/lib/Doctrine/ORM/Mapping/OneToManyMapping.php @@ -29,6 +29,14 @@ namespace Doctrine\ORM\Mapping; * In other words, the many-side MUST be the owning side and the one-side MUST be * the inverse side. * + * IMPORTANT NOTE: + * + * The fields of this class are only public for 2 reasons: + * 1) To allow fast, internal READ access. + * 2) To drastically reduce the size of a serialized instance (private/protected members + * get the whole class name, namespace inclusive, prepended to every property in + * the serialized representation). + * * @author Roman Borschel * @since 2.0 */ @@ -51,7 +59,7 @@ class OneToManyMapping extends AssociationMapping //protected $_sourceKeysToTargetForeignKeys; /** Whether to delete orphaned elements (removed from the collection) */ - private $_deleteOrphans = false; + public $deleteOrphans = false; /** * Initializes a new OneToManyMapping. @@ -79,7 +87,7 @@ class OneToManyMapping extends AssociationMapping throw MappingException::oneToManyRequiresMappedBy($mapping['fieldName']); } - $this->_deleteOrphans = isset($mapping['deleteOrphans']) ? + $this->deleteOrphans = isset($mapping['deleteOrphans']) ? (bool)$mapping['deleteOrphans'] : false; } @@ -90,7 +98,7 @@ class OneToManyMapping extends AssociationMapping */ public function shouldDeleteOrphans() { - return $this->_deleteOrphans; + return $this->deleteOrphans; } /** diff --git a/lib/Doctrine/ORM/Mapping/OneToOneMapping.php b/lib/Doctrine/ORM/Mapping/OneToOneMapping.php index 7abd4b415..d69135cbc 100644 --- a/lib/Doctrine/ORM/Mapping/OneToOneMapping.php +++ b/lib/Doctrine/ORM/Mapping/OneToOneMapping.php @@ -25,6 +25,14 @@ namespace Doctrine\ORM\Mapping; * A one-to-one mapping describes a uni-directional mapping from one entity * to another entity. * + * IMPORTANT NOTE: + * + * The fields of this class are only public for 2 reasons: + * 1) To allow fast, internal READ access. + * 2) To drastically reduce the size of a serialized instance (private/protected members + * get the whole class name, namespace inclusive, prepended to every property in + * the serialized representation). + * * @since 2.0 * @author Roman Borschel */ @@ -35,28 +43,28 @@ class OneToOneMapping extends AssociationMapping * i.e. source.id (pk) => target.user_id (fk). * Reverse mapping of _targetToSourceKeyColumns. */ - private $_sourceToTargetKeyColumns = array(); + public $sourceToTargetKeyColumns = array(); /** * Maps the target primary/foreign key columns to the source foreign/primary key columns. * i.e. target.user_id (fk) => source.id (pk). * Reverse mapping of _sourceToTargetKeyColumns. */ - private $_targetToSourceKeyColumns = array(); + public $targetToSourceKeyColumns = array(); /** * Whether to delete orphaned elements (when nulled out, i.e. $foo->other = null) * * @var boolean */ - private $_deleteOrphans = false; + public $deleteOrphans = false; /** * The join column definitions. * * @var array */ - private $_joinColumns = array(); + public $joinColumns = array(); /** * Creates a new OneToOneMapping. @@ -83,14 +91,14 @@ class OneToOneMapping extends AssociationMapping if ( ! isset($mapping['joinColumns'])) { throw MappingException::invalidMapping($this->_sourceFieldName); } - $this->_joinColumns = $mapping['joinColumns']; + $this->joinColumns = $mapping['joinColumns']; foreach ($mapping['joinColumns'] as $joinColumn) { - $this->_sourceToTargetKeyColumns[$joinColumn['name']] = $joinColumn['referencedColumnName']; + $this->sourceToTargetKeyColumns[$joinColumn['name']] = $joinColumn['referencedColumnName']; } - $this->_targetToSourceKeyColumns = array_flip($this->_sourceToTargetKeyColumns); + $this->targetToSourceKeyColumns = array_flip($this->sourceToTargetKeyColumns); } - $this->_deleteOrphans = isset($mapping['deleteOrphans']) ? + $this->deleteOrphans = isset($mapping['deleteOrphans']) ? (bool)$mapping['deleteOrphans'] : false; return $mapping; @@ -103,7 +111,7 @@ class OneToOneMapping extends AssociationMapping */ public function getJoinColumns() { - return $this->_joinColumns; + return $this->joinColumns; } /** @@ -113,7 +121,7 @@ class OneToOneMapping extends AssociationMapping */ public function getSourceToTargetKeyColumns() { - return $this->_sourceToTargetKeyColumns; + return $this->sourceToTargetKeyColumns; } /** @@ -123,7 +131,7 @@ class OneToOneMapping extends AssociationMapping */ public function getTargetToSourceKeyColumns() { - return $this->_targetToSourceKeyColumns; + return $this->targetToSourceKeyColumns; } /** @@ -146,31 +154,31 @@ class OneToOneMapping extends AssociationMapping */ public function load($owningEntity, $targetEntity, $em) { - $sourceClass = $em->getClassMetadata($this->_sourceEntityName); - $targetClass = $em->getClassMetadata($this->_targetEntityName); + $sourceClass = $em->getClassMetadata($this->sourceEntityName); + $targetClass = $em->getClassMetadata($this->targetEntityName); $conditions = array(); - if ($this->_isOwningSide) { - foreach ($this->_sourceToTargetKeyColumns as $sourceKeyColumn => $targetKeyColumn) { + if ($this->isOwningSide) { + foreach ($this->sourceToTargetKeyColumns as $sourceKeyColumn => $targetKeyColumn) { $conditions[$targetKeyColumn] = $sourceClass->getReflectionProperty( $sourceClass->getFieldName($sourceKeyColumn))->getValue($owningEntity); } - if ($targetClass->hasInverseAssociation($this->_sourceFieldName)) { + if ($targetClass->hasInverseAssociation($this->sourceFieldName)) { $targetClass->setFieldValue( $targetEntity, $targetClass->inverseMappings[$this->_sourceFieldName]->getSourceFieldName(), $owningEntity); } } else { - $owningAssoc = $em->getClassMetadata($this->_targetEntityName)->getAssociationMapping($this->_mappedByFieldName); + $owningAssoc = $em->getClassMetadata($this->targetEntityName)->getAssociationMapping($this->mappedByFieldName); foreach ($owningAssoc->getTargetToSourceKeyColumns() as $targetKeyColumn => $sourceKeyColumn) { $conditions[$sourceKeyColumn] = $sourceClass->getReflectionProperty( $sourceClass->getFieldName($targetKeyColumn))->getValue($owningEntity); } - $targetClass->setFieldValue($targetEntity, $this->_mappedByFieldName, $owningEntity); + $targetClass->setFieldValue($targetEntity, $this->mappedByFieldName, $owningEntity); } - $em->getUnitOfWork()->getEntityPersister($this->_targetEntityName)->load($conditions, $targetEntity); + $em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->load($conditions, $targetEntity); } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Persisters/AbstractEntityPersister.php b/lib/Doctrine/ORM/Persisters/AbstractEntityPersister.php index fdb6b8f63..813d724a8 100644 --- a/lib/Doctrine/ORM/Persisters/AbstractEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/AbstractEntityPersister.php @@ -272,12 +272,11 @@ abstract class AbstractEntityPersister $entity = $this->_em->getUnitOfWork()->createEntity($this->_entityName, $data); } else { foreach ($data as $field => $value) { - $this->_class->setFieldValue($entity, $field, $value); + $this->_class->reflFields[$field]->setValue($entity, $value); } $id = array(); if ($this->_class->isIdentifierComposite()) { - $identifierFieldNames = $this->_class->identifier; - foreach ($identifierFieldNames as $fieldName) { + foreach ($this->_class->identifier as $fieldName) { $id[] = $data[$fieldName]; } } else { @@ -292,15 +291,15 @@ abstract class AbstractEntityPersister if ($assoc->isLazilyFetched()) { // Inject proxy $proxy = $this->_em->getProxyGenerator()->getAssociationProxy($entity, $assoc); - $this->_class->setFieldValue($entity, $field, $proxy); + $this->_class->reflFields[$field]->setValue($entity, $proxy); } else { //TODO: Eager fetch? } } else { // Inject collection - $this->_class->getReflectionProperty($field) - ->setValue($entity, new PersistentCollection($this->_em, - $this->_em->getClassMetadata($assoc->getTargetEntityName()) + $this->_class->reflFields[$field]->setValue( + $entity, new PersistentCollection($this->_em, + $this->_em->getClassMetadata($assoc->targetEntityName) )); } } @@ -318,8 +317,7 @@ abstract class AbstractEntityPersister protected function _getSelectSingleEntitySql(array $criteria) { $columnList = ''; - $columnNames = $this->_class->getColumnNames(); - foreach ($columnNames as $column) { + foreach ($this->_class->columnNames as $column) { if ($columnList != '') $columnList .= ', '; $columnList .= $column; } @@ -327,7 +325,7 @@ abstract class AbstractEntityPersister $conditionSql = ''; foreach ($criteria as $field => $value) { if ($conditionSql != '') $conditionSql .= ' AND '; - $conditionSql .= $this->_class->getColumnName($field) . ' = ?'; + $conditionSql .= $this->_class->columnNames[$field] . ' = ?'; } return 'SELECT ' . $columnList . ' FROM ' . $this->_class->getTableName() diff --git a/lib/Doctrine/ORM/Query/ResultSetMapping.php b/lib/Doctrine/ORM/Query/ResultSetMapping.php index d1312d306..ffa43a2c1 100644 --- a/lib/Doctrine/ORM/Query/ResultSetMapping.php +++ b/lib/Doctrine/ORM/Query/ResultSetMapping.php @@ -65,38 +65,75 @@ class ResultSetMapping $this->aliasMap[$alias] = $class; } + /** + * + * @param $className + * @param $alias + * @param $discrColumn + */ public function setDiscriminatorColumn($className, $alias, $discrColumn) { $this->discriminatorColumns[$className] = $discrColumn; $this->columnOwnerMap[$discrColumn] = $alias; } + /** + * + * @param string $className + * @return string + */ public function getDiscriminatorColumn($className) { return isset($this->discriminatorColumns[$className]) ? $this->discriminatorColumns[$className] : null; } + /** + * + * @param string $alias + * @param string $fieldName + */ public function addIndexBy($alias, $fieldName) { $this->indexByMap[$alias] = $fieldName; } + /** + * + * @param string $alias + * @return boolean + */ public function hasIndexBy($alias) { return isset($this->indexByMap[$alias]); } + /** + * + * @param string $alias + * @return string + */ public function getIndexByField($alias) { return $this->indexByMap[$alias]; } + /** + * + * @param string $columnName + * @return boolean + */ public function isFieldResult($columnName) { return isset($this->fieldMappings[$columnName]); } + /** + * + * @param $alias + * @param $columnName + * @param $fieldName + */ public function addFieldResult($alias, $columnName, $fieldName) { $this->fieldMappings[$columnName] = $fieldName; @@ -106,6 +143,13 @@ class ResultSetMapping } } + /** + * + * @param $class + * @param $alias + * @param $parentAlias + * @param $relation + */ public function addJoinedEntityResult($class, $alias, $parentAlias, $relation) { $this->aliasMap[$alias] = $class; @@ -164,11 +208,21 @@ class ResultSetMapping return $this->aliasMap[$this->columnOwnerMap[$columnName]]; } + /** + * + * @param string $alias + * @return AssociationMapping + */ public function getRelation($alias) { return $this->relationMap[$alias]; } + /** + * + * @param string $alias + * @return boolean + */ public function isRelation($alias) { return isset($this->relationMap[$alias]); @@ -186,50 +240,77 @@ class ResultSetMapping /** * - * @param $alias - * @return + * @param string $alias + * @return string */ public function getParentAlias($alias) { return $this->parentAliasMap[$alias]; } + /** + * + * @param string $alias + * @return boolean + */ public function hasParentAlias($alias) { return isset($this->parentAliasMap[$alias]); } /** + * Gets the field name for a column name. * - * @param $className - * @param $columnName - * @return + * @param string $columnName + * @return string */ public function getFieldName($columnName) { return $this->fieldMappings[$columnName]; } + /** + * + * @return array + */ public function getAliasMap() { return $this->aliasMap; } + /** + * + * @return integer + */ public function getEntityResultCount() { return count($this->aliasMap); } + /** + * + * @return boolean + */ public function isMixedResult() { return $this->isMixed; } + /** + * Adds a column name that will be ignored during hydration. + * + * @param string $columnName + */ public function addIgnoredColumn($columnName) { $this->ignoredColumns[$columnName] = true; } + /** + * + * @param string $columnName + * @return boolean + */ public function isIgnoredColumn($columnName) { return isset($this->ignoredColumns[$columnName]); diff --git a/tests/Doctrine/Tests/ORM/Performance/HydrationPerformanceTest.php b/tests/Doctrine/Tests/ORM/Performance/HydrationPerformanceTest.php index 8bd60fdcf..7c44efaaa 100644 --- a/tests/Doctrine/Tests/ORM/Performance/HydrationPerformanceTest.php +++ b/tests/Doctrine/Tests/ORM/Performance/HydrationPerformanceTest.php @@ -144,9 +144,9 @@ class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase } /** - * [romanb: 10000 rows => 3.4 seconds] + * [romanb: 10000 rows => 3.8 seconds] * - * MAXIMUM TIME: 4 seconds + * MAXIMUM TIME: 5 seconds */ public function testSimpleQueryObjectHydrationPerformance() { @@ -192,7 +192,7 @@ class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase $stmt = new HydratorMockStatement($resultSet); $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em); - $this->setMaxRunningTime(4); + $this->setMaxRunningTime(5); $result = $hydrator->hydrateAll($stmt, $rsm); }