[2.0] Further cleanups. Started eager loading support.
This commit is contained in:
parent
b3d110bac4
commit
49434b0322
@ -423,6 +423,8 @@ abstract class AbstractQuery
|
|||||||
*/
|
*/
|
||||||
public function execute($params = array(), $hydrationMode = null)
|
public function execute($params = array(), $hydrationMode = null)
|
||||||
{
|
{
|
||||||
|
// If there are still pending insertions in the UnitOfWork we need to flush
|
||||||
|
// in order to guarantee a correct result.
|
||||||
if ($this->_em->getUnitOfWork()->hasPendingInsertions()) {
|
if ($this->_em->getUnitOfWork()->hasPendingInsertions()) {
|
||||||
$this->_em->flush();
|
$this->_em->flush();
|
||||||
}
|
}
|
||||||
@ -442,25 +444,24 @@ abstract class AbstractQuery
|
|||||||
if ($cached === false) {
|
if ($cached === false) {
|
||||||
// Cache miss.
|
// Cache miss.
|
||||||
$result = $this->_doExecute($params);
|
$result = $this->_doExecute($params);
|
||||||
$queryResult = CacheHandler::fromResultSet($this, $result);
|
$cacheDriver->save($hash, serialize($result), $this->_resultCacheTTL);
|
||||||
$cacheDriver->save($hash, $queryResult->toCachedForm(), $this->_resultCacheTTL);
|
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
} else {
|
} else {
|
||||||
// Cache hit.
|
// Cache hit.
|
||||||
$queryResult = CacheHandler::fromCachedResult($this, $cached);
|
return unserialize($cached);
|
||||||
|
|
||||||
return $queryResult->getResultSet();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $this->_doExecute($params);
|
$stmt = $this->_doExecute($params);
|
||||||
|
|
||||||
if (is_integer($stmt)) {
|
if (is_numeric($stmt)) {
|
||||||
return $stmt;
|
return $stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->_em->getHydrator($this->_hydrationMode)->hydrateAll($stmt, $this->_resultSetMapping);
|
return $this->_em->getHydrator($this->_hydrationMode)->hydrateAll(
|
||||||
|
$stmt, $this->_resultSetMapping, $this->_hints
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -56,6 +56,9 @@ abstract class AbstractHydrator
|
|||||||
/** @var Statement The statement that provides the data to hydrate. */
|
/** @var Statement The statement that provides the data to hydrate. */
|
||||||
protected $_stmt;
|
protected $_stmt;
|
||||||
|
|
||||||
|
/** @var array The query hints. */
|
||||||
|
protected $_hints;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a new instance of a class derived from <tt>AbstractHydrator</tt>.
|
* Initializes a new instance of a class derived from <tt>AbstractHydrator</tt>.
|
||||||
*
|
*
|
||||||
@ -90,10 +93,11 @@ abstract class AbstractHydrator
|
|||||||
* @param object $resultSetMapping
|
* @param object $resultSetMapping
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function hydrateAll($stmt, $resultSetMapping)
|
public function hydrateAll($stmt, $resultSetMapping, array $hints = array())
|
||||||
{
|
{
|
||||||
$this->_stmt = $stmt;
|
$this->_stmt = $stmt;
|
||||||
$this->_rsm = $resultSetMapping;
|
$this->_rsm = $resultSetMapping;
|
||||||
|
$this->_hints = $hints;
|
||||||
$this->_prepare();
|
$this->_prepare();
|
||||||
$result = $this->_hydrateAll();
|
$result = $this->_hydrateAll();
|
||||||
$this->_cleanup();
|
$this->_cleanup();
|
||||||
|
@ -23,6 +23,7 @@ namespace Doctrine\ORM\Internal\Hydration;
|
|||||||
|
|
||||||
use Doctrine\DBAL\Connection;
|
use Doctrine\DBAL\Connection;
|
||||||
use Doctrine\ORM\PersistentCollection;
|
use Doctrine\ORM\PersistentCollection;
|
||||||
|
use Doctrine\ORM\Query;
|
||||||
use Doctrine\Common\Collections\Collection;
|
use Doctrine\Common\Collections\Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -39,7 +40,6 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
/* Class entries */
|
/* Class entries */
|
||||||
private $_ce = array();
|
private $_ce = array();
|
||||||
private $_discriminatorMap = array();
|
private $_discriminatorMap = array();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following parts are reinitialized on every hydration run.
|
* The following parts are reinitialized on every hydration run.
|
||||||
*/
|
*/
|
||||||
@ -61,7 +61,8 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
protected function _prepare()
|
protected function _prepare()
|
||||||
{
|
{
|
||||||
$this->_isSimpleQuery = count($this->_rsm->aliasMap) <= 1;
|
$this->_isSimpleQuery = count($this->_rsm->aliasMap) <= 1;
|
||||||
$this->_allowPartialObjects = $this->_em->getConfiguration()->getAllowPartialObjects();
|
$this->_allowPartialObjects = $this->_em->getConfiguration()->getAllowPartialObjects()
|
||||||
|
|| isset($this->_hints[Query::HINT_FORCE_PARTIAL_LOAD]);
|
||||||
$this->_identifierMap = array();
|
$this->_identifierMap = array();
|
||||||
$this->_resultPointers = array();
|
$this->_resultPointers = array();
|
||||||
$this->_idTemplate = array();
|
$this->_idTemplate = array();
|
||||||
@ -226,6 +227,13 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an entity instance.
|
||||||
|
*
|
||||||
|
* @param $data The instance data.
|
||||||
|
* @param $dqlAlias The DQL alias of the entity's class.
|
||||||
|
* @return object The entity.
|
||||||
|
*/
|
||||||
private function getEntity(array $data, $dqlAlias)
|
private function getEntity(array $data, $dqlAlias)
|
||||||
{
|
{
|
||||||
$className = $this->_rsm->aliasMap[$dqlAlias];
|
$className = $this->_rsm->aliasMap[$dqlAlias];
|
||||||
@ -234,25 +242,28 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
$className = $this->_discriminatorMap[$className][$data[$discrColumn]];
|
$className = $this->_discriminatorMap[$className][$data[$discrColumn]];
|
||||||
unset($data[$discrColumn]);
|
unset($data[$discrColumn]);
|
||||||
}
|
}
|
||||||
$entity = $this->_uow->createEntity($className, $data);
|
$entity = $this->_uow->createEntity($className, $data, $this->_hints);
|
||||||
|
|
||||||
// Properly initialize any unfetched associations, if partial objects are not allowed.
|
// Properly initialize any unfetched associations, if partial objects are not allowed.
|
||||||
if ( ! $this->_allowPartialObjects) {
|
if ( ! $this->_allowPartialObjects) {
|
||||||
foreach ($this->_ce[$className]->associationMappings as $field => $assoc) {
|
foreach ($this->_ce[$className]->associationMappings as $field => $assoc) {
|
||||||
if ( ! isset($this->_fetchedAssociations[$className][$field])) {
|
if ( ! isset($this->_fetchedAssociations[$className][$field])) {
|
||||||
if ($assoc->isOneToOne()) {
|
if ($assoc->isOneToOne()) {
|
||||||
|
$joinColumns = array();
|
||||||
|
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
|
||||||
|
$joinColumns[$srcColumn] = $data[$assoc->joinColumnFieldNames[$srcColumn]];
|
||||||
|
}
|
||||||
if ($assoc->isLazilyFetched()) {
|
if ($assoc->isLazilyFetched()) {
|
||||||
$joinColumnsValues = array();
|
|
||||||
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
|
|
||||||
$joinColumnsValues[$srcColumn] = $data[$assoc->joinColumnFieldNames[$srcColumn]];
|
|
||||||
}
|
|
||||||
// Inject proxy
|
// Inject proxy
|
||||||
$proxy = $this->_em->getProxyFactory()->getAssociationProxy($entity, $assoc, $joinColumnsValues);
|
$this->_ce[$className]->reflFields[$field]->setValue($entity,
|
||||||
$this->_ce[$className]->reflFields[$field]->setValue($entity, $proxy);
|
$this->_em->getProxyFactory()->getAssociationProxy($entity, $assoc, $joinColumns));
|
||||||
} else {
|
} else {
|
||||||
//TODO: Schedule for eager fetching
|
// Eager load
|
||||||
|
//TODO: Allow more efficient and configurable batching of these loads
|
||||||
|
$assoc->load($entity, new $className, $this->_em, $joinColumns);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
//TODO: Eager load
|
||||||
// Inject collection
|
// Inject collection
|
||||||
$this->_ce[$className]->reflFields[$field]
|
$this->_ce[$className]->reflFields[$field]
|
||||||
->setValue($entity, new PersistentCollection(
|
->setValue($entity, new PersistentCollection(
|
||||||
@ -280,6 +291,7 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
$class->reflFields[$property]->setValue($entity1, $entity2);
|
$class->reflFields[$property]->setValue($entity1, $entity2);
|
||||||
$this->_uow->setOriginalEntityProperty(spl_object_hash($entity1), $property, $entity2);
|
$this->_uow->setOriginalEntityProperty(spl_object_hash($entity1), $property, $entity2);
|
||||||
$relation = $class->associationMappings[$property];
|
$relation = $class->associationMappings[$property];
|
||||||
|
|
||||||
if ($relation->isOneToOne()) {
|
if ($relation->isOneToOne()) {
|
||||||
$targetClass = $this->_ce[$relation->targetEntityName];
|
$targetClass = $this->_ce[$relation->targetEntityName];
|
||||||
if ($relation->isOwningSide) {
|
if ($relation->isOwningSide) {
|
||||||
|
@ -29,7 +29,7 @@ final class Entity extends \Doctrine\Common\Annotations\Annotation {
|
|||||||
final class InheritanceType extends \Doctrine\Common\Annotations\Annotation {}
|
final class InheritanceType extends \Doctrine\Common\Annotations\Annotation {}
|
||||||
final class DiscriminatorColumn extends \Doctrine\Common\Annotations\Annotation {
|
final class DiscriminatorColumn extends \Doctrine\Common\Annotations\Annotation {
|
||||||
public $name;
|
public $name;
|
||||||
//public $fieldName; // field name used in non-object hydration (array/scalar)
|
public $fieldName; // field name used in non-object hydration (array/scalar)
|
||||||
public $type;
|
public $type;
|
||||||
public $length;
|
public $length;
|
||||||
}
|
}
|
||||||
@ -43,7 +43,7 @@ final class GeneratedValue extends \Doctrine\Common\Annotations\Annotation {
|
|||||||
final class Version extends \Doctrine\Common\Annotations\Annotation {}
|
final class Version extends \Doctrine\Common\Annotations\Annotation {}
|
||||||
final class JoinColumn extends \Doctrine\Common\Annotations\Annotation {
|
final class JoinColumn extends \Doctrine\Common\Annotations\Annotation {
|
||||||
public $name;
|
public $name;
|
||||||
//public $fieldName; // field name used in non-object hydration (array/scalar)
|
public $fieldName; // field name used in non-object hydration (array/scalar)
|
||||||
public $referencedColumnName;
|
public $referencedColumnName;
|
||||||
public $unique = false;
|
public $unique = false;
|
||||||
public $nullable = true;
|
public $nullable = true;
|
||||||
|
@ -161,7 +161,7 @@ class OneToOneMapping extends AssociationMapping
|
|||||||
* @param object $targetEntity the entity to load data in
|
* @param object $targetEntity the entity to load data in
|
||||||
* @param EntityManager $em
|
* @param EntityManager $em
|
||||||
* @param array $joinColumnValues values of the join columns of $sourceEntity. There are no fields
|
* @param array $joinColumnValues values of the join columns of $sourceEntity. There are no fields
|
||||||
* to store this data in $sourceEntity
|
* to store this data in $sourceEntity
|
||||||
*/
|
*/
|
||||||
public function load($sourceEntity, $targetEntity, $em, array $joinColumnValues)
|
public function load($sourceEntity, $targetEntity, $em, array $joinColumnValues)
|
||||||
{
|
{
|
||||||
@ -179,10 +179,12 @@ class OneToOneMapping extends AssociationMapping
|
|||||||
$conditions[$targetKeyColumn] = $joinColumnValues[$sourceKeyColumn];
|
$conditions[$targetKeyColumn] = $joinColumnValues[$sourceKeyColumn];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($targetClass->hasInverseAssociationMapping($this->sourceFieldName)) {
|
|
||||||
$targetClass->setFieldValue(
|
$targetEntity = $em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->load($conditions, $targetEntity);
|
||||||
$targetEntity,
|
|
||||||
$targetClass->inverseMappings[$this->sourceFieldName]->getSourceFieldName(),
|
if ($targetEntity !== null && $targetClass->hasInverseAssociationMapping($this->sourceFieldName)) {
|
||||||
|
$targetClass->setFieldValue($targetEntity,
|
||||||
|
$targetClass->inverseMappings[$this->sourceFieldName]->sourceFieldName,
|
||||||
$sourceEntity);
|
$sourceEntity);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -195,10 +197,11 @@ class OneToOneMapping extends AssociationMapping
|
|||||||
$conditions[$sourceKeyColumn] = $joinColumnValues[$targetKeyColumn];
|
$conditions[$sourceKeyColumn] = $joinColumnValues[$targetKeyColumn];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$targetEntity = $em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->load($conditions, $targetEntity);
|
||||||
|
|
||||||
$targetClass->setFieldValue($targetEntity, $this->mappedByFieldName, $sourceEntity);
|
$targetClass->setFieldValue($targetEntity, $this->mappedByFieldName, $sourceEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
$em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->load($conditions, $targetEntity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function _getPrivateValue(ClassMetadata $class, $entity, $column)
|
protected function _getPrivateValue(ClassMetadata $class, $entity, $column)
|
||||||
|
@ -405,7 +405,8 @@ class StandardEntityPersister
|
|||||||
*
|
*
|
||||||
* @param array $criteria The criteria by which to load the entity.
|
* @param array $criteria The criteria by which to load the entity.
|
||||||
* @param object $entity The entity to load the data into. If not specified,
|
* @param object $entity The entity to load the data into. If not specified,
|
||||||
* a new entity is created.
|
* a new entity is created.
|
||||||
|
* @return The loaded entity instance or NULL if the entity/the data can not be found.
|
||||||
*/
|
*/
|
||||||
public function load(array $criteria, $entity = null)
|
public function load(array $criteria, $entity = null)
|
||||||
{
|
{
|
||||||
@ -413,7 +414,14 @@ class StandardEntityPersister
|
|||||||
$stmt->execute(array_values($criteria));
|
$stmt->execute(array_values($criteria));
|
||||||
$data = array();
|
$data = array();
|
||||||
$joinColumnValues = array();
|
$joinColumnValues = array();
|
||||||
foreach ($stmt->fetch(Connection::FETCH_ASSOC) as $column => $value) {
|
$result = $stmt->fetch(Connection::FETCH_ASSOC);
|
||||||
|
$stmt->closeCursor();
|
||||||
|
|
||||||
|
if ($result === false) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($result as $column => $value) {
|
||||||
if (isset($this->_class->fieldNames[$column])) {
|
if (isset($this->_class->fieldNames[$column])) {
|
||||||
$fieldName = $this->_class->fieldNames[$column];
|
$fieldName = $this->_class->fieldNames[$column];
|
||||||
$data[$fieldName] = Type::getType($this->_class->getTypeOfField($fieldName))
|
$data[$fieldName] = Type::getType($this->_class->getTypeOfField($fieldName))
|
||||||
@ -422,7 +430,6 @@ class StandardEntityPersister
|
|||||||
$joinColumnValues[$column] = $value;
|
$joinColumnValues[$column] = $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$stmt->closeCursor();
|
|
||||||
|
|
||||||
if ($entity === null) {
|
if ($entity === null) {
|
||||||
$entity = $this->_em->getUnitOfWork()->createEntity($this->_entityName, $data);
|
$entity = $this->_em->getUnitOfWork()->createEntity($this->_entityName, $data);
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
namespace Doctrine\ORM;
|
namespace Doctrine\ORM;
|
||||||
|
|
||||||
use Doctrine\ORM\Query\CacheHandler;
|
|
||||||
use Doctrine\ORM\Query\Parser;
|
use Doctrine\ORM\Query\Parser;
|
||||||
use Doctrine\ORM\Query\QueryException;
|
use Doctrine\ORM\Query\QueryException;
|
||||||
|
|
||||||
@ -38,11 +37,11 @@ use Doctrine\ORM\Query\QueryException;
|
|||||||
*/
|
*/
|
||||||
final class Query extends AbstractQuery
|
final class Query extends AbstractQuery
|
||||||
{
|
{
|
||||||
|
/* Query STATES */
|
||||||
/**
|
/**
|
||||||
* A query object is in CLEAN state when it has NO unparsed/unprocessed DQL parts.
|
* A query object is in CLEAN state when it has NO unparsed/unprocessed DQL parts.
|
||||||
*/
|
*/
|
||||||
const STATE_CLEAN = 1;
|
const STATE_CLEAN = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A query object is in state DIRTY when it has DQL parts that have not yet been
|
* A query object is in state DIRTY when it has DQL parts that have not yet been
|
||||||
* parsed/processed. This is automatically defined as DIRTY when addDqlQueryPart
|
* parsed/processed. This is automatically defined as DIRTY when addDqlQueryPart
|
||||||
@ -50,6 +49,32 @@ final class Query extends AbstractQuery
|
|||||||
*/
|
*/
|
||||||
const STATE_DIRTY = 2;
|
const STATE_DIRTY = 2;
|
||||||
|
|
||||||
|
/* Query HINTS */
|
||||||
|
/**
|
||||||
|
* The refresh hint turns any query into a refresh query with the result that
|
||||||
|
* any local changes in entities are overridden with the fetched values.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const HINT_REFRESH = 'doctrine.refresh';
|
||||||
|
/**
|
||||||
|
* The forcePartialLoad query hint forces a particular query to return
|
||||||
|
* partial objects when partial objects in general are disallowed in the
|
||||||
|
* configuration.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const HINT_FORCE_PARTIAL_LOAD = 'doctrine.forcePartialLoad';
|
||||||
|
/**
|
||||||
|
* The includeMetaColumns query hint causes meta columns like foreign keys and
|
||||||
|
* discriminator columns to be selected and returned as part of the query result.
|
||||||
|
*
|
||||||
|
* This hint does only apply to non-object queries.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const HINT_INCLUDE_META_COLUMNS = 'doctrine.includeMetaColumns';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var integer $_state The current state of this query.
|
* @var integer $_state The current state of this query.
|
||||||
*/
|
*/
|
||||||
|
@ -1,58 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* $Id$
|
|
||||||
*
|
|
||||||
* 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 LGPL. For more information, see
|
|
||||||
* <http://www.doctrine-project.org>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Doctrine\ORM\Query;
|
|
||||||
|
|
||||||
use Doctrine\Common\DoctrineException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Doctrine_ORM_Query_AbstractResult
|
|
||||||
*
|
|
||||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
|
||||||
* @link www.doctrine-project.com
|
|
||||||
* @since 2.0
|
|
||||||
* @version $Revision: 1393 $
|
|
||||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
|
||||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
|
||||||
* @author Roman Borschel <roman@code-factory.org>
|
|
||||||
*/
|
|
||||||
abstract class AbstractResult
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var mixed $_data The actual data to be stored. Can be an array, a string or an integer.
|
|
||||||
*/
|
|
||||||
protected $_data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns this object in serialized format, revertable using fromCached*.
|
|
||||||
*
|
|
||||||
* @return string Serialized cached item.
|
|
||||||
*/
|
|
||||||
public function toCachedForm()
|
|
||||||
{
|
|
||||||
return serialize(array(
|
|
||||||
$this->_data,
|
|
||||||
$this->getQueryComponents(),
|
|
||||||
$this->getTableAliasMap(),
|
|
||||||
$this->getEnumParams()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,146 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* $Id: Cache.php 3938 2008-03-06 19:36:50Z romanb $
|
|
||||||
*
|
|
||||||
* 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 LGPL. For more information, see
|
|
||||||
* <http://www.doctrine-project.org>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Doctrine\ORM\Query;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Doctrine\ORM\Query\CacheHandler
|
|
||||||
*
|
|
||||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
|
||||||
* @link www.doctrine-project.com
|
|
||||||
* @since 2.0
|
|
||||||
* @version $Revision: 1393 $
|
|
||||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
|
||||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
|
||||||
*
|
|
||||||
* @todo Re-document this class
|
|
||||||
*/
|
|
||||||
abstract class CacheHandler
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Static factory method. Receives a Doctrine_ORM_Query object and generates
|
|
||||||
* the object after processing queryComponents. Table aliases are retrieved
|
|
||||||
* directly from Doctrine_ORM_Query_Parser.
|
|
||||||
*
|
|
||||||
* @param mixed $result Data to be stored.
|
|
||||||
* @param Doctrine_ORM_Query_ParserResult $parserResult Parser results that enables to have important data retrieved.
|
|
||||||
*/
|
|
||||||
public static function fromResultSet($result, $parserResult)
|
|
||||||
{
|
|
||||||
$queryComponents = array();
|
|
||||||
|
|
||||||
foreach ($parserResult->getQueryComponents() as $alias => $components) {
|
|
||||||
if ( ! isset($components['parent'])) {
|
|
||||||
$queryComponents[$alias][] = $components['mapper']->getComponentName();
|
|
||||||
//$queryComponents[$alias][] = $components['mapper']->getComponentName();
|
|
||||||
} else {
|
|
||||||
$queryComponents[$alias][] = $components['parent'] . '.' . $components['relation']->getAlias();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($components['agg'])) {
|
|
||||||
$queryComponents[$alias][] = $components['agg'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($components['map'])) {
|
|
||||||
$queryComponents[$alias][] = $components['map'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new QueryResult(
|
|
||||||
$result,
|
|
||||||
$queryComponents,
|
|
||||||
$parserResult->getTableAliasMap(),
|
|
||||||
$parserResult->getEnumParams()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Static factory method. Receives a Doctrine_ORM_Query object and a cached data.
|
|
||||||
* It handles the cache and generates the object after processing queryComponents.
|
|
||||||
* Table aliases are retrieved from cache.
|
|
||||||
*
|
|
||||||
* @param Doctrine_ORM_Query $query Doctrine_ORM_Query_Object related to this cache item.
|
|
||||||
* @param mixed $cached Cached data.
|
|
||||||
*/
|
|
||||||
public static function fromCachedResult($query, $cached = false)
|
|
||||||
{
|
|
||||||
$cached = unserialize($cached);
|
|
||||||
|
|
||||||
return new QueryResult(
|
|
||||||
$cached[0],
|
|
||||||
self::_getQueryComponents($cached[1]),
|
|
||||||
$cached[2],
|
|
||||||
$cached[3]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Static factory method. Receives a Doctrine_ORM_Query object and a cached data.
|
|
||||||
* It handles the cache and generates the object after processing queryComponents.
|
|
||||||
* Table aliases are retrieved from cache.
|
|
||||||
*
|
|
||||||
* @param Doctrine_ORM_Query $query Doctrine_ORM_Query_Object related to this cache item.
|
|
||||||
* @param mixed $cached Cached data.
|
|
||||||
*/
|
|
||||||
public static function fromCachedQuery($query, $cached = false)
|
|
||||||
{
|
|
||||||
$cached = unserialize($cached);
|
|
||||||
|
|
||||||
return new ParserResult(
|
|
||||||
$cached[0],
|
|
||||||
self::_getQueryComponents($cached[1]),
|
|
||||||
$cached[2],
|
|
||||||
$cached[3]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @nodoc
|
|
||||||
*/
|
|
||||||
protected static function _getQueryComponents($query, $cachedQueryComponents)
|
|
||||||
{
|
|
||||||
$queryComponents = array();
|
|
||||||
|
|
||||||
foreach ($cachedQueryComponents as $alias => $components) {
|
|
||||||
$e = explode('.', $components[0]);
|
|
||||||
|
|
||||||
if (count($e) === 1) {
|
|
||||||
$queryComponents[$alias]['mapper'] = $query->getConnection()->getMapper($e[0]);
|
|
||||||
$queryComponents[$alias]['table'] = $queryComponents[$alias]['mapper']->getTable();
|
|
||||||
} else {
|
|
||||||
$queryComponents[$alias]['parent'] = $e[0];
|
|
||||||
$queryComponents[$alias]['relation'] = $queryComponents[$e[0]]['table']->getAssociation($e[1]);
|
|
||||||
$queryComponents[$alias]['mapper'] = $query->getConnection()->getMapper($queryComponents[$alias]['relation']->getTargetEntityName());
|
|
||||||
$queryComponents[$alias]['table'] = $queryComponents[$alias]['mapper']->getTable();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($v[1])) {
|
|
||||||
$queryComponents[$alias]['agg'] = $components[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($v[2])) {
|
|
||||||
$queryComponents[$alias]['map'] = $components[2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $queryComponents;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,112 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* $Id$
|
|
||||||
*
|
|
||||||
* 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 LGPL. For more information, see
|
|
||||||
* <http://www.phpdoctrine.org>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Doctrine\ORM\Query\Exec;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for SQL statement executors.
|
|
||||||
*
|
|
||||||
* @author Roman Borschel <roman@code-factory.org>
|
|
||||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
|
||||||
* @link http://www.phpdoctrine.org
|
|
||||||
* @since 2.0
|
|
||||||
* @version $Revision$
|
|
||||||
*/
|
|
||||||
abstract class AbstractExecutor implements \Serializable
|
|
||||||
{
|
|
||||||
protected $_sqlStatements;
|
|
||||||
|
|
||||||
public function __construct(\Doctrine\ORM\Query\AST\Node $AST, $sqlWalker)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the SQL statements that are executed by the executor.
|
|
||||||
*
|
|
||||||
* @return array All the SQL update statements.
|
|
||||||
*/
|
|
||||||
public function getSqlStatements()
|
|
||||||
{
|
|
||||||
return $this->_sqlStatements;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes all sql statements.
|
|
||||||
*
|
|
||||||
* @param Doctrine_Connection $conn The database connection that is used to execute the queries.
|
|
||||||
* @param array $params The parameters.
|
|
||||||
*/
|
|
||||||
abstract public function execute(\Doctrine\DBAL\Connection $conn, array $params);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory method.
|
|
||||||
* Creates an appropriate sql executor for the given AST.
|
|
||||||
*
|
|
||||||
* @param Doctrine_ORM_Query_AST $AST The root node of the AST.
|
|
||||||
* @return Doctrine_ORM_Query_SqlExecutor_Abstract The executor that is suitable for the given AST.
|
|
||||||
*/
|
|
||||||
public static function create(\Doctrine\ORM\Query\AST\Node $AST, $sqlWalker)
|
|
||||||
{
|
|
||||||
$isDeleteStatement = $AST instanceof \Doctrine\ORM\Query\AST\DeleteStatement;
|
|
||||||
$isUpdateStatement = $AST instanceof \Doctrine\ORM\Query\AST\UpdateStatement;
|
|
||||||
|
|
||||||
if ($isDeleteStatement) {
|
|
||||||
$primaryClass = $sqlWalker->getEntityManager()->getClassMetadata(
|
|
||||||
$AST->getDeleteClause()->getAbstractSchemaName()
|
|
||||||
);
|
|
||||||
if ($primaryClass->isInheritanceTypeJoined()) {
|
|
||||||
return new MultiTableDeleteExecutor($AST, $sqlWalker);
|
|
||||||
} else {
|
|
||||||
return new SingleTableDeleteUpdateExecutor($AST, $sqlWalker);
|
|
||||||
}
|
|
||||||
} else if ($isUpdateStatement) {
|
|
||||||
$primaryClass = $sqlWalker->getEntityManager()->getClassMetadata(
|
|
||||||
$AST->getUpdateClause()->getAbstractSchemaName()
|
|
||||||
);
|
|
||||||
if ($primaryClass->isInheritanceTypeJoined()) {
|
|
||||||
return new MultiTableUpdateExecutor($AST, $sqlWalker);
|
|
||||||
} else {
|
|
||||||
return new SingleTableDeleteUpdateExecutor($AST, $sqlWalker);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return new SingleSelectExecutor($AST, $sqlWalker);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serializes the sql statements of the executor.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function serialize()
|
|
||||||
{
|
|
||||||
return serialize($this->_sqlStatements);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reconstructs the executor with it's sql statements.
|
|
||||||
*/
|
|
||||||
public function unserialize($serialized)
|
|
||||||
{
|
|
||||||
$this->_sqlStatements = unserialize($serialized);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -19,29 +19,36 @@
|
|||||||
* <http://www.doctrine-project.org>.
|
* <http://www.doctrine-project.org>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Doctrine\ORM\Query;
|
namespace Doctrine\ORM\Query\Exec;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Doctrine_ORM_Query_QueryResult
|
* Base class for SQL statement executors.
|
||||||
*
|
*
|
||||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
* @author Roman Borschel <roman@code-factory.org>
|
||||||
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
|
|
||||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||||
* @link http://www.doctrine-project.org
|
* @link http://www.doctrine-project.org
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
* @version $Revision$
|
* @version $Revision$
|
||||||
*/
|
*/
|
||||||
class QueryResult extends AbstractResult
|
abstract class AbstractSqlExecutor
|
||||||
{
|
{
|
||||||
protected $_data;
|
protected $_sqlStatements;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns cached resultset.
|
* Gets the SQL statements that are executed by the executor.
|
||||||
*
|
*
|
||||||
* @return array Resultset.
|
* @return array All the SQL update statements.
|
||||||
*/
|
*/
|
||||||
public function getResultSet()
|
public function getSqlStatements()
|
||||||
{
|
{
|
||||||
return $this->_data;
|
return $this->_sqlStatements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes all sql statements.
|
||||||
|
*
|
||||||
|
* @param Doctrine_Connection $conn The database connection that is used to execute the queries.
|
||||||
|
* @param array $params The parameters.
|
||||||
|
*/
|
||||||
|
abstract public function execute(\Doctrine\DBAL\Connection $conn, array $params);
|
||||||
}
|
}
|
@ -33,7 +33,7 @@ use Doctrine\ORM\Query\AST;
|
|||||||
* @since 2.0
|
* @since 2.0
|
||||||
* @version $Revision$
|
* @version $Revision$
|
||||||
*/
|
*/
|
||||||
class MultiTableDeleteExecutor extends AbstractExecutor
|
class MultiTableDeleteExecutor extends AbstractSqlExecutor
|
||||||
{
|
{
|
||||||
private $_createTempTableSql;
|
private $_createTempTableSql;
|
||||||
private $_dropTempTableSql;
|
private $_dropTempTableSql;
|
||||||
|
@ -33,7 +33,7 @@ use Doctrine\ORM\Query\AST;
|
|||||||
* @since 2.0
|
* @since 2.0
|
||||||
* @version $Revision$
|
* @version $Revision$
|
||||||
*/
|
*/
|
||||||
class MultiTableUpdateExecutor extends AbstractExecutor
|
class MultiTableUpdateExecutor extends AbstractSqlExecutor
|
||||||
{
|
{
|
||||||
private $_createTempTableSql;
|
private $_createTempTableSql;
|
||||||
private $_dropTempTableSql;
|
private $_dropTempTableSql;
|
||||||
|
@ -30,11 +30,10 @@ namespace Doctrine\ORM\Query\Exec;
|
|||||||
* @link www.doctrine-project.org
|
* @link www.doctrine-project.org
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
class SingleSelectExecutor extends AbstractExecutor
|
class SingleSelectExecutor extends AbstractSqlExecutor
|
||||||
{
|
{
|
||||||
public function __construct(\Doctrine\ORM\Query\AST\SelectStatement $AST, $sqlWalker)
|
public function __construct(\Doctrine\ORM\Query\AST\SelectStatement $AST, $sqlWalker)
|
||||||
{
|
{
|
||||||
parent::__construct($AST, $sqlWalker);
|
|
||||||
$this->_sqlStatements = $sqlWalker->walkSelectStatement($AST);
|
$this->_sqlStatements = $sqlWalker->walkSelectStatement($AST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,11 +34,10 @@ use Doctrine\ORM\Query\AST;
|
|||||||
* @since 2.0
|
* @since 2.0
|
||||||
* @todo This is exactly the same as SingleSelectExecutor. Unify in SingleStatementExecutor.
|
* @todo This is exactly the same as SingleSelectExecutor. Unify in SingleStatementExecutor.
|
||||||
*/
|
*/
|
||||||
class SingleTableDeleteUpdateExecutor extends AbstractExecutor
|
class SingleTableDeleteUpdateExecutor extends AbstractSqlExecutor
|
||||||
{
|
{
|
||||||
public function __construct(AST\Node $AST, $sqlWalker)
|
public function __construct(AST\Node $AST, $sqlWalker)
|
||||||
{
|
{
|
||||||
parent::__construct($AST, $sqlWalker);
|
|
||||||
if ($AST instanceof AST\UpdateStatement) {
|
if ($AST instanceof AST\UpdateStatement) {
|
||||||
$this->_sqlStatements = $sqlWalker->walkUpdateStatement($AST);
|
$this->_sqlStatements = $sqlWalker->walkUpdateStatement($AST);
|
||||||
} else if ($AST instanceof AST\DeleteStatement) {
|
} else if ($AST instanceof AST\DeleteStatement) {
|
||||||
|
@ -189,7 +189,7 @@ class Parser
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Assign an SQL executor to the parser result
|
// Assign an SQL executor to the parser result
|
||||||
$this->_parserResult->setSqlExecutor(Exec\AbstractExecutor::create($AST, $sqlWalker));
|
$this->_parserResult->setSqlExecutor($sqlWalker->getExecutor($AST));
|
||||||
|
|
||||||
return $this->_parserResult;
|
return $this->_parserResult;
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ class ParserResult
|
|||||||
*
|
*
|
||||||
* @param AbstractExecutor $executor
|
* @param AbstractExecutor $executor
|
||||||
*/
|
*/
|
||||||
public function setSqlExecutor(\Doctrine\ORM\Query\Exec\AbstractExecutor $executor)
|
public function setSqlExecutor($executor)
|
||||||
{
|
{
|
||||||
$this->_sqlExecutor = $executor;
|
$this->_sqlExecutor = $executor;
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
namespace Doctrine\ORM\Query;
|
namespace Doctrine\ORM\Query;
|
||||||
|
|
||||||
|
use Doctrine\ORM\Query;
|
||||||
use Doctrine\ORM\Query\Parser;
|
use Doctrine\ORM\Query\Parser;
|
||||||
use Doctrine\ORM\Query\AST;
|
use Doctrine\ORM\Query\AST;
|
||||||
use Doctrine\Common\DoctrineException;
|
use Doctrine\Common\DoctrineException;
|
||||||
@ -33,6 +34,7 @@ use Doctrine\Common\DoctrineException;
|
|||||||
* @since 2.0
|
* @since 2.0
|
||||||
* @todo Code review for identifier quoting.
|
* @todo Code review for identifier quoting.
|
||||||
* @todo Code review for schema usage with table names.
|
* @todo Code review for schema usage with table names.
|
||||||
|
* (Prepend schema name to tables IF schema is defined AND platform supports them)
|
||||||
*/
|
*/
|
||||||
class SqlWalker implements TreeWalker
|
class SqlWalker implements TreeWalker
|
||||||
{
|
{
|
||||||
@ -51,7 +53,7 @@ class SqlWalker implements TreeWalker
|
|||||||
private $_em;
|
private $_em;
|
||||||
/** The Connection of the EntityManager. */
|
/** The Connection of the EntityManager. */
|
||||||
private $_conn;
|
private $_conn;
|
||||||
/** The parsed Query instance. */
|
/** The Query instance. */
|
||||||
private $_query;
|
private $_query;
|
||||||
private $_dqlToSqlAliasMap = array();
|
private $_dqlToSqlAliasMap = array();
|
||||||
/** Map of all components/classes that appear in the DQL query. */
|
/** Map of all components/classes that appear in the DQL query. */
|
||||||
@ -135,8 +137,9 @@ class SqlWalker implements TreeWalker
|
|||||||
$sql .= $AST->getOrderByClause() ? $this->walkOrderByClause($AST->getOrderByClause()) : '';
|
$sql .= $AST->getOrderByClause() ? $this->walkOrderByClause($AST->getOrderByClause()) : '';
|
||||||
|
|
||||||
$q = $this->getQuery();
|
$q = $this->getQuery();
|
||||||
$sql = $this->getConnection()->getDatabasePlatform()
|
$sql = $this->getConnection()->getDatabasePlatform()->modifyLimitQuery(
|
||||||
->modifyLimitQuery($sql, $q->getMaxResults(), $q->getFirstResult());
|
$sql, $q->getMaxResults(), $q->getFirstResult()
|
||||||
|
);
|
||||||
|
|
||||||
return $sql;
|
return $sql;
|
||||||
}
|
}
|
||||||
@ -163,17 +166,15 @@ class SqlWalker implements TreeWalker
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//if ($this->_query->getHydrationMode() == \Doctrine\ORM\Query::HYDRATE_OBJECT) {
|
|
||||||
if ($class->isInheritanceTypeSingleTable() || $class->isInheritanceTypeJoined()) {
|
if ($class->isInheritanceTypeSingleTable() || $class->isInheritanceTypeJoined()) {
|
||||||
$rootClass = $this->_em->getClassMetadata($class->rootEntityName);
|
$rootClass = $this->_em->getClassMetadata($class->rootEntityName);
|
||||||
$tblAlias = $this->getSqlTableAlias($rootClass->getTableName() . $dqlAlias);
|
$tblAlias = $this->getSqlTableAlias($rootClass->getTableName(), $dqlAlias);
|
||||||
$discrColumn = $rootClass->discriminatorColumn;
|
$discrColumn = $rootClass->discriminatorColumn;
|
||||||
$columnAlias = $this->getSqlColumnAlias($discrColumn['name']);
|
$columnAlias = $this->getSqlColumnAlias($discrColumn['name']);
|
||||||
$sql .= ", $tblAlias." . $discrColumn['name'] . ' AS ' . $columnAlias;
|
$sql .= ", $tblAlias." . $discrColumn['name'] . ' AS ' . $columnAlias;
|
||||||
$this->_rsm->setDiscriminatorColumn($dqlAlias, $columnAlias);
|
$this->_rsm->setDiscriminatorColumn($dqlAlias, $columnAlias);
|
||||||
$this->_rsm->addMetaResult($dqlAlias, $columnAlias, $discrColumn['fieldName']);
|
$this->_rsm->addMetaResult($dqlAlias, $columnAlias, $discrColumn['fieldName']);
|
||||||
}
|
}
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $sql;
|
return $sql;
|
||||||
@ -195,7 +196,7 @@ class SqlWalker implements TreeWalker
|
|||||||
$this->_currentRootAlias = $dqlAlias;
|
$this->_currentRootAlias = $dqlAlias;
|
||||||
$class = $rangeDecl->getClassMetadata();
|
$class = $rangeDecl->getClassMetadata();
|
||||||
|
|
||||||
$sql .= $class->getTableName() . ' ' . $this->getSqlTableAlias($class->getTableName() . $dqlAlias);
|
$sql .= $class->getTableName() . ' ' . $this->getSqlTableAlias($class->getTableName(), $dqlAlias);
|
||||||
|
|
||||||
if ($class->isInheritanceTypeJoined()) {
|
if ($class->isInheritanceTypeJoined()) {
|
||||||
$sql .= $this->_generateClassTableInheritanceJoins($class, $dqlAlias);
|
$sql .= $this->_generateClassTableInheritanceJoins($class, $dqlAlias);
|
||||||
@ -246,7 +247,7 @@ class SqlWalker implements TreeWalker
|
|||||||
$dqlAlias = $expr->getIdentificationVariable();
|
$dqlAlias = $expr->getIdentificationVariable();
|
||||||
$qComp = $this->_queryComponents[$dqlAlias];
|
$qComp = $this->_queryComponents[$dqlAlias];
|
||||||
$columnName = $qComp['metadata']->getColumnName($parts[0]);
|
$columnName = $qComp['metadata']->getColumnName($parts[0]);
|
||||||
$sql = $this->getSqlTableAlias($qComp['metadata']->getTableName() . $dqlAlias) . '.' . $columnName;
|
$sql = $this->getSqlTableAlias($qComp['metadata']->getTableName(), $dqlAlias) . '.' . $columnName;
|
||||||
$sql .= $orderByItem->isAsc() ? ' ASC' : ' DESC';
|
$sql .= $orderByItem->isAsc() ? ' ASC' : ' DESC';
|
||||||
return $sql;
|
return $sql;
|
||||||
}
|
}
|
||||||
@ -285,8 +286,8 @@ class SqlWalker implements TreeWalker
|
|||||||
$targetQComp = $this->_queryComponents[$joinedDqlAlias];
|
$targetQComp = $this->_queryComponents[$joinedDqlAlias];
|
||||||
|
|
||||||
$targetTableName = $targetQComp['metadata']->getTableName();
|
$targetTableName = $targetQComp['metadata']->getTableName();
|
||||||
$targetTableAlias = $this->getSqlTableAlias($targetTableName . $joinedDqlAlias);
|
$targetTableAlias = $this->getSqlTableAlias($targetTableName, $joinedDqlAlias);
|
||||||
$sourceTableAlias = $this->getSqlTableAlias($sourceQComp['metadata']->getTableName() . $joinAssocPathExpr->getIdentificationVariable());
|
$sourceTableAlias = $this->getSqlTableAlias($sourceQComp['metadata']->getTableName(), $joinAssocPathExpr->getIdentificationVariable());
|
||||||
|
|
||||||
// Ensure we got the owning side, since it has all mapping info
|
// Ensure we got the owning side, since it has all mapping info
|
||||||
if ( ! $targetQComp['relation']->isOwningSide()) {
|
if ( ! $targetQComp['relation']->isOwningSide()) {
|
||||||
@ -385,7 +386,7 @@ class SqlWalker implements TreeWalker
|
|||||||
$this->_selectedClasses[$dqlAlias] = $class;
|
$this->_selectedClasses[$dqlAlias] = $class;
|
||||||
}
|
}
|
||||||
|
|
||||||
$sqlTableAlias = $this->getSqlTableAlias($class->getTableName() . $dqlAlias);
|
$sqlTableAlias = $this->getSqlTableAlias($class->getTableName(), $dqlAlias);
|
||||||
$columnName = $class->getColumnName($fieldName);
|
$columnName = $class->getColumnName($fieldName);
|
||||||
$columnAlias = $this->getSqlColumnAlias($columnName);
|
$columnAlias = $this->getSqlColumnAlias($columnName);
|
||||||
$sql .= $sqlTableAlias . '.' . $columnName . ' AS ' . $columnAlias;
|
$sql .= $sqlTableAlias . '.' . $columnName . ' AS ' . $columnAlias;
|
||||||
@ -436,7 +437,7 @@ class SqlWalker implements TreeWalker
|
|||||||
$tableName = $class->primaryTable['name'];
|
$tableName = $class->primaryTable['name'];
|
||||||
}
|
}
|
||||||
if ($beginning) $beginning = false; else $sql .= ', ';
|
if ($beginning) $beginning = false; else $sql .= ', ';
|
||||||
$sqlTableAlias = $this->getSqlTableAlias($tableName . $dqlAlias);
|
$sqlTableAlias = $this->getSqlTableAlias($tableName, $dqlAlias);
|
||||||
$columnAlias = $this->getSqlColumnAlias($mapping['columnName']);
|
$columnAlias = $this->getSqlColumnAlias($mapping['columnName']);
|
||||||
$sql .= $sqlTableAlias . '.' . $this->_conn->quoteIdentifier($mapping['columnName']) . ' AS ' . $columnAlias;
|
$sql .= $sqlTableAlias . '.' . $this->_conn->quoteIdentifier($mapping['columnName']) . ' AS ' . $columnAlias;
|
||||||
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName);
|
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName);
|
||||||
@ -450,7 +451,7 @@ class SqlWalker implements TreeWalker
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($beginning) $beginning = false; else $sql .= ', ';
|
if ($beginning) $beginning = false; else $sql .= ', ';
|
||||||
$sqlTableAlias = $this->getSqlTableAlias($subClass->primaryTable['name'] . $dqlAlias);
|
$sqlTableAlias = $this->getSqlTableAlias($subClass->primaryTable['name'], $dqlAlias);
|
||||||
$columnAlias = $this->getSqlColumnAlias($mapping['columnName']);
|
$columnAlias = $this->getSqlColumnAlias($mapping['columnName']);
|
||||||
$sql .= $sqlTableAlias . '.' . $this->_conn->quoteIdentifier($mapping['columnName']) . ' AS ' . $columnAlias;
|
$sql .= $sqlTableAlias . '.' . $this->_conn->quoteIdentifier($mapping['columnName']) . ' AS ' . $columnAlias;
|
||||||
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName);
|
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName);
|
||||||
@ -464,7 +465,7 @@ class SqlWalker implements TreeWalker
|
|||||||
$this->_em->getClassMetadata($subclassName)->fieldMappings
|
$this->_em->getClassMetadata($subclassName)->fieldMappings
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$sqlTableAlias = $this->getSqlTableAlias($class->getTableName() . $dqlAlias);
|
$sqlTableAlias = $this->getSqlTableAlias($class->getTableName(), $dqlAlias);
|
||||||
foreach ($fieldMappings as $fieldName => $mapping) {
|
foreach ($fieldMappings as $fieldName => $mapping) {
|
||||||
if ($beginning) $beginning = false; else $sql .= ', ';
|
if ($beginning) $beginning = false; else $sql .= ', ';
|
||||||
$columnAlias = $this->getSqlColumnAlias($mapping['columnName']);
|
$columnAlias = $this->getSqlColumnAlias($mapping['columnName']);
|
||||||
@ -472,7 +473,9 @@ class SqlWalker implements TreeWalker
|
|||||||
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName);
|
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! $this->_em->getConfiguration()->getAllowPartialObjects()) {
|
// Append foreign keys if necessary.
|
||||||
|
if ( ! $this->_em->getConfiguration()->getAllowPartialObjects() &&
|
||||||
|
! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) {
|
||||||
foreach ($class->associationMappings as $assoc) {
|
foreach ($class->associationMappings as $assoc) {
|
||||||
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
|
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
|
||||||
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
|
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
|
||||||
@ -539,7 +542,7 @@ class SqlWalker implements TreeWalker
|
|||||||
$firstIdentificationVarDecl = $identificationVarDecls[0];
|
$firstIdentificationVarDecl = $identificationVarDecls[0];
|
||||||
$rangeDecl = $firstIdentificationVarDecl->getRangeVariableDeclaration();
|
$rangeDecl = $firstIdentificationVarDecl->getRangeVariableDeclaration();
|
||||||
$sql .= $rangeDecl->getClassMetadata()->getTableName() . ' '
|
$sql .= $rangeDecl->getClassMetadata()->getTableName() . ' '
|
||||||
. $this->getSqlTableAlias($rangeDecl->getClassMetadata()->getTableName() . $rangeDecl->getAliasIdentificationVariable());
|
. $this->getSqlTableAlias($rangeDecl->getClassMetadata()->getTableName(), $rangeDecl->getAliasIdentificationVariable());
|
||||||
|
|
||||||
foreach ($firstIdentificationVarDecl->getJoinVariableDeclarations() as $joinVarDecl) {
|
foreach ($firstIdentificationVarDecl->getJoinVariableDeclarations() as $joinVarDecl) {
|
||||||
$sql .= $this->walkJoinVariableDeclaration($joinVarDecl);
|
$sql .= $this->walkJoinVariableDeclaration($joinVarDecl);
|
||||||
@ -589,7 +592,7 @@ class SqlWalker implements TreeWalker
|
|||||||
// FIXME: Composite key support, or select all columns? Does that make
|
// FIXME: Composite key support, or select all columns? Does that make
|
||||||
// in a subquery?
|
// in a subquery?
|
||||||
$class = $this->_queryComponents[$expr]['metadata'];
|
$class = $this->_queryComponents[$expr]['metadata'];
|
||||||
$sql .= ' ' . $this->getSqlTableAlias($class->getTableName() . $expr) . '.';
|
$sql .= ' ' . $this->getSqlTableAlias($class->getTableName(), $expr) . '.';
|
||||||
$sql .= $class->getColumnName($class->identifier[0]);
|
$sql .= $class->getColumnName($class->identifier[0]);
|
||||||
}
|
}
|
||||||
return $sql;
|
return $sql;
|
||||||
@ -613,7 +616,7 @@ class SqlWalker implements TreeWalker
|
|||||||
|
|
||||||
$sql .= $aggExpression->getFunctionName() . '(';
|
$sql .= $aggExpression->getFunctionName() . '(';
|
||||||
if ($aggExpression->isDistinct()) $sql .= 'DISTINCT ';
|
if ($aggExpression->isDistinct()) $sql .= 'DISTINCT ';
|
||||||
$sql .= $this->getSqlTableAlias($qComp['metadata']->getTableName() . $dqlAlias) . '.' . $columnName;
|
$sql .= $this->getSqlTableAlias($qComp['metadata']->getTableName(), $dqlAlias) . '.' . $columnName;
|
||||||
$sql .= ')';
|
$sql .= ')';
|
||||||
return $sql;
|
return $sql;
|
||||||
}
|
}
|
||||||
@ -644,7 +647,7 @@ class SqlWalker implements TreeWalker
|
|||||||
$dqlAlias = $pathExpr->getIdentificationVariable();
|
$dqlAlias = $pathExpr->getIdentificationVariable();
|
||||||
$qComp = $this->_queryComponents[$dqlAlias];
|
$qComp = $this->_queryComponents[$dqlAlias];
|
||||||
$columnName = $qComp['metadata']->getColumnName($parts[0]);
|
$columnName = $qComp['metadata']->getColumnName($parts[0]);
|
||||||
return $this->getSqlTableAlias($qComp['metadata']->getTableName() . $dqlAlias) . '.' . $columnName;
|
return $this->getSqlTableAlias($qComp['metadata']->getTableName(), $dqlAlias) . '.' . $columnName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -803,7 +806,7 @@ class SqlWalker implements TreeWalker
|
|||||||
}
|
}
|
||||||
$discrColumn = $class->discriminatorColumn;
|
$discrColumn = $class->discriminatorColumn;
|
||||||
if ($this->_useSqlTableAliases) {
|
if ($this->_useSqlTableAliases) {
|
||||||
$sql .= $this->getSqlTableAlias($class->getTableName() . $dqlAlias) . '.';
|
$sql .= $this->getSqlTableAlias($class->getTableName(), $dqlAlias) . '.';
|
||||||
}
|
}
|
||||||
$sql .= $discrColumn['name'] . ' IN (' . implode(', ', $values) . ')';
|
$sql .= $discrColumn['name'] . ' IN (' . implode(', ', $values) . ')';
|
||||||
}
|
}
|
||||||
@ -886,7 +889,7 @@ class SqlWalker implements TreeWalker
|
|||||||
if ($assoc->isOneToMany()) {
|
if ($assoc->isOneToMany()) {
|
||||||
$targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
|
$targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
|
||||||
$targetTableAlias = $this->getSqlTableAlias($targetClass->primaryTable['name']);
|
$targetTableAlias = $this->getSqlTableAlias($targetClass->primaryTable['name']);
|
||||||
$sourceTableAlias = $this->getSqlTableAlias($class->primaryTable['name'] . $dqlAlias);
|
$sourceTableAlias = $this->getSqlTableAlias($class->primaryTable['name'], $dqlAlias);
|
||||||
|
|
||||||
$sql .= $this->_conn->quoteIdentifier($targetClass->primaryTable['name'])
|
$sql .= $this->_conn->quoteIdentifier($targetClass->primaryTable['name'])
|
||||||
. ' ' . $targetTableAlias . ' WHERE ';
|
. ' ' . $targetTableAlias . ' WHERE ';
|
||||||
@ -908,7 +911,7 @@ class SqlWalker implements TreeWalker
|
|||||||
}
|
}
|
||||||
} else { // many-to-many
|
} else { // many-to-many
|
||||||
$targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
|
$targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
|
||||||
$sourceTableAlias = $this->getSqlTableAlias($class->primaryTable['name'] . $dqlAlias);
|
$sourceTableAlias = $this->getSqlTableAlias($class->primaryTable['name'], $dqlAlias);
|
||||||
$joinTable = $assoc->isOwningSide ? $assoc->joinTable : $targetClass->associationMappings[$assoc->mappedByFieldName]->joinTable;
|
$joinTable = $assoc->isOwningSide ? $assoc->joinTable : $targetClass->associationMappings[$assoc->mappedByFieldName]->joinTable;
|
||||||
$joinTableAlias = $this->getSqlTableAlias($joinTable['name']);
|
$joinTableAlias = $this->getSqlTableAlias($joinTable['name']);
|
||||||
$targetTableAlias = $this->getSqlTableAlias($targetClass->primaryTable['name']);
|
$targetTableAlias = $this->getSqlTableAlias($targetClass->primaryTable['name']);
|
||||||
@ -1218,9 +1221,9 @@ class SqlWalker implements TreeWalker
|
|||||||
if ($this->_useSqlTableAliases) {
|
if ($this->_useSqlTableAliases) {
|
||||||
if ($class->isInheritanceTypeJoined() && isset($class->fieldMappings[$fieldName]['inherited'])) {
|
if ($class->isInheritanceTypeJoined() && isset($class->fieldMappings[$fieldName]['inherited'])) {
|
||||||
$sql .= $this->getSqlTableAlias($this->_em->getClassMetadata(
|
$sql .= $this->getSqlTableAlias($this->_em->getClassMetadata(
|
||||||
$class->fieldMappings[$fieldName]['inherited'])->getTableName() . $dqlAlias) . '.';
|
$class->fieldMappings[$fieldName]['inherited'])->getTableName(), $dqlAlias) . '.';
|
||||||
} else {
|
} else {
|
||||||
$sql .= $this->getSqlTableAlias($class->getTableName() . $dqlAlias) . '.';
|
$sql .= $this->getSqlTableAlias($class->getTableName(), $dqlAlias) . '.';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1247,8 +1250,9 @@ class SqlWalker implements TreeWalker
|
|||||||
* @param string $dqlAlias The DQL alias.
|
* @param string $dqlAlias The DQL alias.
|
||||||
* @return string Generated table alias.
|
* @return string Generated table alias.
|
||||||
*/
|
*/
|
||||||
public function getSqlTableAlias($tableName)
|
public function getSqlTableAlias($tableName, $dqlAlias = '')
|
||||||
{
|
{
|
||||||
|
$tableName .= $dqlAlias;
|
||||||
if ( ! isset($this->_dqlToSqlAliasMap[$tableName])) {
|
if ( ! isset($this->_dqlToSqlAliasMap[$tableName])) {
|
||||||
$this->_dqlToSqlAliasMap[$tableName] = strtolower(substr($tableName, 0, 1)) . $this->_tableAliasCounter++ . '_';
|
$this->_dqlToSqlAliasMap[$tableName] = strtolower(substr($tableName, 0, 1)) . $this->_tableAliasCounter++ . '_';
|
||||||
}
|
}
|
||||||
@ -1279,23 +1283,24 @@ class SqlWalker implements TreeWalker
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the SQL JOINs, that are necessary for Class Table Inheritance,
|
* Generates the SQL JOINs that are necessary for Class Table Inheritance
|
||||||
* for the given class.
|
* for the given class.
|
||||||
*
|
*
|
||||||
* @param ClassMetadata $class
|
* @param ClassMetadata $class The class for which to generate the joins.
|
||||||
* @param string $dqlAlias
|
* @param string $dqlAlias The DQL alias of the class.
|
||||||
|
* @return string The SQL.
|
||||||
*/
|
*/
|
||||||
private function _generateClassTableInheritanceJoins($class, $dqlAlias)
|
private function _generateClassTableInheritanceJoins($class, $dqlAlias)
|
||||||
{
|
{
|
||||||
$sql = '';
|
$sql = '';
|
||||||
|
|
||||||
$baseTableAlias = $this->getSqlTableAlias($class->primaryTable['name'] . $dqlAlias);
|
$baseTableAlias = $this->getSqlTableAlias($class->primaryTable['name'], $dqlAlias);
|
||||||
$idColumns = $class->getIdentifierColumnNames();
|
$idColumns = $class->getIdentifierColumnNames();
|
||||||
|
|
||||||
// INNER JOIN parent class tables
|
// INNER JOIN parent class tables
|
||||||
foreach ($class->parentClasses as $parentClassName) {
|
foreach ($class->parentClasses as $parentClassName) {
|
||||||
$parentClass = $this->_em->getClassMetadata($parentClassName);
|
$parentClass = $this->_em->getClassMetadata($parentClassName);
|
||||||
$tableAlias = $this->getSqlTableAlias($parentClass->primaryTable['name'] . $dqlAlias);
|
$tableAlias = $this->getSqlTableAlias($parentClass->primaryTable['name'], $dqlAlias);
|
||||||
$sql .= ' INNER JOIN ' . $parentClass->primaryTable['name'] . ' ' . $tableAlias . ' ON ';
|
$sql .= ' INNER JOIN ' . $parentClass->primaryTable['name'] . ' ' . $tableAlias . ' ON ';
|
||||||
$first = true;
|
$first = true;
|
||||||
foreach ($idColumns as $idColumn) {
|
foreach ($idColumns as $idColumn) {
|
||||||
@ -1307,7 +1312,7 @@ class SqlWalker implements TreeWalker
|
|||||||
// LEFT JOIN subclass tables
|
// LEFT JOIN subclass tables
|
||||||
foreach ($class->subClasses as $subClassName) {
|
foreach ($class->subClasses as $subClassName) {
|
||||||
$subClass = $this->_em->getClassMetadata($subClassName);
|
$subClass = $this->_em->getClassMetadata($subClassName);
|
||||||
$tableAlias = $this->getSqlTableAlias($subClass->primaryTable['name'] . $dqlAlias);
|
$tableAlias = $this->getSqlTableAlias($subClass->primaryTable['name'], $dqlAlias);
|
||||||
$sql .= ' LEFT JOIN ' . $subClass->primaryTable['name'] . ' ' . $tableAlias . ' ON ';
|
$sql .= ' LEFT JOIN ' . $subClass->primaryTable['name'] . ' ' . $tableAlias . ' ON ';
|
||||||
$first = true;
|
$first = true;
|
||||||
foreach ($idColumns as $idColumn) {
|
foreach ($idColumns as $idColumn) {
|
||||||
@ -1318,4 +1323,37 @@ class SqlWalker implements TreeWalker
|
|||||||
|
|
||||||
return $sql;
|
return $sql;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an executor that can be used to execute the result of this walker.
|
||||||
|
*
|
||||||
|
* @return AbstractExecutor
|
||||||
|
*/
|
||||||
|
public function getExecutor($AST)
|
||||||
|
{
|
||||||
|
$isDeleteStatement = $AST instanceof AST\DeleteStatement;
|
||||||
|
$isUpdateStatement = $AST instanceof AST\UpdateStatement;
|
||||||
|
|
||||||
|
if ($isDeleteStatement) {
|
||||||
|
$primaryClass = $this->_em->getClassMetadata(
|
||||||
|
$AST->getDeleteClause()->getAbstractSchemaName()
|
||||||
|
);
|
||||||
|
if ($primaryClass->isInheritanceTypeJoined()) {
|
||||||
|
return new Exec\MultiTableDeleteExecutor($AST, $this);
|
||||||
|
} else {
|
||||||
|
return new Exec\SingleTableDeleteUpdateExecutor($AST, $this);
|
||||||
|
}
|
||||||
|
} else if ($isUpdateStatement) {
|
||||||
|
$primaryClass = $this->_em->getClassMetadata(
|
||||||
|
$AST->getUpdateClause()->getAbstractSchemaName()
|
||||||
|
);
|
||||||
|
if ($primaryClass->isInheritanceTypeJoined()) {
|
||||||
|
return new Exec\MultiTableUpdateExecutor($AST, $this);
|
||||||
|
} else {
|
||||||
|
return new Exec\SingleTableDeleteUpdateExecutor($AST, $this);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return new Exec\SingleSelectExecutor($AST, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,23 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* 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 LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
namespace Doctrine\ORM\Query;
|
namespace Doctrine\ORM\Query;
|
||||||
|
|
||||||
@ -333,4 +352,11 @@ interface TreeWalker
|
|||||||
* @return string The SQL.
|
* @return string The SQL.
|
||||||
*/
|
*/
|
||||||
function walkPathExpression($pathExpr);
|
function walkPathExpression($pathExpr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an executor that can be used to execute the result of this walker.
|
||||||
|
*
|
||||||
|
* @return AbstractExecutor
|
||||||
|
*/
|
||||||
|
function getExecutor($AST);
|
||||||
}
|
}
|
@ -1,4 +1,23 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* 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 LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
namespace Doctrine\ORM\Query;
|
namespace Doctrine\ORM\Query;
|
||||||
|
|
||||||
|
@ -1476,8 +1476,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
if (isset($this->_identityMap[$class->rootEntityName][$idHash])) {
|
if (isset($this->_identityMap[$class->rootEntityName][$idHash])) {
|
||||||
$entity = $this->_identityMap[$class->rootEntityName][$idHash];
|
$entity = $this->_identityMap[$class->rootEntityName][$idHash];
|
||||||
$oid = spl_object_hash($entity);
|
$oid = spl_object_hash($entity);
|
||||||
$overrideLocalChanges = false;
|
$overrideLocalChanges = isset($hints[Query::HINT_REFRESH]);
|
||||||
//$overrideLocalChanges = isset($hints['doctrine.refresh']) && $hints['doctrine.refresh'] === true;
|
|
||||||
} else {
|
} else {
|
||||||
$entity = new $className;
|
$entity = new $className;
|
||||||
$oid = spl_object_hash($entity);
|
$oid = spl_object_hash($entity);
|
||||||
|
@ -4,6 +4,14 @@ namespace Doctrine\Tests\Mocks;
|
|||||||
|
|
||||||
class MockTreeWalker extends \Doctrine\ORM\Query\TreeWalkerAdapter
|
class MockTreeWalker extends \Doctrine\ORM\Query\TreeWalkerAdapter
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Gets an executor that can be used to execute the result of this walker.
|
||||||
|
*
|
||||||
|
* @return AbstractExecutor
|
||||||
|
*/
|
||||||
|
public function getExecutor($AST)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +89,7 @@ class OneToOneBidirectionalAssociationTest extends \Doctrine\Tests\OrmFunctional
|
|||||||
$result = $query->getResultList();
|
$result = $query->getResultList();
|
||||||
$customer = $result[0];
|
$customer = $result[0];
|
||||||
|
|
||||||
|
$this->assertNull($customer->getMentor());
|
||||||
$this->assertTrue($customer->getCart() instanceof ECommerceCart);
|
$this->assertTrue($customer->getCart() instanceof ECommerceCart);
|
||||||
$this->assertEquals('paypal', $customer->getCart()->getPayment());
|
$this->assertEquals('paypal', $customer->getCart()->getPayment());
|
||||||
}
|
}
|
||||||
|
@ -276,5 +276,63 @@ class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
|
|||||||
$e = microtime(true);
|
$e = microtime(true);
|
||||||
echo __FUNCTION__ . " - " . ($e - $s) . " seconds" . PHP_EOL;
|
echo __FUNCTION__ . " - " . ($e - $s) . " seconds" . PHP_EOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Times for comparison:
|
||||||
|
*
|
||||||
|
* [romanb: 10000 rows => 0.7 seconds]
|
||||||
|
*
|
||||||
|
* MAXIMUM TIME: 1 second
|
||||||
|
*/
|
||||||
|
public function testSimpleQueryScalarHydrationPerformance()
|
||||||
|
{
|
||||||
|
$rsm = new ResultSetMapping;
|
||||||
|
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
|
||||||
|
$rsm->addFieldResult('u', 'u__id', 'id');
|
||||||
|
$rsm->addFieldResult('u', 'u__status', 'status');
|
||||||
|
$rsm->addFieldResult('u', 'u__username', 'username');
|
||||||
|
$rsm->addFieldResult('u', 'u__name', 'name');
|
||||||
|
|
||||||
|
// Faked result set
|
||||||
|
$resultSet = array(
|
||||||
|
//row1
|
||||||
|
array(
|
||||||
|
'u__id' => '1',
|
||||||
|
'u__status' => 'developer',
|
||||||
|
'u__username' => 'romanb',
|
||||||
|
'u__name' => 'Roman',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'u__id' => '1',
|
||||||
|
'u__status' => 'developer',
|
||||||
|
'u__username' => 'romanb',
|
||||||
|
'u__name' => 'Roman',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'u__id' => '2',
|
||||||
|
'u__status' => 'developer',
|
||||||
|
'u__username' => 'romanb',
|
||||||
|
'u__name' => 'Roman',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
for ($i = 4; $i < 10000; ++$i) {
|
||||||
|
$resultSet[] = array(
|
||||||
|
'u__id' => $i,
|
||||||
|
'u__status' => 'developer',
|
||||||
|
'u__username' => 'jwage',
|
||||||
|
'u__name' => 'Jonathan',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = new HydratorMockStatement($resultSet);
|
||||||
|
$hydrator = new \Doctrine\ORM\Internal\Hydration\ScalarHydrator($this->_em);
|
||||||
|
|
||||||
|
$this->setMaxRunningTime(1);
|
||||||
|
$s = microtime(true);
|
||||||
|
$result = $hydrator->hydrateAll($stmt, $rsm);
|
||||||
|
$e = microtime(true);
|
||||||
|
echo __FUNCTION__ . " - " . ($e - $s) . " seconds" . PHP_EOL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,8 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
$parser = new \Doctrine\ORM\Query\Parser($query);
|
$parser = new \Doctrine\ORM\Query\Parser($query);
|
||||||
//$parser->setSqlTreeWalker(new \Doctrine\Tests\Mocks\MockTreeWalker);
|
// We do NOT test SQL construction here. That only unnecessarily slows down the tests!
|
||||||
|
$parser->setSqlTreeWalker(new \Doctrine\Tests\Mocks\MockTreeWalker);
|
||||||
|
|
||||||
return $parser->parse();
|
return $parser->parse();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user