1
0
mirror of synced 2025-01-31 04:21:44 +03:00

#1277 DDC-3346 DDC-3531 - moved resultsetmapping into the newly created CachedPersisterContext

This commit is contained in:
Marco Pivetta 2015-01-22 17:58:56 +01:00
parent 981cebbf4c
commit 4c62d3bfda
5 changed files with 158 additions and 34 deletions

View File

@ -66,7 +66,7 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
$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 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
{
$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;
}

View File

@ -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 <tt>BasicEntityPersister</tt> that uses the given EntityManager
* and persists instances of the class described by the given ClassMetadata descriptor.
@ -231,6 +227,10 @@ class BasicEntityPersister implements EntityPersister
$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 @@ class BasicEntityPersister implements EntityPersister
*/
public function getResultSetMapping()
{
return $this->rsm;
return $this->cachedPersisterContexts['noLimits']->rsm;
}
/**
@ -720,7 +720,7 @@ class BasicEntityPersister implements EntityPersister
}
$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 @@ class BasicEntityPersister implements EntityPersister
$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 @@ class BasicEntityPersister implements EntityPersister
$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 @@ class BasicEntityPersister implements EntityPersister
$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 @@ class BasicEntityPersister implements EntityPersister
*/
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 @@ class BasicEntityPersister implements EntityPersister
*/
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 @@ class BasicEntityPersister implements EntityPersister
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 @@ class BasicEntityPersister implements EntityPersister
* 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 @@ class BasicEntityPersister implements EntityPersister
$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 @@ class BasicEntityPersister implements EntityPersister
}
$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 @@ class BasicEntityPersister implements EntityPersister
$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 @@ class BasicEntityPersister implements EntityPersister
. '.' . $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 @@ class BasicEntityPersister implements EntityPersister
$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));

View File

@ -0,0 +1,121 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
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 <ocramius@gmail.com>
*/
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;
}
}

View File

@ -425,14 +425,14 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
}
$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) {

View File

@ -63,8 +63,8 @@ class SingleTablePersister extends AbstractEntityInheritancePersister
$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) {