From e36c7b0c2a11f87738186214d2ae7805ac90a951 Mon Sep 17 00:00:00 2001 From: Pavel Batanov Date: Thu, 22 Jan 2015 17:32:03 +0300 Subject: [PATCH 01/22] DDC-3346 failing test example --- .../Tests/Models/DDC3346/DDC3346Article.php | 31 +++++++++ .../Tests/Models/DDC3346/DDC3346Author.php | 32 ++++++++++ .../ORM/Functional/Ticket/DDC3346Test.php | 64 +++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 tests/Doctrine/Tests/Models/DDC3346/DDC3346Article.php create mode 100644 tests/Doctrine/Tests/Models/DDC3346/DDC3346Author.php create mode 100644 tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php diff --git a/tests/Doctrine/Tests/Models/DDC3346/DDC3346Article.php b/tests/Doctrine/Tests/Models/DDC3346/DDC3346Article.php new file mode 100644 index 00000000000..0f57011db2f --- /dev/null +++ b/tests/Doctrine/Tests/Models/DDC3346/DDC3346Article.php @@ -0,0 +1,31 @@ +user = $author; + } +} diff --git a/tests/Doctrine/Tests/Models/DDC3346/DDC3346Author.php b/tests/Doctrine/Tests/Models/DDC3346/DDC3346Author.php new file mode 100644 index 00000000000..8fa87ca5e23 --- /dev/null +++ b/tests/Doctrine/Tests/Models/DDC3346/DDC3346Author.php @@ -0,0 +1,32 @@ +setUpEntitySchema( + array( + 'Doctrine\Tests\Models\DDC3346\DDC3346Article', + 'Doctrine\Tests\Models\DDC3346\DDC3346Author', + ) + ); + } + + public function testFindOneByWithEagerFetch() + { + $user = new DDC3346Author(); + $user->name = "Buggy Woogy"; + $user->username = "bwoogy"; + $user->status = "active"; + + $article1 = new DDC3346Article(); + $article1->text = "First content"; + $article1->setAuthor($user); + + $article2 = new DDC3346Article(); + $article2->text = "Second content"; + $article2->setAuthor($user); + + $this->_em->persist($user); + $this->_em->persist($article1); + $this->_em->persist($article2); + $this->_em->flush(); + $this->_em->close(); + + /** @var DDC3346Author[] $authors */ + $authors = $this->_em->getRepository('Doctrine\Tests\Models\DDC3346\DDC3346Author')->findBy( + array('username' => "bwoogy") + ); + + $this->assertCount(1, $authors); + + $this->assertCount(2, $authors[0]->articles); + + $this->_em->close(); + + /** @var DDC3346Author $author */ + $author = $this->_em->getRepository('Doctrine\Tests\Models\DDC3346\DDC3346Author')->findOneBy( + array('username' => "bwoogy") + ); + + $this->assertCount(2, $author->articles); + } +} From 981cebbf4c5f52939083bb5e858ca04e729265a3 Mon Sep 17 00:00:00 2001 From: Pavel Batanov Date: Thu, 22 Jan 2015 18:31:15 +0300 Subject: [PATCH 02/22] Update test according to @Ocramius notes --- tests/Doctrine/Tests/Models/DDC3346/DDC3346Article.php | 5 +---- tests/Doctrine/Tests/Models/DDC3346/DDC3346Author.php | 9 +-------- .../Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php | 8 ++------ 3 files changed, 4 insertions(+), 18 deletions(-) diff --git a/tests/Doctrine/Tests/Models/DDC3346/DDC3346Article.php b/tests/Doctrine/Tests/Models/DDC3346/DDC3346Article.php index 0f57011db2f..127209dcbbd 100644 --- a/tests/Doctrine/Tests/Models/DDC3346/DDC3346Article.php +++ b/tests/Doctrine/Tests/Models/DDC3346/DDC3346Article.php @@ -8,6 +8,7 @@ */ class DDC3346Article { + const CLASSNAME = 'Doctrine\Tests\Models\DDC3346\DDC3346Article'; /** * @Id * @Column(type="integer") @@ -19,10 +20,6 @@ class DDC3346Article * @JoinColumn(name="user_id", referencedColumnName="id") */ public $user; - /** - * @Column(type="text") - */ - public $text; public function setAuthor(DDC3346Author $author) { diff --git a/tests/Doctrine/Tests/Models/DDC3346/DDC3346Author.php b/tests/Doctrine/Tests/Models/DDC3346/DDC3346Author.php index 8fa87ca5e23..a24d9a601ec 100644 --- a/tests/Doctrine/Tests/Models/DDC3346/DDC3346Author.php +++ b/tests/Doctrine/Tests/Models/DDC3346/DDC3346Author.php @@ -8,23 +8,16 @@ */ class DDC3346Author { + const CLASSNAME = 'Doctrine\Tests\Models\DDC3346\DDC3346Author'; /** * @Id @Column(type="integer") * @GeneratedValue */ public $id; - /** - * @Column(type="string", length=50, nullable=true) - */ - public $status; /** * @Column(type="string", length=255, unique=true) */ public $username; - /** - * @Column(type="string", length=255) - */ - public $name; /** * @OneToMany(targetEntity="DDC3346Article", mappedBy="user", fetch="EAGER", cascade={"detach"}) */ diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php index b858eded75a..e082c1b56a6 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php @@ -16,8 +16,8 @@ public function setUp() $this->setUpEntitySchema( array( - 'Doctrine\Tests\Models\DDC3346\DDC3346Article', - 'Doctrine\Tests\Models\DDC3346\DDC3346Author', + DDC3346Author::CLASSNAME, + DDC3346Article::CLASSNAME, ) ); } @@ -25,16 +25,12 @@ public function setUp() public function testFindOneByWithEagerFetch() { $user = new DDC3346Author(); - $user->name = "Buggy Woogy"; $user->username = "bwoogy"; - $user->status = "active"; $article1 = new DDC3346Article(); - $article1->text = "First content"; $article1->setAuthor($user); $article2 = new DDC3346Article(); - $article2->text = "Second content"; $article2->setAuthor($user); $this->_em->persist($user); From 4c62d3bfda07986889cd4660ad1c3fe0d788793a Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Thu, 22 Jan 2015 17:58:56 +0100 Subject: [PATCH 03/22] #1277 DDC-3346 DDC-3531 - moved resultsetmapping into the newly created `CachedPersisterContext` --- .../AbstractEntityInheritancePersister.php | 4 +- .../Entity/BasicEntityPersister.php | 55 ++++---- .../Entity/CachedPersisterContext.php | 121 ++++++++++++++++++ .../Entity/JoinedSubclassPersister.php | 8 +- .../Entity/SingleTablePersister.php | 4 +- 5 files changed, 158 insertions(+), 34 deletions(-) create mode 100644 lib/Doctrine/ORM/Persisters/Entity/CachedPersisterContext.php diff --git a/lib/Doctrine/ORM/Persisters/Entity/AbstractEntityInheritancePersister.php b/lib/Doctrine/ORM/Persisters/Entity/AbstractEntityInheritancePersister.php index edb39afc634..e8f9801cc9d 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/AbstractEntityInheritancePersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/AbstractEntityInheritancePersister.php @@ -66,7 +66,7 @@ protected function getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r' $sql = $this->getSQLTableAlias($class->name, $tableAlias) . '.' . $this->quoteStrategy->getColumnName($field, $class, $this->platform); - $this->rsm->addFieldResult($alias, $columnAlias, $field, $class->name); + $this->cachedPersisterContexts['noLimits']->rsm->addFieldResult($alias, $columnAlias, $field, $class->name); if (isset($class->fieldMappings[$field]['requireSQLConversion'])) { $type = Type::getType($class->getTypeOfField($field)); @@ -88,7 +88,7 @@ protected function getSelectJoinColumnSQL($tableAlias, $joinColumnName, $classNa { $columnAlias = $this->getSQLColumnAlias($joinColumnName); - $this->rsm->addMetaResult('r', $columnAlias, $joinColumnName, false, $type); + $this->cachedPersisterContexts['noLimits']->rsm->addMetaResult('r', $columnAlias, $joinColumnName, false, $type); return $tableAlias . '.' . $joinColumnName . ' AS ' . $columnAlias; } diff --git a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php index c53e817c151..30382581181 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php @@ -134,15 +134,6 @@ class BasicEntityPersister implements EntityPersister */ protected $queuedInserts = array(); - /** - * ResultSetMapping that is used for all queries. Is generated lazily once per request. - * - * TODO: Evaluate Caching in combination with the other cached SQL snippets. - * - * @var Query\ResultSetMapping - */ - protected $rsm; - /** * The map of column names to DBAL mapping types of all prepared columns used * when INSERTing or UPDATEing an entity. @@ -216,6 +207,11 @@ class BasicEntityPersister implements EntityPersister */ private $identifierFlattener; + /** + * @var CachedPersisterContext[] + */ + protected $cachedPersisterContexts = []; + /** * Initializes a new BasicEntityPersister that uses the given EntityManager * and persists instances of the class described by the given ClassMetadata descriptor. @@ -231,6 +227,10 @@ public function __construct(EntityManagerInterface $em, ClassMetadata $class) $this->platform = $this->conn->getDatabasePlatform(); $this->quoteStrategy = $em->getConfiguration()->getQuoteStrategy(); $this->identifierFlattener = new IdentifierFlattener($em->getUnitOfWork(), $em->getMetadataFactory()); + $this->cachedPersisterContexts['noLimits'] = new CachedPersisterContext( + $class, + new Query\ResultSetMapping() + ); } /** @@ -246,7 +246,7 @@ public function getClassMetadata() */ public function getResultSetMapping() { - return $this->rsm; + return $this->cachedPersisterContexts['noLimits']->rsm; } /** @@ -720,7 +720,7 @@ public function load(array $criteria, $entity = null, $assoc = null, array $hint } $hydrator = $this->em->newHydrator($this->selectJoinSql ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT); - $entities = $hydrator->hydrateAll($stmt, $this->rsm, $hints); + $entities = $hydrator->hydrateAll($stmt, $this->cachedPersisterContexts['noLimits']->rsm, $hints); return $entities ? $entities[0] : null; } @@ -809,7 +809,7 @@ public function refresh(array $id, $entity, $lockMode = null) $stmt = $this->conn->executeQuery($sql, $params, $types); $hydrator = $this->em->newHydrator(Query::HYDRATE_OBJECT); - $hydrator->hydrateAll($stmt, $this->rsm, array(Query::HINT_REFRESH => true)); + $hydrator->hydrateAll($stmt, $this->cachedPersisterContexts['noLimits']->rsm, array(Query::HINT_REFRESH => true)); } /** @@ -841,7 +841,7 @@ public function loadCriteria(Criteria $criteria) $stmt = $this->conn->executeQuery($query, $params, $types); $hydrator = $this->em->newHydrator(($this->selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT); - return $hydrator->hydrateAll($stmt, $this->rsm, array(UnitOfWork::HINT_DEFEREAGERLOAD => true)); + return $hydrator->hydrateAll($stmt, $this->cachedPersisterContexts['noLimits']->rsm, array(UnitOfWork::HINT_DEFEREAGERLOAD => true)); } /** @@ -886,7 +886,7 @@ public function loadAll(array $criteria = array(), array $orderBy = null, $limit $hydrator = $this->em->newHydrator(($this->selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT); - return $hydrator->hydrateAll($stmt, $this->rsm, array(UnitOfWork::HINT_DEFEREAGERLOAD => true)); + return $hydrator->hydrateAll($stmt, $this->cachedPersisterContexts['noLimits']->rsm, array(UnitOfWork::HINT_DEFEREAGERLOAD => true)); } /** @@ -909,11 +909,11 @@ public function getManyToManyCollection(array $assoc, $sourceEntity, $offset = n */ private function loadArrayFromStatement($assoc, $stmt) { - $rsm = $this->rsm; + $rsm = $this->cachedPersisterContexts['noLimits']->rsm; $hints = array(UnitOfWork::HINT_DEFEREAGERLOAD => true); if (isset($assoc['indexBy'])) { - $rsm = clone ($this->rsm); // this is necessary because the "default rsm" should be changed. + $rsm = clone ($this->cachedPersisterContexts['noLimits']->rsm); // this is necessary because the "default rsm" should be changed. $rsm->addIndexBy('r', $assoc['indexBy']); } @@ -931,14 +931,14 @@ private function loadArrayFromStatement($assoc, $stmt) */ private function loadCollectionFromStatement($assoc, $stmt, $coll) { - $rsm = $this->rsm; + $rsm = $this->cachedPersisterContexts['noLimits']->rsm; $hints = array( UnitOfWork::HINT_DEFEREAGERLOAD => true, 'collection' => $coll ); if (isset($assoc['indexBy'])) { - $rsm = clone ($this->rsm); // this is necessary because the "default rsm" should be changed. + $rsm = clone ($this->cachedPersisterContexts['noLimits']->rsm); // this is necessary because the "default rsm" should be changed. $rsm->addIndexBy('r', $assoc['indexBy']); } @@ -1062,7 +1062,7 @@ public function getSelectSQL($criteria, $assoc = null, $lockMode = null, $limit break; } - $columnList = $this->getSelectColumnsSQL(); + $columnList = $this->getSelectColumnsSQL(null !== $limit); $tableAlias = $this->getSQLTableAlias($this->class->name); $filterSql = $this->generateFilterConditionSQL($this->class, $tableAlias); $tableName = $this->quoteStrategy->getTableName($this->class, $this->platform); @@ -1180,17 +1180,19 @@ protected final function getOrderBySQL(array $orderBy, $baseTableAlias) * the resulting SQL fragment is generated only once and cached in {@link selectColumnListSql}. * Subclasses may or may not do the same. * + * @param bool $hasLimitClause + * * @return string The SQL fragment. */ - protected function getSelectColumnsSQL() + protected function getSelectColumnsSQL(/*$hasLimitClause = false*/) { + //if ( ! $hasLimitClause && $this->selectColumnListSql !== null) { if ($this->selectColumnListSql !== null) { return $this->selectColumnListSql; } $columnList = array(); - $this->rsm = new Query\ResultSetMapping(); - $this->rsm->addEntityResult($this->class->name, 'r'); // r for root + $this->cachedPersisterContexts['noLimits']->rsm->addEntityResult($this->class->name, 'r'); // r for root // Add regular columns to select list foreach ($this->class->fieldNames as $field) { @@ -1210,6 +1212,7 @@ protected function getSelectColumnsSQL() $isAssocToOneInverseSide = $assoc['type'] & ClassMetadata::TO_ONE && ! $assoc['isOwningSide']; $isAssocFromOneEager = $assoc['type'] !== ClassMetadata::MANY_TO_MANY && $assoc['fetch'] === ClassMetadata::FETCH_EAGER; + //if ($hasLimitClause || ! ($isAssocFromOneEager || $isAssocToOneInverseSide)) { if ( ! ($isAssocFromOneEager || $isAssocToOneInverseSide)) { continue; } @@ -1221,7 +1224,7 @@ protected function getSelectColumnsSQL() } $assocAlias = 'e' . ($eagerAliasCounter++); - $this->rsm->addJoinedEntityResult($assoc['targetEntity'], $assocAlias, 'r', $assocField); + $this->cachedPersisterContexts['noLimits']->rsm->addJoinedEntityResult($assoc['targetEntity'], $assocAlias, 'r', $assocField); foreach ($eagerEntity->fieldNames as $field) { $columnList[] = $this->getSelectColumnSQL($field, $eagerEntity, $assocAlias); @@ -1241,7 +1244,7 @@ protected function getSelectColumnsSQL() $joinCondition = array(); if (isset($assoc['indexBy'])) { - $this->rsm->addIndexBy($assocAlias, $assoc['indexBy']); + $this->cachedPersisterContexts['noLimits']->rsm->addIndexBy($assocAlias, $assoc['indexBy']); } if ( ! $assoc['isOwningSide']) { @@ -1318,7 +1321,7 @@ protected function getSelectColumnAssociationSQL($field, $assoc, ClassMetadata $ . '.' . $quotedColumn . ' AS ' . $resultColumnName; $type = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $targetClass, $this->em); - $this->rsm->addMetaResult($alias, $resultColumnName, $quotedColumn, $isIdentifier, $type); + $this->cachedPersisterContexts['noLimits']->rsm->addMetaResult($alias, $resultColumnName, $quotedColumn, $isIdentifier, $type); } return implode(', ', $columnList); @@ -1456,7 +1459,7 @@ protected function getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r' $sql = $tableAlias . '.' . $columnName; $columnAlias = $this->getSQLColumnAlias($class->columnNames[$field]); - $this->rsm->addFieldResult($alias, $columnAlias, $field); + $this->cachedPersisterContexts['noLimits']->rsm->addFieldResult($alias, $columnAlias, $field); if (isset($class->fieldMappings[$field]['requireSQLConversion'])) { $type = Type::getType($class->getTypeOfField($field)); diff --git a/lib/Doctrine/ORM/Persisters/Entity/CachedPersisterContext.php b/lib/Doctrine/ORM/Persisters/Entity/CachedPersisterContext.php new file mode 100644 index 00000000000..a148a54dda7 --- /dev/null +++ b/lib/Doctrine/ORM/Persisters/Entity/CachedPersisterContext.php @@ -0,0 +1,121 @@ +. + */ + +namespace Doctrine\ORM\Persisters\Entity; +use Doctrine\Common\Persistence\Mapping\ClassMetadata; +use Doctrine\ORM\Query\ResultSetMapping; + +/** + * A swappable persister context to use as a container for the current + * generated query/resultSetMapping/type binding information. + * + * This class is a utility class to be used only by the persister API + * + * This object is highly mutable due to performance reasons. Same reasoning + * behind its properties being public. + * + * @author Marco Pivetta + */ +class CachedPersisterContext +{ + /** + * Metadata object that describes the mapping of the mapped entity class. + * + * @var \Doctrine\ORM\Mapping\ClassMetadata + */ + public $class; + + /** + * ResultSetMapping that is used for all queries. Is generated lazily once per request. + * + * @var \Doctrine\ORM\Query\ResultSetMapping + */ + public $rsm; + + /** + * The map of column names to DBAL mapping types of all prepared columns used + * when INSERTing or UPDATEing an entity. + * + * @var array + * + * @see \Doctrine\ORM\Persisters\Entity\BasicEntityPersister#prepareInsertData($entity) + * @see \Doctrine\ORM\Persisters\Entity\BasicEntityPersister#prepareUpdateData($entity) + */ + public $columnTypes = array(); + + /** + * The map of quoted column names. + * + * @var array + * + * @see \Doctrine\ORM\Persisters\Entity\BasicEntityPersister#prepareInsertData($entity) + * @see \Doctrine\ORM\Persisters\Entity\BasicEntityPersister#prepareUpdateData($entity) + */ + public $quotedColumns = array(); + + /** + * The INSERT SQL statement used for entities handled by this persister. + * This SQL is only generated once per request, if at all. + * + * @var string + */ + public $insertSql = ''; + + /** + * The SELECT column list SQL fragment used for querying entities by this persister. + * This SQL fragment is only generated once per request, if at all. + * + * @var string + */ + public $selectColumnListSql; + + /** + * The JOIN SQL fragment used to eagerly load all many-to-one and one-to-one + * associations configured as FETCH_EAGER, as well as all inverse one-to-one associations. + * + * @var string + */ + public $selectJoinSql; + + /** + * Counter for creating unique SQL table and column aliases. + * + * @var integer + */ + public $sqlAliasCounter = 0; + + /** + * Map from class names (FQCN) to the corresponding generated SQL table aliases. + * + * @var array + */ + public $sqlTableAliases = array(); + + /** + * @param ClassMetadata $class + * @param ResultSetMapping $rsm + */ + public function __construct( + ClassMetadata $class, + ResultSetMapping $rsm + ) { + $this->class = $class; + $this->rsm = $rsm; + } +} diff --git a/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php b/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php index 019d987d5fb..3ec9afc309f 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php @@ -425,14 +425,14 @@ protected function getSelectColumnsSQL() } $columnList = array(); - $this->rsm = new ResultSetMapping(); + //$this->cachedPersisterContexts['noLimits']->rsm = new ResultSetMapping(); $discrColumn = $this->class->discriminatorColumn['name']; $baseTableAlias = $this->getSQLTableAlias($this->class->name); $resultColumnName = $this->platform->getSQLResultCasing($discrColumn); - $this->rsm->addEntityResult($this->class->name, 'r'); - $this->rsm->setDiscriminatorColumn('r', $resultColumnName); - $this->rsm->addMetaResult('r', $resultColumnName, $discrColumn); + $this->cachedPersisterContexts['noLimits']->rsm->addEntityResult($this->class->name, 'r'); + $this->cachedPersisterContexts['noLimits']->rsm->setDiscriminatorColumn('r', $resultColumnName); + $this->cachedPersisterContexts['noLimits']->rsm->addMetaResult('r', $resultColumnName, $discrColumn); // Add regular columns foreach ($this->class->fieldMappings as $fieldName => $mapping) { diff --git a/lib/Doctrine/ORM/Persisters/Entity/SingleTablePersister.php b/lib/Doctrine/ORM/Persisters/Entity/SingleTablePersister.php index 23ebdf2d2d9..b93c2afc9e5 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/SingleTablePersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/SingleTablePersister.php @@ -63,8 +63,8 @@ protected function getSelectColumnsSQL() $resultColumnName = $this->platform->getSQLResultCasing($discrColumn); - $this->rsm->setDiscriminatorColumn('r', $resultColumnName); - $this->rsm->addMetaResult('r', $resultColumnName, $discrColumn); + $this->cachedPersisterContexts['noLimits']->rsm->setDiscriminatorColumn('r', $resultColumnName); + $this->cachedPersisterContexts['noLimits']->rsm->addMetaResult('r', $resultColumnName, $discrColumn); // Append subclass columns foreach ($this->class->subClasses as $subClassName) { From 55930a3402ab8b718750cd4ac38d4235b92530a5 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Thu, 22 Jan 2015 18:05:29 +0100 Subject: [PATCH 04/22] #1277 DDC-3346 DDC-3531 - moved `selectColumnListSql` into the newly created `CachedPersisterContext` --- .../Entity/BasicEntityPersister.php | 8 ++--- .../Entity/CachedPersisterContext.php | 31 +------------------ .../Entity/JoinedSubclassPersister.php | 8 ++--- .../Entity/SingleTablePersister.php | 8 ++--- 4 files changed, 13 insertions(+), 42 deletions(-) diff --git a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php index 30382581181..b56b9948410 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php @@ -1187,8 +1187,8 @@ protected final function getOrderBySQL(array $orderBy, $baseTableAlias) protected function getSelectColumnsSQL(/*$hasLimitClause = false*/) { //if ( ! $hasLimitClause && $this->selectColumnListSql !== null) { - if ($this->selectColumnListSql !== null) { - return $this->selectColumnListSql; + if ($this->cachedPersisterContexts['noLimits']->selectColumnListSql !== null) { + return $this->cachedPersisterContexts['noLimits']->selectColumnListSql; } $columnList = array(); @@ -1288,9 +1288,9 @@ protected function getSelectColumnsSQL(/*$hasLimitClause = false*/) $this->selectJoinSql .= implode(' AND ', $joinCondition); } - $this->selectColumnListSql = implode(', ', $columnList); + $this->cachedPersisterContexts['noLimits']->selectColumnListSql = implode(', ', $columnList); - return $this->selectColumnListSql; + return $this->cachedPersisterContexts['noLimits']->selectColumnListSql; } /** diff --git a/lib/Doctrine/ORM/Persisters/Entity/CachedPersisterContext.php b/lib/Doctrine/ORM/Persisters/Entity/CachedPersisterContext.php index a148a54dda7..f3845d06e3b 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/CachedPersisterContext.php +++ b/lib/Doctrine/ORM/Persisters/Entity/CachedPersisterContext.php @@ -48,40 +48,11 @@ class CachedPersisterContext */ public $rsm; - /** - * The map of column names to DBAL mapping types of all prepared columns used - * when INSERTing or UPDATEing an entity. - * - * @var array - * - * @see \Doctrine\ORM\Persisters\Entity\BasicEntityPersister#prepareInsertData($entity) - * @see \Doctrine\ORM\Persisters\Entity\BasicEntityPersister#prepareUpdateData($entity) - */ - public $columnTypes = array(); - - /** - * The map of quoted column names. - * - * @var array - * - * @see \Doctrine\ORM\Persisters\Entity\BasicEntityPersister#prepareInsertData($entity) - * @see \Doctrine\ORM\Persisters\Entity\BasicEntityPersister#prepareUpdateData($entity) - */ - public $quotedColumns = array(); - - /** - * The INSERT SQL statement used for entities handled by this persister. - * This SQL is only generated once per request, if at all. - * - * @var string - */ - public $insertSql = ''; - /** * The SELECT column list SQL fragment used for querying entities by this persister. * This SQL fragment is only generated once per request, if at all. * - * @var string + * @var string|null */ public $selectColumnListSql; diff --git a/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php b/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php index 3ec9afc309f..5e1e6f6fe48 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php @@ -420,8 +420,8 @@ protected function getLockTablesSql($lockMode) protected function getSelectColumnsSQL() { // Create the column list fragment only once - if ($this->selectColumnListSql !== null) { - return $this->selectColumnListSql; + if ($this->cachedPersisterContexts['noLimits']->selectColumnListSql !== null) { + return $this->cachedPersisterContexts['noLimits']->selectColumnListSql; } $columnList = array(); @@ -523,9 +523,9 @@ protected function getSelectColumnsSQL() } } - $this->selectColumnListSql = implode(', ', $columnList); + $this->cachedPersisterContexts['noLimits']->selectColumnListSql = implode(', ', $columnList); - return $this->selectColumnListSql; + return $this->cachedPersisterContexts['noLimits']->selectColumnListSql; } /** diff --git a/lib/Doctrine/ORM/Persisters/Entity/SingleTablePersister.php b/lib/Doctrine/ORM/Persisters/Entity/SingleTablePersister.php index b93c2afc9e5..8f1cf65d2c1 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/SingleTablePersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/SingleTablePersister.php @@ -48,8 +48,8 @@ protected function getDiscriminatorColumnTableName() */ protected function getSelectColumnsSQL() { - if ($this->selectColumnListSql !== null) { - return $this->selectColumnListSql; + if ($this->cachedPersisterContexts['noLimits']->selectColumnListSql !== null) { + return $this->cachedPersisterContexts['noLimits']->selectColumnListSql; } $columnList[] = parent::getSelectColumnsSQL(); @@ -106,9 +106,9 @@ protected function getSelectColumnsSQL() } } - $this->selectColumnListSql = implode(', ', $columnList); + $this->cachedPersisterContexts['noLimits']->selectColumnListSql = implode(', ', $columnList); - return $this->selectColumnListSql; + return $this->cachedPersisterContexts['noLimits']->selectColumnListSql; } /** From b9f698c98cefd1f08bc5c7023fe0057315e7e8c1 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Thu, 22 Jan 2015 18:07:28 +0100 Subject: [PATCH 05/22] #1277 DDC-3346 DDC-3531 - moved `selectJoinSql` into the newly created `CachedPersisterContext` --- .../Entity/BasicEntityPersister.php | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php index b56b9948410..a0795879b10 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php @@ -163,14 +163,6 @@ class BasicEntityPersister implements EntityPersister */ private $insertSql; - /** - * The SELECT column list SQL fragment used for querying entities by this persister. - * This SQL fragment is only generated once per request, if at all. - * - * @var string - */ - protected $selectColumnListSql; - /** * The JOIN SQL fragment used to eagerly load all many-to-one and one-to-one * associations configured as FETCH_EAGER, as well as all inverse one-to-one associations. @@ -719,7 +711,7 @@ public function load(array $criteria, $entity = null, $assoc = null, array $hint $hints[Query::HINT_REFRESH_ENTITY] = $entity; } - $hydrator = $this->em->newHydrator($this->selectJoinSql ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT); + $hydrator = $this->em->newHydrator($this->cachedPersisterContexts['noLimits']->selectJoinSql ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT); $entities = $hydrator->hydrateAll($stmt, $this->cachedPersisterContexts['noLimits']->rsm, $hints); return $entities ? $entities[0] : null; @@ -839,7 +831,7 @@ public function loadCriteria(Criteria $criteria) list($params, $types) = $this->expandCriteriaParameters($criteria); $stmt = $this->conn->executeQuery($query, $params, $types); - $hydrator = $this->em->newHydrator(($this->selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT); + $hydrator = $this->em->newHydrator(($this->cachedPersisterContexts['noLimits']->selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT); return $hydrator->hydrateAll($stmt, $this->cachedPersisterContexts['noLimits']->rsm, array(UnitOfWork::HINT_DEFEREAGERLOAD => true)); } @@ -884,7 +876,7 @@ public function loadAll(array $criteria = array(), array $orderBy = null, $limit list($params, $types) = $this->expandParameters($criteria); $stmt = $this->conn->executeQuery($sql, $params, $types); - $hydrator = $this->em->newHydrator(($this->selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT); + $hydrator = $this->em->newHydrator(($this->cachedPersisterContexts['noLimits']->selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT); return $hydrator->hydrateAll($stmt, $this->cachedPersisterContexts['noLimits']->rsm, array(UnitOfWork::HINT_DEFEREAGERLOAD => true)); } @@ -1075,7 +1067,7 @@ public function getSelectSQL($criteria, $assoc = null, $lockMode = null, $limit $select = 'SELECT ' . $columnList; $from = ' FROM ' . $tableName . ' '. $tableAlias; - $join = $this->selectJoinSql . $joinSql; + $join = $this->cachedPersisterContexts['noLimits']->selectJoinSql . $joinSql; $where = ($conditionSql ? ' WHERE ' . $conditionSql : ''); $lock = $this->platform->appendLockHint($from, $lockMode); $query = $select @@ -1199,7 +1191,7 @@ protected function getSelectColumnsSQL(/*$hasLimitClause = false*/) $columnList[] = $this->getSelectColumnSQL($field, $this->class); } - $this->selectJoinSql = ''; + $this->cachedPersisterContexts['noLimits']->selectJoinSql = ''; $eagerAliasCounter = 0; foreach ($this->class->associationMappings as $assocField => $assoc) { @@ -1257,7 +1249,7 @@ protected function getSelectColumnsSQL(/*$hasLimitClause = false*/) if ($assoc['isOwningSide']) { $tableAlias = $this->getSQLTableAlias($association['targetEntity'], $assocAlias); - $this->selectJoinSql .= ' ' . $this->getJoinSQLForJoinColumns($association['joinColumns']); + $this->cachedPersisterContexts['noLimits']->selectJoinSql .= ' ' . $this->getJoinSQLForJoinColumns($association['joinColumns']); foreach ($association['joinColumns'] as $joinColumn) { $sourceCol = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform); @@ -1273,7 +1265,7 @@ protected function getSelectColumnsSQL(/*$hasLimitClause = false*/) } else { - $this->selectJoinSql .= ' LEFT JOIN'; + $this->cachedPersisterContexts['noLimits']->selectJoinSql .= ' LEFT JOIN'; foreach ($association['joinColumns'] as $joinColumn) { $sourceCol = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform); @@ -1284,8 +1276,8 @@ protected function getSelectColumnsSQL(/*$hasLimitClause = false*/) } } - $this->selectJoinSql .= ' ' . $joinTableName . ' ' . $joinTableAlias . ' ON '; - $this->selectJoinSql .= implode(' AND ', $joinCondition); + $this->cachedPersisterContexts['noLimits']->selectJoinSql .= ' ' . $joinTableName . ' ' . $joinTableAlias . ' ON '; + $this->cachedPersisterContexts['noLimits']->selectJoinSql .= implode(' AND ', $joinCondition); } $this->cachedPersisterContexts['noLimits']->selectColumnListSql = implode(', ', $columnList); From 2a7f1490297daab8ed548d12efb53aa584d95ebc Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Thu, 22 Jan 2015 18:09:30 +0100 Subject: [PATCH 06/22] #1277 DDC-3346 DDC-3531 - moved `sqlAliasCounter` into the newly created `CachedPersisterContext` --- .../Entity/BasicEntityPersister.php | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php index a0795879b10..4df64bbd808 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php @@ -163,21 +163,6 @@ class BasicEntityPersister implements EntityPersister */ private $insertSql; - /** - * The JOIN SQL fragment used to eagerly load all many-to-one and one-to-one - * associations configured as FETCH_EAGER, as well as all inverse one-to-one associations. - * - * @var string - */ - protected $selectJoinSql; - - /** - * Counter for creating unique SQL table and column aliases. - * - * @var integer - */ - protected $sqlAliasCounter = 0; - /** * Map from class names (FQCN) to the corresponding generated SQL table aliases. * @@ -1481,7 +1466,7 @@ protected function getSQLTableAlias($className, $assocName = '') return $this->sqlTableAliases[$className]; } - $tableAlias = 't' . $this->sqlAliasCounter++; + $tableAlias = 't' . $this->cachedPersisterContexts['noLimits']->sqlAliasCounter++; $this->sqlTableAliases[$className] = $tableAlias; @@ -1925,7 +1910,7 @@ protected function getJoinSQLForJoinColumns($joinColumns) */ public function getSQLColumnAlias($columnName) { - return $this->quoteStrategy->getColumnAlias($columnName, $this->sqlAliasCounter++, $this->platform); + return $this->quoteStrategy->getColumnAlias($columnName, $this->cachedPersisterContexts['noLimits']->sqlAliasCounter++, $this->platform); } /** From ebdfab8f2cfd38948f5cfbe196d7b15cdf8d4048 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Thu, 22 Jan 2015 18:10:43 +0100 Subject: [PATCH 07/22] #1277 DDC-3346 DDC-3531 - moved `sqlTableAliases` into the newly created `CachedPersisterContext` --- .../ORM/Persisters/Entity/BasicEntityPersister.php | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php index 4df64bbd808..24bafa5504c 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php @@ -163,13 +163,6 @@ class BasicEntityPersister implements EntityPersister */ private $insertSql; - /** - * Map from class names (FQCN) to the corresponding generated SQL table aliases. - * - * @var array - */ - protected $sqlTableAliases = array(); - /** * The quote strategy. * @@ -1462,13 +1455,13 @@ protected function getSQLTableAlias($className, $assocName = '') $className .= '#' . $assocName; } - if (isset($this->sqlTableAliases[$className])) { - return $this->sqlTableAliases[$className]; + if (isset($this->cachedPersisterContexts['noLimits']->sqlTableAliases[$className])) { + return $this->cachedPersisterContexts['noLimits']->sqlTableAliases[$className]; } $tableAlias = 't' . $this->cachedPersisterContexts['noLimits']->sqlAliasCounter++; - $this->sqlTableAliases[$className] = $tableAlias; + $this->cachedPersisterContexts['noLimits']->sqlTableAliases[$className] = $tableAlias; return $tableAlias; } From 8b9171c8ade4ec2d9f8bec70f00ce4f3d4c09adc Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Thu, 22 Jan 2015 18:15:10 +0100 Subject: [PATCH 08/22] #1277 DDC-3346 DDC-3531 - caching the currently in use persister context --- .../Entity/BasicEntityPersister.php | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php index 24bafa5504c..fd7408f2b7b 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php @@ -182,6 +182,11 @@ class BasicEntityPersister implements EntityPersister */ protected $cachedPersisterContexts = []; + /** + * @var CachedPersisterContext + */ + protected $currentPersisterContext; + /** * Initializes a new BasicEntityPersister that uses the given EntityManager * and persists instances of the class described by the given ClassMetadata descriptor. @@ -197,7 +202,11 @@ public function __construct(EntityManagerInterface $em, ClassMetadata $class) $this->platform = $this->conn->getDatabasePlatform(); $this->quoteStrategy = $em->getConfiguration()->getQuoteStrategy(); $this->identifierFlattener = new IdentifierFlattener($em->getUnitOfWork(), $em->getMetadataFactory()); - $this->cachedPersisterContexts['noLimits'] = new CachedPersisterContext( + $this->cachedPersisterContexts['noLimits'] = $this->currentPersisterContext = new CachedPersisterContext( + $class, + new Query\ResultSetMapping() + ); + $this->cachedPersisterContexts['withLimits'] = new CachedPersisterContext( $class, new Query\ResultSetMapping() ); @@ -1927,4 +1936,13 @@ protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targ $sql = implode(' AND ', $filterClauses); return $sql ? "(" . $sql . ")" : ""; // Wrap again to avoid "X or Y and FilterConditionSQL" } + + private function loadPersisterContext($offset, $limit) + { + if (null === $offset && null === $limit) { + $this->currentPersisterContext = $this->cachedPersisterContexts['noLimits']; + } + + $this->currentPersisterContext = $this->cachedPersisterContexts['withLimits']; + } } From 23a0d9a1fb649ff3fcd728c2d4c0046eaa540c76 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Thu, 22 Jan 2015 18:20:19 +0100 Subject: [PATCH 09/22] #1277 DDC-3346 DDC-3531 - switch persister context at runtime --- .../Persisters/Entity/BasicEntityPersister.php | 18 ++++++++++++++++-- .../Entity/JoinedSubclassPersister.php | 2 ++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php index fd7408f2b7b..8047907ee8a 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php @@ -689,6 +689,8 @@ public function getOwningTable($fieldName) */ public function load(array $criteria, $entity = null, $assoc = null, array $hints = array(), $lockMode = null, $limit = null, array $orderBy = null) { + $this->loadPersisterContext(null, $limit); + $sql = $this->getSelectSQL($criteria, $assoc, $lockMode, $limit, null, $orderBy); list($params, $types) = $this->expandParameters($criteria); $stmt = $this->conn->executeQuery($sql, $params, $types); @@ -859,6 +861,8 @@ public function expandCriteriaParameters(Criteria $criteria) */ public function loadAll(array $criteria = array(), array $orderBy = null, $limit = null, $offset = null) { + $this->loadPersisterContext($offset, $limit); + $sql = $this->getSelectSQL($criteria, null, null, $limit, $offset, $orderBy); list($params, $types) = $this->expandParameters($criteria); $stmt = $this->conn->executeQuery($sql, $params, $types); @@ -873,6 +877,8 @@ public function loadAll(array $criteria = array(), array $orderBy = null, $limit */ public function getManyToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null) { + $this->loadPersisterContext($offset, $limit); + $stmt = $this->getManyToManyStatement($assoc, $sourceEntity, $offset, $limit); return $this->loadArrayFromStatement($assoc, $stmt); @@ -946,6 +952,8 @@ public function loadManyToManyCollection(array $assoc, $sourceEntity, Persistent */ private function getManyToManyStatement(array $assoc, $sourceEntity, $offset = null, $limit = null) { + $this->loadPersisterContext($offset, $limit); + $sourceClass = $this->em->getClassMetadata($assoc['sourceEntity']); $class = $sourceClass; $association = $assoc; @@ -1011,6 +1019,8 @@ private function getManyToManyStatement(array $assoc, $sourceEntity, $offset = n */ public function getSelectSQL($criteria, $assoc = null, $lockMode = null, $limit = null, $offset = null, array $orderBy = null) { + $this->loadPersisterContext($offset, $limit); + $lockSql = ''; $joinSql = ''; $orderBySql = ''; @@ -1041,7 +1051,7 @@ public function getSelectSQL($criteria, $assoc = null, $lockMode = null, $limit break; } - $columnList = $this->getSelectColumnsSQL(null !== $limit); + $columnList = $this->getSelectColumnsSQL(); $tableAlias = $this->getSQLTableAlias($this->class->name); $filterSql = $this->generateFilterConditionSQL($this->class, $tableAlias); $tableName = $this->quoteStrategy->getTableName($this->class, $this->platform); @@ -1672,6 +1682,8 @@ protected function getSelectConditionSQL(array $criteria, $assoc = null) */ public function getOneToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null) { + $this->loadPersisterContext($offset, $limit); + $stmt = $this->getOneToManyStatement($assoc, $sourceEntity, $offset, $limit); return $this->loadArrayFromStatement($assoc, $stmt); @@ -1699,6 +1711,8 @@ public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentC */ private function getOneToManyStatement(array $assoc, $sourceEntity, $offset = null, $limit = null) { + $this->loadPersisterContext($offset, $limit); + $criteria = array(); $parameters = array(); $owningAssoc = $this->class->associationMappings[$assoc['mappedBy']]; @@ -1937,7 +1951,7 @@ protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targ return $sql ? "(" . $sql . ")" : ""; // Wrap again to avoid "X or Y and FilterConditionSQL" } - private function loadPersisterContext($offset, $limit) + protected function loadPersisterContext($offset, $limit) { if (null === $offset && null === $limit) { $this->currentPersisterContext = $this->cachedPersisterContexts['noLimits']; diff --git a/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php b/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php index 5e1e6f6fe48..1e7366d0f08 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php @@ -299,6 +299,8 @@ public function delete($entity) */ public function getSelectSQL($criteria, $assoc = null, $lockMode = null, $limit = null, $offset = null, array $orderBy = null) { + $this->loadPersisterContext($offset, $limit); + $baseTableAlias = $this->getSQLTableAlias($this->class->name); $joinSql = $this->getJoinSql($baseTableAlias); From 67f60f22860f7f45810ed36aaf5523025e1f5e01 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Thu, 22 Jan 2015 18:30:12 +0100 Subject: [PATCH 10/22] #1277 DDC-3346 DDC-3531 - switching persister context at runtime, depending on choices --- .../AbstractEntityInheritancePersister.php | 4 +- .../Entity/BasicEntityPersister.php | 64 +++++++++---------- .../Entity/JoinedSubclassPersister.php | 16 ++--- .../Entity/SingleTablePersister.php | 12 ++-- 4 files changed, 48 insertions(+), 48 deletions(-) diff --git a/lib/Doctrine/ORM/Persisters/Entity/AbstractEntityInheritancePersister.php b/lib/Doctrine/ORM/Persisters/Entity/AbstractEntityInheritancePersister.php index e8f9801cc9d..6b5e5c4f13c 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/AbstractEntityInheritancePersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/AbstractEntityInheritancePersister.php @@ -66,7 +66,7 @@ protected function getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r' $sql = $this->getSQLTableAlias($class->name, $tableAlias) . '.' . $this->quoteStrategy->getColumnName($field, $class, $this->platform); - $this->cachedPersisterContexts['noLimits']->rsm->addFieldResult($alias, $columnAlias, $field, $class->name); + $this->currentPersisterContext->rsm->addFieldResult($alias, $columnAlias, $field, $class->name); if (isset($class->fieldMappings[$field]['requireSQLConversion'])) { $type = Type::getType($class->getTypeOfField($field)); @@ -88,7 +88,7 @@ protected function getSelectJoinColumnSQL($tableAlias, $joinColumnName, $classNa { $columnAlias = $this->getSQLColumnAlias($joinColumnName); - $this->cachedPersisterContexts['noLimits']->rsm->addMetaResult('r', $columnAlias, $joinColumnName, false, $type); + $this->currentPersisterContext->rsm->addMetaResult('r', $columnAlias, $joinColumnName, false, $type); return $tableAlias . '.' . $joinColumnName . ' AS ' . $columnAlias; } diff --git a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php index 8047907ee8a..6d3c6f37cbf 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php @@ -225,7 +225,7 @@ public function getClassMetadata() */ public function getResultSetMapping() { - return $this->cachedPersisterContexts['noLimits']->rsm; + return $this->currentPersisterContext->rsm; } /** @@ -700,8 +700,8 @@ public function load(array $criteria, $entity = null, $assoc = null, array $hint $hints[Query::HINT_REFRESH_ENTITY] = $entity; } - $hydrator = $this->em->newHydrator($this->cachedPersisterContexts['noLimits']->selectJoinSql ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT); - $entities = $hydrator->hydrateAll($stmt, $this->cachedPersisterContexts['noLimits']->rsm, $hints); + $hydrator = $this->em->newHydrator($this->currentPersisterContext->selectJoinSql ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT); + $entities = $hydrator->hydrateAll($stmt, $this->currentPersisterContext->rsm, $hints); return $entities ? $entities[0] : null; } @@ -790,7 +790,7 @@ public function refresh(array $id, $entity, $lockMode = null) $stmt = $this->conn->executeQuery($sql, $params, $types); $hydrator = $this->em->newHydrator(Query::HYDRATE_OBJECT); - $hydrator->hydrateAll($stmt, $this->cachedPersisterContexts['noLimits']->rsm, array(Query::HINT_REFRESH => true)); + $hydrator->hydrateAll($stmt, $this->currentPersisterContext->rsm, array(Query::HINT_REFRESH => true)); } /** @@ -820,9 +820,9 @@ public function loadCriteria(Criteria $criteria) list($params, $types) = $this->expandCriteriaParameters($criteria); $stmt = $this->conn->executeQuery($query, $params, $types); - $hydrator = $this->em->newHydrator(($this->cachedPersisterContexts['noLimits']->selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT); + $hydrator = $this->em->newHydrator(($this->currentPersisterContext->selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT); - return $hydrator->hydrateAll($stmt, $this->cachedPersisterContexts['noLimits']->rsm, array(UnitOfWork::HINT_DEFEREAGERLOAD => true)); + return $hydrator->hydrateAll($stmt, $this->currentPersisterContext->rsm, array(UnitOfWork::HINT_DEFEREAGERLOAD => true)); } /** @@ -867,9 +867,9 @@ public function loadAll(array $criteria = array(), array $orderBy = null, $limit list($params, $types) = $this->expandParameters($criteria); $stmt = $this->conn->executeQuery($sql, $params, $types); - $hydrator = $this->em->newHydrator(($this->cachedPersisterContexts['noLimits']->selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT); + $hydrator = $this->em->newHydrator(($this->currentPersisterContext->selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT); - return $hydrator->hydrateAll($stmt, $this->cachedPersisterContexts['noLimits']->rsm, array(UnitOfWork::HINT_DEFEREAGERLOAD => true)); + return $hydrator->hydrateAll($stmt, $this->currentPersisterContext->rsm, array(UnitOfWork::HINT_DEFEREAGERLOAD => true)); } /** @@ -894,11 +894,11 @@ public function getManyToManyCollection(array $assoc, $sourceEntity, $offset = n */ private function loadArrayFromStatement($assoc, $stmt) { - $rsm = $this->cachedPersisterContexts['noLimits']->rsm; + $rsm = $this->currentPersisterContext->rsm; $hints = array(UnitOfWork::HINT_DEFEREAGERLOAD => true); if (isset($assoc['indexBy'])) { - $rsm = clone ($this->cachedPersisterContexts['noLimits']->rsm); // this is necessary because the "default rsm" should be changed. + $rsm = clone ($this->currentPersisterContext->rsm); // this is necessary because the "default rsm" should be changed. $rsm->addIndexBy('r', $assoc['indexBy']); } @@ -916,14 +916,14 @@ private function loadArrayFromStatement($assoc, $stmt) */ private function loadCollectionFromStatement($assoc, $stmt, $coll) { - $rsm = $this->cachedPersisterContexts['noLimits']->rsm; + $rsm = $this->currentPersisterContext->rsm; $hints = array( UnitOfWork::HINT_DEFEREAGERLOAD => true, 'collection' => $coll ); if (isset($assoc['indexBy'])) { - $rsm = clone ($this->cachedPersisterContexts['noLimits']->rsm); // this is necessary because the "default rsm" should be changed. + $rsm = clone ($this->currentPersisterContext->rsm); // this is necessary because the "default rsm" should be changed. $rsm->addIndexBy('r', $assoc['indexBy']); } @@ -1064,7 +1064,7 @@ public function getSelectSQL($criteria, $assoc = null, $lockMode = null, $limit $select = 'SELECT ' . $columnList; $from = ' FROM ' . $tableName . ' '. $tableAlias; - $join = $this->cachedPersisterContexts['noLimits']->selectJoinSql . $joinSql; + $join = $this->currentPersisterContext->selectJoinSql . $joinSql; $where = ($conditionSql ? ' WHERE ' . $conditionSql : ''); $lock = $this->platform->appendLockHint($from, $lockMode); $query = $select @@ -1176,19 +1176,19 @@ protected final function getOrderBySQL(array $orderBy, $baseTableAlias) protected function getSelectColumnsSQL(/*$hasLimitClause = false*/) { //if ( ! $hasLimitClause && $this->selectColumnListSql !== null) { - if ($this->cachedPersisterContexts['noLimits']->selectColumnListSql !== null) { - return $this->cachedPersisterContexts['noLimits']->selectColumnListSql; + if ($this->currentPersisterContext->selectColumnListSql !== null) { + return $this->currentPersisterContext->selectColumnListSql; } $columnList = array(); - $this->cachedPersisterContexts['noLimits']->rsm->addEntityResult($this->class->name, 'r'); // r for root + $this->currentPersisterContext->rsm->addEntityResult($this->class->name, 'r'); // r for root // Add regular columns to select list foreach ($this->class->fieldNames as $field) { $columnList[] = $this->getSelectColumnSQL($field, $this->class); } - $this->cachedPersisterContexts['noLimits']->selectJoinSql = ''; + $this->currentPersisterContext->selectJoinSql = ''; $eagerAliasCounter = 0; foreach ($this->class->associationMappings as $assocField => $assoc) { @@ -1213,7 +1213,7 @@ protected function getSelectColumnsSQL(/*$hasLimitClause = false*/) } $assocAlias = 'e' . ($eagerAliasCounter++); - $this->cachedPersisterContexts['noLimits']->rsm->addJoinedEntityResult($assoc['targetEntity'], $assocAlias, 'r', $assocField); + $this->currentPersisterContext->rsm->addJoinedEntityResult($assoc['targetEntity'], $assocAlias, 'r', $assocField); foreach ($eagerEntity->fieldNames as $field) { $columnList[] = $this->getSelectColumnSQL($field, $eagerEntity, $assocAlias); @@ -1233,7 +1233,7 @@ protected function getSelectColumnsSQL(/*$hasLimitClause = false*/) $joinCondition = array(); if (isset($assoc['indexBy'])) { - $this->cachedPersisterContexts['noLimits']->rsm->addIndexBy($assocAlias, $assoc['indexBy']); + $this->currentPersisterContext->rsm->addIndexBy($assocAlias, $assoc['indexBy']); } if ( ! $assoc['isOwningSide']) { @@ -1246,7 +1246,7 @@ protected function getSelectColumnsSQL(/*$hasLimitClause = false*/) if ($assoc['isOwningSide']) { $tableAlias = $this->getSQLTableAlias($association['targetEntity'], $assocAlias); - $this->cachedPersisterContexts['noLimits']->selectJoinSql .= ' ' . $this->getJoinSQLForJoinColumns($association['joinColumns']); + $this->currentPersisterContext->selectJoinSql .= ' ' . $this->getJoinSQLForJoinColumns($association['joinColumns']); foreach ($association['joinColumns'] as $joinColumn) { $sourceCol = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform); @@ -1262,7 +1262,7 @@ protected function getSelectColumnsSQL(/*$hasLimitClause = false*/) } else { - $this->cachedPersisterContexts['noLimits']->selectJoinSql .= ' LEFT JOIN'; + $this->currentPersisterContext->selectJoinSql .= ' LEFT JOIN'; foreach ($association['joinColumns'] as $joinColumn) { $sourceCol = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform); @@ -1273,13 +1273,13 @@ protected function getSelectColumnsSQL(/*$hasLimitClause = false*/) } } - $this->cachedPersisterContexts['noLimits']->selectJoinSql .= ' ' . $joinTableName . ' ' . $joinTableAlias . ' ON '; - $this->cachedPersisterContexts['noLimits']->selectJoinSql .= implode(' AND ', $joinCondition); + $this->currentPersisterContext->selectJoinSql .= ' ' . $joinTableName . ' ' . $joinTableAlias . ' ON '; + $this->currentPersisterContext->selectJoinSql .= implode(' AND ', $joinCondition); } - $this->cachedPersisterContexts['noLimits']->selectColumnListSql = implode(', ', $columnList); + $this->currentPersisterContext->selectColumnListSql = implode(', ', $columnList); - return $this->cachedPersisterContexts['noLimits']->selectColumnListSql; + return $this->currentPersisterContext->selectColumnListSql; } /** @@ -1310,7 +1310,7 @@ protected function getSelectColumnAssociationSQL($field, $assoc, ClassMetadata $ . '.' . $quotedColumn . ' AS ' . $resultColumnName; $type = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $targetClass, $this->em); - $this->cachedPersisterContexts['noLimits']->rsm->addMetaResult($alias, $resultColumnName, $quotedColumn, $isIdentifier, $type); + $this->currentPersisterContext->rsm->addMetaResult($alias, $resultColumnName, $quotedColumn, $isIdentifier, $type); } return implode(', ', $columnList); @@ -1448,7 +1448,7 @@ protected function getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r' $sql = $tableAlias . '.' . $columnName; $columnAlias = $this->getSQLColumnAlias($class->columnNames[$field]); - $this->cachedPersisterContexts['noLimits']->rsm->addFieldResult($alias, $columnAlias, $field); + $this->currentPersisterContext->rsm->addFieldResult($alias, $columnAlias, $field); if (isset($class->fieldMappings[$field]['requireSQLConversion'])) { $type = Type::getType($class->getTypeOfField($field)); @@ -1474,13 +1474,13 @@ protected function getSQLTableAlias($className, $assocName = '') $className .= '#' . $assocName; } - if (isset($this->cachedPersisterContexts['noLimits']->sqlTableAliases[$className])) { - return $this->cachedPersisterContexts['noLimits']->sqlTableAliases[$className]; + if (isset($this->currentPersisterContext->sqlTableAliases[$className])) { + return $this->currentPersisterContext->sqlTableAliases[$className]; } - $tableAlias = 't' . $this->cachedPersisterContexts['noLimits']->sqlAliasCounter++; + $tableAlias = 't' . $this->currentPersisterContext->sqlAliasCounter++; - $this->cachedPersisterContexts['noLimits']->sqlTableAliases[$className] = $tableAlias; + $this->currentPersisterContext->sqlTableAliases[$className] = $tableAlias; return $tableAlias; } @@ -1926,7 +1926,7 @@ protected function getJoinSQLForJoinColumns($joinColumns) */ public function getSQLColumnAlias($columnName) { - return $this->quoteStrategy->getColumnAlias($columnName, $this->cachedPersisterContexts['noLimits']->sqlAliasCounter++, $this->platform); + return $this->quoteStrategy->getColumnAlias($columnName, $this->currentPersisterContext->sqlAliasCounter++, $this->platform); } /** diff --git a/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php b/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php index 1e7366d0f08..6f33baf9c85 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php @@ -422,19 +422,19 @@ protected function getLockTablesSql($lockMode) protected function getSelectColumnsSQL() { // Create the column list fragment only once - if ($this->cachedPersisterContexts['noLimits']->selectColumnListSql !== null) { - return $this->cachedPersisterContexts['noLimits']->selectColumnListSql; + if ($this->currentPersisterContext->selectColumnListSql !== null) { + return $this->currentPersisterContext->selectColumnListSql; } $columnList = array(); - //$this->cachedPersisterContexts['noLimits']->rsm = new ResultSetMapping(); + //$this->currentPersisterContext->rsm = new ResultSetMapping(); $discrColumn = $this->class->discriminatorColumn['name']; $baseTableAlias = $this->getSQLTableAlias($this->class->name); $resultColumnName = $this->platform->getSQLResultCasing($discrColumn); - $this->cachedPersisterContexts['noLimits']->rsm->addEntityResult($this->class->name, 'r'); - $this->cachedPersisterContexts['noLimits']->rsm->setDiscriminatorColumn('r', $resultColumnName); - $this->cachedPersisterContexts['noLimits']->rsm->addMetaResult('r', $resultColumnName, $discrColumn); + $this->currentPersisterContext->rsm->addEntityResult($this->class->name, 'r'); + $this->currentPersisterContext->rsm->setDiscriminatorColumn('r', $resultColumnName); + $this->currentPersisterContext->rsm->addMetaResult('r', $resultColumnName, $discrColumn); // Add regular columns foreach ($this->class->fieldMappings as $fieldName => $mapping) { @@ -525,9 +525,9 @@ protected function getSelectColumnsSQL() } } - $this->cachedPersisterContexts['noLimits']->selectColumnListSql = implode(', ', $columnList); + $this->currentPersisterContext->selectColumnListSql = implode(', ', $columnList); - return $this->cachedPersisterContexts['noLimits']->selectColumnListSql; + return $this->currentPersisterContext->selectColumnListSql; } /** diff --git a/lib/Doctrine/ORM/Persisters/Entity/SingleTablePersister.php b/lib/Doctrine/ORM/Persisters/Entity/SingleTablePersister.php index 8f1cf65d2c1..f9e4d557363 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/SingleTablePersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/SingleTablePersister.php @@ -48,8 +48,8 @@ protected function getDiscriminatorColumnTableName() */ protected function getSelectColumnsSQL() { - if ($this->cachedPersisterContexts['noLimits']->selectColumnListSql !== null) { - return $this->cachedPersisterContexts['noLimits']->selectColumnListSql; + if ($this->currentPersisterContext->selectColumnListSql !== null) { + return $this->currentPersisterContext->selectColumnListSql; } $columnList[] = parent::getSelectColumnsSQL(); @@ -63,8 +63,8 @@ protected function getSelectColumnsSQL() $resultColumnName = $this->platform->getSQLResultCasing($discrColumn); - $this->cachedPersisterContexts['noLimits']->rsm->setDiscriminatorColumn('r', $resultColumnName); - $this->cachedPersisterContexts['noLimits']->rsm->addMetaResult('r', $resultColumnName, $discrColumn); + $this->currentPersisterContext->rsm->setDiscriminatorColumn('r', $resultColumnName); + $this->currentPersisterContext->rsm->addMetaResult('r', $resultColumnName, $discrColumn); // Append subclass columns foreach ($this->class->subClasses as $subClassName) { @@ -106,9 +106,9 @@ protected function getSelectColumnsSQL() } } - $this->cachedPersisterContexts['noLimits']->selectColumnListSql = implode(', ', $columnList); + $this->currentPersisterContext->selectColumnListSql = implode(', ', $columnList); - return $this->cachedPersisterContexts['noLimits']->selectColumnListSql; + return $this->currentPersisterContext->selectColumnListSql; } /** From a37fa97be35e446a84d43c7790d54e2a13e5570b Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 23 Jan 2015 15:54:48 +0100 Subject: [PATCH 11/22] #1277 DDC-3346 DDC-3531 - skipping joining of associations when limiting and fetch-joining to-many eager associations --- .../Persisters/Entity/BasicEntityPersister.php | 16 +++++++++++----- .../Persisters/Entity/CachedPersisterContext.php | 16 +++++++++++++--- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php index 6d3c6f37cbf..b91f850b9d2 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php @@ -204,11 +204,13 @@ public function __construct(EntityManagerInterface $em, ClassMetadata $class) $this->identifierFlattener = new IdentifierFlattener($em->getUnitOfWork(), $em->getMetadataFactory()); $this->cachedPersisterContexts['noLimits'] = $this->currentPersisterContext = new CachedPersisterContext( $class, - new Query\ResultSetMapping() + new Query\ResultSetMapping(), + false ); $this->cachedPersisterContexts['withLimits'] = new CachedPersisterContext( $class, - new Query\ResultSetMapping() + new Query\ResultSetMapping(), + true ); } @@ -1169,11 +1171,9 @@ protected final function getOrderBySQL(array $orderBy, $baseTableAlias) * the resulting SQL fragment is generated only once and cached in {@link selectColumnListSql}. * Subclasses may or may not do the same. * - * @param bool $hasLimitClause - * * @return string The SQL fragment. */ - protected function getSelectColumnsSQL(/*$hasLimitClause = false*/) + protected function getSelectColumnsSQL() { //if ( ! $hasLimitClause && $this->selectColumnListSql !== null) { if ($this->currentPersisterContext->selectColumnListSql !== null) { @@ -1206,6 +1206,10 @@ protected function getSelectColumnsSQL(/*$hasLimitClause = false*/) continue; } + if ((($assoc['type'] & ClassMetadata::TO_MANY) > 0) && $this->currentPersisterContext->handlesLimits) { + continue; + } + $eagerEntity = $this->em->getClassMetadata($assoc['targetEntity']); if ($eagerEntity->inheritanceType != ClassMetadata::INHERITANCE_TYPE_NONE) { @@ -1955,6 +1959,8 @@ protected function loadPersisterContext($offset, $limit) { if (null === $offset && null === $limit) { $this->currentPersisterContext = $this->cachedPersisterContexts['noLimits']; + + return; } $this->currentPersisterContext = $this->cachedPersisterContexts['withLimits']; diff --git a/lib/Doctrine/ORM/Persisters/Entity/CachedPersisterContext.php b/lib/Doctrine/ORM/Persisters/Entity/CachedPersisterContext.php index f3845d06e3b..81fde938b3e 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/CachedPersisterContext.php +++ b/lib/Doctrine/ORM/Persisters/Entity/CachedPersisterContext.php @@ -78,15 +78,25 @@ class CachedPersisterContext */ public $sqlTableAliases = array(); + /** + * Whether this persistent context is considering limit operations applied to the selection queries + * + * @var bool + */ + public $handlesLimits; + /** * @param ClassMetadata $class * @param ResultSetMapping $rsm + * @param bool $handlesLimits */ public function __construct( ClassMetadata $class, - ResultSetMapping $rsm + ResultSetMapping $rsm, + $handlesLimits ) { - $this->class = $class; - $this->rsm = $rsm; + $this->class = $class; + $this->rsm = $rsm; + $this->handlesLimits = (bool) $handlesLimits; } } From 1672448993b0c72d842738507055ec535b179ddc Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 23 Jan 2015 16:01:48 +0100 Subject: [PATCH 12/22] #1277 DDC-3346 DDC-3531 - renaming persister context switch for clarity --- .../Entity/BasicEntityPersister.php | 24 ++++++++++++------- .../Entity/JoinedSubclassPersister.php | 2 +- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php index b91f850b9d2..a1ad364e052 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php @@ -691,7 +691,7 @@ public function getOwningTable($fieldName) */ public function load(array $criteria, $entity = null, $assoc = null, array $hints = array(), $lockMode = null, $limit = null, array $orderBy = null) { - $this->loadPersisterContext(null, $limit); + $this->switchPersisterContext(null, $limit); $sql = $this->getSelectSQL($criteria, $assoc, $lockMode, $limit, null, $orderBy); list($params, $types) = $this->expandParameters($criteria); @@ -863,7 +863,7 @@ public function expandCriteriaParameters(Criteria $criteria) */ public function loadAll(array $criteria = array(), array $orderBy = null, $limit = null, $offset = null) { - $this->loadPersisterContext($offset, $limit); + $this->switchPersisterContext($offset, $limit); $sql = $this->getSelectSQL($criteria, null, null, $limit, $offset, $orderBy); list($params, $types) = $this->expandParameters($criteria); @@ -879,7 +879,7 @@ public function loadAll(array $criteria = array(), array $orderBy = null, $limit */ public function getManyToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null) { - $this->loadPersisterContext($offset, $limit); + $this->switchPersisterContext($offset, $limit); $stmt = $this->getManyToManyStatement($assoc, $sourceEntity, $offset, $limit); @@ -954,7 +954,7 @@ public function loadManyToManyCollection(array $assoc, $sourceEntity, Persistent */ private function getManyToManyStatement(array $assoc, $sourceEntity, $offset = null, $limit = null) { - $this->loadPersisterContext($offset, $limit); + $this->switchPersisterContext($offset, $limit); $sourceClass = $this->em->getClassMetadata($assoc['sourceEntity']); $class = $sourceClass; @@ -1021,7 +1021,7 @@ private function getManyToManyStatement(array $assoc, $sourceEntity, $offset = n */ public function getSelectSQL($criteria, $assoc = null, $lockMode = null, $limit = null, $offset = null, array $orderBy = null) { - $this->loadPersisterContext($offset, $limit); + $this->switchPersisterContext($offset, $limit); $lockSql = ''; $joinSql = ''; @@ -1686,7 +1686,7 @@ protected function getSelectConditionSQL(array $criteria, $assoc = null) */ public function getOneToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null) { - $this->loadPersisterContext($offset, $limit); + $this->switchPersisterContext($offset, $limit); $stmt = $this->getOneToManyStatement($assoc, $sourceEntity, $offset, $limit); @@ -1715,7 +1715,7 @@ public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentC */ private function getOneToManyStatement(array $assoc, $sourceEntity, $offset = null, $limit = null) { - $this->loadPersisterContext($offset, $limit); + $this->switchPersisterContext($offset, $limit); $criteria = array(); $parameters = array(); @@ -1955,7 +1955,15 @@ protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targ return $sql ? "(" . $sql . ")" : ""; // Wrap again to avoid "X or Y and FilterConditionSQL" } - protected function loadPersisterContext($offset, $limit) + /** + * Switches persister context according to current query offset/limits + * + * This is due to the fact that to-many associations cannot be fetch-joined when a limit is involved + * + * @param null|int $offset + * @param null|int $limit + */ + protected function switchPersisterContext($offset, $limit) { if (null === $offset && null === $limit) { $this->currentPersisterContext = $this->cachedPersisterContexts['noLimits']; diff --git a/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php b/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php index 6f33baf9c85..5d259e4af73 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php @@ -299,7 +299,7 @@ public function delete($entity) */ public function getSelectSQL($criteria, $assoc = null, $lockMode = null, $limit = null, $offset = null, array $orderBy = null) { - $this->loadPersisterContext($offset, $limit); + $this->switchPersisterContext($offset, $limit); $baseTableAlias = $this->getSQLTableAlias($this->class->name); $joinSql = $this->getJoinSql($baseTableAlias); From 157bf203bcf34d16c73fffed65d170957db4e838 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 23 Jan 2015 16:09:18 +0100 Subject: [PATCH 13/22] #1277 DDC-3346 DDC-3531 - additional tests for LIMIT and OFFSET repository API (must not hydrate collections) --- .../ORM/Functional/Ticket/DDC3346Test.php | 64 ++++++++++++++++--- 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php index e082c1b56a6..7ae4fa70603 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php @@ -22,7 +22,7 @@ public function setUp() ); } - public function testFindOneByWithEagerFetch() + public function testFindOneWithEagerFetchWillNotHydrateLimitedCollection() { $user = new DDC3346Author(); $user->username = "bwoogy"; @@ -37,24 +37,70 @@ public function testFindOneByWithEagerFetch() $this->_em->persist($article1); $this->_em->persist($article2); $this->_em->flush(); - $this->_em->close(); + $this->_em->clear(); + + /** @var DDC3346Author $author */ + $author = $this->_em->getRepository('Doctrine\Tests\Models\DDC3346\DDC3346Author')->findOneBy( + array('username' => "bwoogy") + ); + + $this->assertCount(2, $author->articles); + } + + public function testFindLimitedWithEagerFetchWillNotHydrateLimitedCollection() + { + $user = new DDC3346Author(); + $user->username = "bwoogy"; + + $article1 = new DDC3346Article(); + $article1->setAuthor($user); + + $article2 = new DDC3346Article(); + $article2->setAuthor($user); + + $this->_em->persist($user); + $this->_em->persist($article1); + $this->_em->persist($article2); + $this->_em->flush(); + $this->_em->clear(); /** @var DDC3346Author[] $authors */ $authors = $this->_em->getRepository('Doctrine\Tests\Models\DDC3346\DDC3346Author')->findBy( - array('username' => "bwoogy") + array('username' => "bwoogy"), + null, + 1 ); $this->assertCount(1, $authors); - $this->assertCount(2, $authors[0]->articles); + } - $this->_em->close(); + public function testFindWithEagerFetchAndOffsetWillNotHydrateLimitedCollection() + { + $user = new DDC3346Author(); + $user->username = "bwoogy"; - /** @var DDC3346Author $author */ - $author = $this->_em->getRepository('Doctrine\Tests\Models\DDC3346\DDC3346Author')->findOneBy( - array('username' => "bwoogy") + $article1 = new DDC3346Article(); + $article1->setAuthor($user); + + $article2 = new DDC3346Article(); + $article2->setAuthor($user); + + $this->_em->persist($user); + $this->_em->persist($article1); + $this->_em->persist($article2); + $this->_em->flush(); + $this->_em->clear(); + + /** @var DDC3346Author[] $authors */ + $authors = $this->_em->getRepository('Doctrine\Tests\Models\DDC3346\DDC3346Author')->findBy( + array('username' => "bwoogy"), + null, + null, + 1 ); - $this->assertCount(2, $author->articles); + $this->assertCount(1, $authors); + $this->assertCount(2, $authors[0]->articles); } } From 6e3ad496e2a089900b2b42c742cad2d44a6a0002 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 23 Jan 2015 16:10:14 +0100 Subject: [PATCH 14/22] #1277 DDC-3346 DDC-3531 - constants over string references --- .../Tests/ORM/Functional/Ticket/DDC3346Test.php | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php index 7ae4fa70603..e02788c6959 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php @@ -14,12 +14,10 @@ public function setUp() { parent::setUp(); - $this->setUpEntitySchema( - array( - DDC3346Author::CLASSNAME, - DDC3346Article::CLASSNAME, - ) - ); + $this->setUpEntitySchema(array( + DDC3346Author::CLASSNAME, + DDC3346Article::CLASSNAME, + )); } public function testFindOneWithEagerFetchWillNotHydrateLimitedCollection() @@ -40,7 +38,7 @@ public function testFindOneWithEagerFetchWillNotHydrateLimitedCollection() $this->_em->clear(); /** @var DDC3346Author $author */ - $author = $this->_em->getRepository('Doctrine\Tests\Models\DDC3346\DDC3346Author')->findOneBy( + $author = $this->_em->getRepository(DDC3346Author::CLASSNAME)->findOneBy( array('username' => "bwoogy") ); @@ -65,7 +63,7 @@ public function testFindLimitedWithEagerFetchWillNotHydrateLimitedCollection() $this->_em->clear(); /** @var DDC3346Author[] $authors */ - $authors = $this->_em->getRepository('Doctrine\Tests\Models\DDC3346\DDC3346Author')->findBy( + $authors = $this->_em->getRepository(DDC3346Author::CLASSNAME)->findBy( array('username' => "bwoogy"), null, 1 @@ -93,7 +91,7 @@ public function testFindWithEagerFetchAndOffsetWillNotHydrateLimitedCollection() $this->_em->clear(); /** @var DDC3346Author[] $authors */ - $authors = $this->_em->getRepository('Doctrine\Tests\Models\DDC3346\DDC3346Author')->findBy( + $authors = $this->_em->getRepository(DDC3346Author::CLASSNAME)->findBy( array('username' => "bwoogy"), null, null, From 16f447d1accb4242b49fa6d6ff83775e2c5c7e88 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 23 Jan 2015 16:15:57 +0100 Subject: [PATCH 15/22] #1277 DDC-3346 DDC-3531 - correct usage of the model set (setUp/tearDown of model-related tables) --- .../Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php | 7 ++----- tests/Doctrine/Tests/OrmFunctionalTestCase.php | 9 +++++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php index e02788c6959..10e1309e39f 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php @@ -12,12 +12,9 @@ class DDC3346Test extends \Doctrine\Tests\OrmFunctionalTestCase { public function setUp() { - parent::setUp(); + $this->useModelSet('ddc3346'); - $this->setUpEntitySchema(array( - DDC3346Author::CLASSNAME, - DDC3346Article::CLASSNAME, - )); + parent::setUp(); } public function testFindOneWithEagerFetchWillNotHydrateLimitedCollection() diff --git a/tests/Doctrine/Tests/OrmFunctionalTestCase.php b/tests/Doctrine/Tests/OrmFunctionalTestCase.php index cfced6d61f1..f73ac54fcc8 100644 --- a/tests/Doctrine/Tests/OrmFunctionalTestCase.php +++ b/tests/Doctrine/Tests/OrmFunctionalTestCase.php @@ -193,6 +193,10 @@ abstract class OrmFunctionalTestCase extends OrmTestCase 'Doctrine\Tests\Models\DDC2504\DDC2504ChildClass', 'Doctrine\Tests\Models\DDC2504\DDC2504OtherClass', ), + 'ddc3346' => array( + 'Doctrine\Tests\Models\DDC3346\DDC3346Author', + 'Doctrine\Tests\Models\DDC3346\DDC3346Article', + ), 'quote' => array( 'Doctrine\Tests\Models\Quote\Address', 'Doctrine\Tests\Models\Quote\Group', @@ -399,6 +403,11 @@ protected function tearDown() $conn->executeUpdate('DELETE FROM cache_country'); } + if (isset($this->_usedModelSets['ddc3346'])) { + $conn->executeUpdate('DELETE FROM ddc3346_articles'); + $conn->executeUpdate('DELETE FROM ddc3346_users'); + } + if (isset($this->_usedModelSets['quote'])) { $conn->executeUpdate('DELETE FROM ' . $platform->quoteIdentifier("quote-address")); $conn->executeUpdate('DELETE FROM ' . $platform->quoteIdentifier("quote-group")); From 36bc448880de657ad4fbb0a9a0821ddad79d9c90 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 23 Jan 2015 16:19:15 +0100 Subject: [PATCH 16/22] #1277 DDC-3346 DDC-3531 - refactoring test code for simplicity/readability --- .../ORM/Functional/Ticket/DDC3346Test.php | 55 +++++-------------- 1 file changed, 15 insertions(+), 40 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php index 10e1309e39f..b2e62f9a626 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php @@ -15,25 +15,12 @@ public function setUp() $this->useModelSet('ddc3346'); parent::setUp(); + + $this->loadAuthorFixture(); } public function testFindOneWithEagerFetchWillNotHydrateLimitedCollection() { - $user = new DDC3346Author(); - $user->username = "bwoogy"; - - $article1 = new DDC3346Article(); - $article1->setAuthor($user); - - $article2 = new DDC3346Article(); - $article2->setAuthor($user); - - $this->_em->persist($user); - $this->_em->persist($article1); - $this->_em->persist($article2); - $this->_em->flush(); - $this->_em->clear(); - /** @var DDC3346Author $author */ $author = $this->_em->getRepository(DDC3346Author::CLASSNAME)->findOneBy( array('username' => "bwoogy") @@ -44,25 +31,24 @@ public function testFindOneWithEagerFetchWillNotHydrateLimitedCollection() public function testFindLimitedWithEagerFetchWillNotHydrateLimitedCollection() { - $user = new DDC3346Author(); - $user->username = "bwoogy"; - - $article1 = new DDC3346Article(); - $article1->setAuthor($user); - - $article2 = new DDC3346Article(); - $article2->setAuthor($user); + /** @var DDC3346Author[] $authors */ + $authors = $this->_em->getRepository(DDC3346Author::CLASSNAME)->findBy( + array('username' => "bwoogy"), + null, + 1 + ); - $this->_em->persist($user); - $this->_em->persist($article1); - $this->_em->persist($article2); - $this->_em->flush(); - $this->_em->clear(); + $this->assertCount(1, $authors); + $this->assertCount(2, $authors[0]->articles); + } + public function testFindWithEagerFetchAndOffsetWillNotHydrateLimitedCollection() + { /** @var DDC3346Author[] $authors */ $authors = $this->_em->getRepository(DDC3346Author::CLASSNAME)->findBy( array('username' => "bwoogy"), null, + null, 1 ); @@ -70,7 +56,7 @@ public function testFindLimitedWithEagerFetchWillNotHydrateLimitedCollection() $this->assertCount(2, $authors[0]->articles); } - public function testFindWithEagerFetchAndOffsetWillNotHydrateLimitedCollection() + private function loadAuthorFixture() { $user = new DDC3346Author(); $user->username = "bwoogy"; @@ -86,16 +72,5 @@ public function testFindWithEagerFetchAndOffsetWillNotHydrateLimitedCollection() $this->_em->persist($article2); $this->_em->flush(); $this->_em->clear(); - - /** @var DDC3346Author[] $authors */ - $authors = $this->_em->getRepository(DDC3346Author::CLASSNAME)->findBy( - array('username' => "bwoogy"), - null, - null, - 1 - ); - - $this->assertCount(1, $authors); - $this->assertCount(2, $authors[0]->articles); } } From 04a271a04ea53650d8cf8a6f54f91e1d966af6b7 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 23 Jan 2015 16:22:17 +0100 Subject: [PATCH 17/22] #1277 DDC-3346 DDC-3531 - refactoring test assets for readability --- .../Doctrine/Tests/Models/DDC3346/DDC3346Article.php | 11 +++++------ tests/Doctrine/Tests/Models/DDC3346/DDC3346Author.php | 7 +++++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/Doctrine/Tests/Models/DDC3346/DDC3346Article.php b/tests/Doctrine/Tests/Models/DDC3346/DDC3346Article.php index 127209dcbbd..dc8a876c512 100644 --- a/tests/Doctrine/Tests/Models/DDC3346/DDC3346Article.php +++ b/tests/Doctrine/Tests/Models/DDC3346/DDC3346Article.php @@ -8,21 +8,20 @@ */ class DDC3346Article { - const CLASSNAME = 'Doctrine\Tests\Models\DDC3346\DDC3346Article'; + const CLASSNAME = __CLASS__; + /** * @Id * @Column(type="integer") * @GeneratedValue(strategy="AUTO") */ public $id; + /** + * @var DDC3346Author + * * @ManyToOne(targetEntity="DDC3346Author", inversedBy="articles") * @JoinColumn(name="user_id", referencedColumnName="id") */ public $user; - - public function setAuthor(DDC3346Author $author) - { - $this->user = $author; - } } diff --git a/tests/Doctrine/Tests/Models/DDC3346/DDC3346Author.php b/tests/Doctrine/Tests/Models/DDC3346/DDC3346Author.php index a24d9a601ec..5229ee280a2 100644 --- a/tests/Doctrine/Tests/Models/DDC3346/DDC3346Author.php +++ b/tests/Doctrine/Tests/Models/DDC3346/DDC3346Author.php @@ -8,18 +8,21 @@ */ class DDC3346Author { - const CLASSNAME = 'Doctrine\Tests\Models\DDC3346\DDC3346Author'; + const CLASSNAME = __CLASS__; + /** * @Id @Column(type="integer") * @GeneratedValue */ public $id; + /** * @Column(type="string", length=255, unique=true) */ public $username; + /** * @OneToMany(targetEntity="DDC3346Article", mappedBy="user", fetch="EAGER", cascade={"detach"}) */ - public $articles; + public $articles = array(); } From 39a8941d1bc8b56ea2f63010df4f4d59c5271709 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 23 Jan 2015 16:22:39 +0100 Subject: [PATCH 18/22] #1277 DDC-3346 DDC-3531 - minor CS fixes/cleanups: avoiding setters --- .../ORM/Functional/Ticket/DDC3346Test.php | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php index b2e62f9a626..7aca1866a90 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php @@ -21,9 +21,9 @@ public function setUp() public function testFindOneWithEagerFetchWillNotHydrateLimitedCollection() { - /** @var DDC3346Author $author */ + /* @var DDC3346Author $author */ $author = $this->_em->getRepository(DDC3346Author::CLASSNAME)->findOneBy( - array('username' => "bwoogy") + array('username' => 'bwoogy') ); $this->assertCount(2, $author->articles); @@ -31,9 +31,9 @@ public function testFindOneWithEagerFetchWillNotHydrateLimitedCollection() public function testFindLimitedWithEagerFetchWillNotHydrateLimitedCollection() { - /** @var DDC3346Author[] $authors */ + /* @var DDC3346Author[] $authors */ $authors = $this->_em->getRepository(DDC3346Author::CLASSNAME)->findBy( - array('username' => "bwoogy"), + array('username' => 'bwoogy'), null, 1 ); @@ -44,9 +44,9 @@ public function testFindLimitedWithEagerFetchWillNotHydrateLimitedCollection() public function testFindWithEagerFetchAndOffsetWillNotHydrateLimitedCollection() { - /** @var DDC3346Author[] $authors */ + /* @var DDC3346Author[] $authors */ $authors = $this->_em->getRepository(DDC3346Author::CLASSNAME)->findBy( - array('username' => "bwoogy"), + array('username' => 'bwoogy'), null, null, 1 @@ -58,14 +58,13 @@ public function testFindWithEagerFetchAndOffsetWillNotHydrateLimitedCollection() private function loadAuthorFixture() { - $user = new DDC3346Author(); - $user->username = "bwoogy"; - + $user = new DDC3346Author(); $article1 = new DDC3346Article(); - $article1->setAuthor($user); - $article2 = new DDC3346Article(); - $article2->setAuthor($user); + + $user->username = 'bwoogy'; + $article1->user = $user; + $article2->user = $user; $this->_em->persist($user); $this->_em->persist($article1); From 186c59305894b5969c9eb7c62ddbbaef55574a0f Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 23 Jan 2015 16:23:11 +0100 Subject: [PATCH 19/22] #1277 DDC-3346 DDC-3531 - proper bi-directional association setup --- .../Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php index 7aca1866a90..c7b89813a6a 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php @@ -62,9 +62,11 @@ private function loadAuthorFixture() $article1 = new DDC3346Article(); $article2 = new DDC3346Article(); - $user->username = 'bwoogy'; - $article1->user = $user; - $article2->user = $user; + $user->username = 'bwoogy'; + $article1->user = $user; + $article2->user = $user; + $user->articles[] = $article1; + $user->articles[] = $article2; $this->_em->persist($user); $this->_em->persist($article1); From dff365318d5cc4af31f37452ef593dca0def1c8f Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 23 Jan 2015 17:03:47 +0100 Subject: [PATCH 20/22] #1277 DDC-3346 DDC-3531 - enforcing `0` offset to avoid persisting more than 1 row --- tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php index c7b89813a6a..ba286da24f2 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3346Test.php @@ -49,7 +49,7 @@ public function testFindWithEagerFetchAndOffsetWillNotHydrateLimitedCollection() array('username' => 'bwoogy'), null, null, - 1 + 0 // using an explicitly defined offset ); $this->assertCount(1, $authors); From 97ea6a7d85ceb2695dc02bd0e2d102215e851f41 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 24 Jan 2015 14:38:58 +0100 Subject: [PATCH 21/22] #1277 DDC-3346 - removing array-based persister context handling (better to just use private props) --- .../Entity/BasicEntityPersister.php | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php index a1ad364e052..c16d3101176 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php @@ -178,14 +178,19 @@ class BasicEntityPersister implements EntityPersister private $identifierFlattener; /** - * @var CachedPersisterContext[] + * @var CachedPersisterContext */ - protected $cachedPersisterContexts = []; + protected $currentPersisterContext; /** * @var CachedPersisterContext */ - protected $currentPersisterContext; + private $limitsHandlingContext; + + /** + * @var CachedPersisterContext + */ + private $noLimitsContext; /** * Initializes a new BasicEntityPersister that uses the given EntityManager @@ -196,18 +201,18 @@ class BasicEntityPersister implements EntityPersister */ public function __construct(EntityManagerInterface $em, ClassMetadata $class) { - $this->em = $em; - $this->class = $class; - $this->conn = $em->getConnection(); - $this->platform = $this->conn->getDatabasePlatform(); - $this->quoteStrategy = $em->getConfiguration()->getQuoteStrategy(); - $this->identifierFlattener = new IdentifierFlattener($em->getUnitOfWork(), $em->getMetadataFactory()); - $this->cachedPersisterContexts['noLimits'] = $this->currentPersisterContext = new CachedPersisterContext( + $this->em = $em; + $this->class = $class; + $this->conn = $em->getConnection(); + $this->platform = $this->conn->getDatabasePlatform(); + $this->quoteStrategy = $em->getConfiguration()->getQuoteStrategy(); + $this->identifierFlattener = new IdentifierFlattener($em->getUnitOfWork(), $em->getMetadataFactory()); + $this->noLimitsContext = $this->currentPersisterContext = new CachedPersisterContext( $class, new Query\ResultSetMapping(), false ); - $this->cachedPersisterContexts['withLimits'] = new CachedPersisterContext( + $this->limitsHandlingContext = new CachedPersisterContext( $class, new Query\ResultSetMapping(), true @@ -1966,11 +1971,11 @@ protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targ protected function switchPersisterContext($offset, $limit) { if (null === $offset && null === $limit) { - $this->currentPersisterContext = $this->cachedPersisterContexts['noLimits']; + $this->currentPersisterContext = $this->noLimitsContext; return; } - $this->currentPersisterContext = $this->cachedPersisterContexts['withLimits']; + $this->currentPersisterContext = $this->limitsHandlingContext; } } From d4b278c80989854a65f80d0730970464e067bdc4 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sun, 25 Jan 2015 05:03:19 +0100 Subject: [PATCH 22/22] #1277 DDC-3346 - removing leftover comments --- lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php | 2 -- lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php | 1 - 2 files changed, 3 deletions(-) diff --git a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php index c16d3101176..a3f35f4404e 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php @@ -1180,7 +1180,6 @@ protected final function getOrderBySQL(array $orderBy, $baseTableAlias) */ protected function getSelectColumnsSQL() { - //if ( ! $hasLimitClause && $this->selectColumnListSql !== null) { if ($this->currentPersisterContext->selectColumnListSql !== null) { return $this->currentPersisterContext->selectColumnListSql; } @@ -1206,7 +1205,6 @@ protected function getSelectColumnsSQL() $isAssocToOneInverseSide = $assoc['type'] & ClassMetadata::TO_ONE && ! $assoc['isOwningSide']; $isAssocFromOneEager = $assoc['type'] !== ClassMetadata::MANY_TO_MANY && $assoc['fetch'] === ClassMetadata::FETCH_EAGER; - //if ($hasLimitClause || ! ($isAssocFromOneEager || $isAssocToOneInverseSide)) { if ( ! ($isAssocFromOneEager || $isAssocToOneInverseSide)) { continue; } diff --git a/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php b/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php index 5d259e4af73..a5bd84348cf 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php @@ -427,7 +427,6 @@ protected function getSelectColumnsSQL() } $columnList = array(); - //$this->currentPersisterContext->rsm = new ResultSetMapping(); $discrColumn = $this->class->discriminatorColumn['name']; $baseTableAlias = $this->getSQLTableAlias($this->class->name); $resultColumnName = $this->platform->getSQLResultCasing($discrColumn);