Commit 5842411a authored by romanb's avatar romanb

[2.0][DDC-49][DDC-50][DDC-33] Fixed DDC-49 and DDC-50. Also addressed DDC-33....

[2.0][DDC-49][DDC-50][DDC-33] Fixed DDC-49 and DDC-50. Also addressed DDC-33. Various other small changes and fixes. For problems with proxy objects please refer to the updated documentation.
parent cb1c7bce
......@@ -45,7 +45,6 @@ class Configuration extends \Doctrine\DBAL\Configuration
'metadataCacheImpl' => null,
'metadataDriverImpl' => null,
'proxyDir' => null,
'allowPartialObjects' => true, //TODO: Remove
'useCExtension' => false,
'namedQueries' => array(),
'namedNativeQueries' => array(),
......@@ -72,7 +71,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
*/
public function getAllowPartialObjects()
{
return $this->_attributes['allowPartialObjects'];
return true;
}
/**
......@@ -86,9 +85,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @deprecated
*/
public function setAllowPartialObjects($allowed)
{
$this->_attributes['allowPartialObjects'] = $allowed;
}
{}
/**
* Sets the directory where Doctrine generates any necessary proxy class files.
......
......@@ -314,19 +314,17 @@ class EntityManager
*/
public function getReference($entityName, $identifier)
{
$class = $this->_metadataFactory->getMetadataFor($entityName);
// Check identity map first, if its already in there just return it.
if ($entity = $this->_unitOfWork->tryGetById($identifier,
$this->_metadataFactory->getMetadataFor($entityName)->rootEntityName)) {
if ($entity = $this->_unitOfWork->tryGetById($identifier, $class->rootEntityName)) {
return $entity;
}
if ($this->_config->getAllowPartialObjects()) {
$entity = new $entityName;
$this->getClassMetadata($entityName)->setIdentifierValues($entity, $identifier);
} else {
$entity = $this->_proxyFactory->getReferenceProxy($entityName, $identifier);
if ( ! is_array($identifier)) {
$identifier = array($class->identifier[0] => $identifier);
}
$this->_unitOfWork->registerManaged($entity, (array) $identifier, array());
$entity = $this->_proxyFactory->getReferenceProxy($entityName, $identifier);
$this->_unitOfWork->registerManaged($entity, $identifier, array());
return $entity;
}
......
......@@ -58,8 +58,7 @@ class ObjectHydrator extends AbstractHydrator
/** @override */
protected function _prepare()
{
$this->_allowPartialObjects = $this->_em->getConfiguration()->getAllowPartialObjects()
|| isset($this->_hints[Query::HINT_FORCE_PARTIAL_LOAD]);
$this->_allowPartialObjects = isset($this->_hints[Query::HINT_FORCE_PARTIAL_LOAD]);
$this->_proxyFactory = $this->_em->getProxyFactory();
......@@ -201,7 +200,7 @@ class ObjectHydrator extends AbstractHydrator
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
$joinColumns[$srcColumn] = $data[$assoc->joinColumnFieldNames[$srcColumn]];
}
if ($assoc->isLazilyFetched()) {
if ($assoc->isLazilyFetched() /*&& ! $assoc->isOptional*/) {
// Inject proxy
$proxy = $this->_proxyFactory->getAssociationProxy($entity, $assoc, $joinColumns);
$this->_uow->setOriginalEntityProperty($oid, $field, $proxy);
......
......@@ -208,7 +208,7 @@ class OneToOneMapping extends AssociationMapping
}
}
$targetEntity = $em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->load($conditions, $targetEntity);
$targetEntity = $em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->load($conditions, $targetEntity, $this);
if ($targetEntity !== null && $targetClass->hasInverseAssociationMapping($this->sourceEntityName, $this->sourceFieldName)) {
$targetClass->setFieldValue($targetEntity,
......@@ -227,7 +227,7 @@ class OneToOneMapping extends AssociationMapping
}
}
$targetEntity = $em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->load($conditions, $targetEntity);
$targetEntity = $em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->load($conditions, $targetEntity, $this);
$targetClass->setFieldValue($targetEntity, $this->mappedByFieldName, $sourceEntity);
}
......
......@@ -229,6 +229,7 @@ final class PersistentCollection implements \Doctrine\Common\Collections\Collect
private function _initialize()
{
if ( ! $this->_initialized) {
$this->_coll->clear();
$this->_association->load($this->_owner, $this, $this->_em);
$this->_initialized = true;
}
......
......@@ -414,9 +414,9 @@ class StandardEntityPersister
* 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, $assoc = null)
{
$stmt = $this->_conn->prepare($this->_getSelectEntitiesSql($criteria));
$stmt = $this->_conn->prepare($this->_getSelectEntitiesSql($criteria, $assoc));
$stmt->execute(array_values($criteria));
$result = $stmt->fetch(Connection::FETCH_ASSOC);
$stmt->closeCursor();
......@@ -525,34 +525,31 @@ class StandardEntityPersister
$this->_em->getUnitOfWork()->registerManaged($entity, $id, $data);
}
if ( ! $this->_em->getConfiguration()->getAllowPartialObjects()) {
// Partial objects not allowed, so make sure we put in proxies and
// empty collections respectively.
foreach ($this->_class->associationMappings as $field => $assoc) {
if ($assoc->isOneToOne()) {
if ($assoc->isLazilyFetched()) {
// Inject proxy
$proxy = $this->_em->getProxyFactory()->getAssociationProxy($entity, $assoc, $joinColumnValues);
$this->_class->reflFields[$field]->setValue($entity, $proxy);
} else {
// Eager load
//TODO: Allow more efficient and configurable batching of these loads
$assoc->load($entity, new $assoc->targetEntityName, $this->_em, $joinColumnValues);
}
// Initialize associations
foreach ($this->_class->associationMappings as $field => $assoc) {
if ($assoc->isOneToOne()) {
if ($assoc->isLazilyFetched()) {
// Inject proxy
$proxy = $this->_em->getProxyFactory()->getAssociationProxy($entity, $assoc, $joinColumnValues);
$this->_class->reflFields[$field]->setValue($entity, $proxy);
} else {
// Inject collection
$coll = new PersistentCollection(
$this->_em,
$this->_em->getClassMetadata($assoc->targetEntityName),
/*$this->_class->reflFields[$field]->getValue($entity) ?:*/ new ArrayCollection);
$coll->setOwner($entity, $assoc);
$this->_class->reflFields[$field]->setValue($entity, $coll);
if ($assoc->isLazilyFetched()) {
$coll->setInitialized(false);
} else {
//TODO: Allow more efficient and configurable batching of these loads
$assoc->load($entity, $coll, $this->_em);
}
// Eager load
//TODO: Allow more efficient and configurable batching of these loads
$assoc->load($entity, new $assoc->targetEntityName, $this->_em, $joinColumnValues);
}
} else {
// Inject collection
$coll = new PersistentCollection(
$this->_em,
$this->_em->getClassMetadata($assoc->targetEntityName),
/*$this->_class->reflFields[$field]->getValue($entity) ?:*/ new ArrayCollection);
$coll->setOwner($entity, $assoc);
$this->_class->reflFields[$field]->setValue($entity, $coll);
if ($assoc->isLazilyFetched()) {
$coll->setInitialized(false);
} else {
//TODO: Allow more efficient and configurable batching of these loads
$assoc->load($entity, $coll, $this->_em);
}
}
}
......@@ -575,13 +572,11 @@ class StandardEntityPersister
}
$joinColumnNames = array();
if ( ! $this->_em->getConfiguration()->getAllowPartialObjects()) {
foreach ($this->_class->associationMappings as $assoc) {
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
$joinColumnNames[] = $srcColumn;
$columnList .= ', ' . $assoc->getQuotedJoinColumnName($srcColumn, $this->_platform);
}
foreach ($this->_class->associationMappings as $assoc2) {
if ($assoc2->isOwningSide && $assoc2->isOneToOne()) {
foreach ($assoc2->targetToSourceKeyColumns as $srcColumn) {
$joinColumnNames[] = $srcColumn;
$columnList .= ', ' . $assoc2->getQuotedJoinColumnName($srcColumn, $this->_platform);
}
}
}
......@@ -623,12 +618,10 @@ class StandardEntityPersister
$columnList .= $this->_class->getQuotedColumnName($field, $this->_platform);
}
if ( ! $this->_em->getConfiguration()->getAllowPartialObjects()) {
foreach ($this->_class->associationMappings as $assoc) {
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
$columnList .= ', ' . $assoc->getQuotedJoinColumnName($srcColumn, $this->_platform);
}
foreach ($this->_class->associationMappings as $assoc) {
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
$columnList .= ', ' . $assoc->getQuotedJoinColumnName($srcColumn, $this->_platform);
}
}
}
......
......@@ -8,4 +8,7 @@ namespace Doctrine\ORM\Proxy;
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
*/
interface Proxy {}
\ No newline at end of file
interface Proxy
{
function __isInitialized__();
}
\ No newline at end of file
......@@ -289,6 +289,7 @@ namespace <namespace> {
$this->_loaded = true;
}
}
public function __isInitialized__() { return $this->_loaded; }
<methods>
......@@ -331,6 +332,7 @@ namespace <namespace> {
$this->_loaded = true;
}
}
public function __isInitialized__() { return $this->_loaded; }
<methods>
......
......@@ -1575,7 +1575,6 @@ class Parser
// Deny hydration of partial objects if doctrine.forcePartialLoad query hint not defined
if (
$this->_query->getHydrationMode() == Query::HYDRATE_OBJECT &&
! $this->_em->getConfiguration()->getAllowPartialObjects() &&
! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)
) {
throw DoctrineException::partialObjectsAreDangerous();
......
......@@ -252,7 +252,7 @@ class SqlWalker implements TreeWalker
}
// LEFT JOIN subclass tables, only if partial objects disallowed
if ( ! $this->_em->getConfiguration()->getAllowPartialObjects() && ! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) {
if ( ! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) {
foreach ($class->subClasses as $subClassName) {
$subClass = $this->_em->getClassMetadata($subClassName);
$tableAlias = $this->getSqlTableAlias($subClass->primaryTable['name'], $dqlAlias);
......@@ -446,8 +446,7 @@ class SqlWalker implements TreeWalker
', ', array_map(array($this, 'walkSelectExpression'), $selectClause->selectExpressions)
);
$addMetaColumns = ! $this->_em->getConfiguration()->getAllowPartialObjects() &&
! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD) &&
$addMetaColumns = ! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD) &&
$this->_query->getHydrationMode() == Query::HYDRATE_OBJECT
||
$this->_query->getHydrationMode() != Query::HYDRATE_OBJECT &&
......@@ -480,6 +479,7 @@ class SqlWalker implements TreeWalker
// Add foreign key columns to SQL, if necessary
if ($addMetaColumns) {
//FIXME: Include foreign key columns of child classes also!!??
foreach ($class->associationMappings as $assoc) {
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
if (isset($class->inheritedAssociationFields[$assoc->sourceFieldName])) {
......@@ -654,22 +654,19 @@ class SqlWalker implements TreeWalker
if ($assoc->isOneToOne()) {
$sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ';
$first = true;
foreach ($assoc->sourceToTargetKeyColumns as $sourceColumn => $targetColumn) {
if ( ! $first) {
$sql .= ' AND ';
} else {
$first = false;
}
if ( ! $first) $sql .= ' AND '; else $first = false;
$quotedSourceColumn = $assoc->getQuotedJoinColumnName($sourceColumn, $this->_platform);
$quotedTargetColumn = $sourceClass->getQuotedColumnName($sourceClass->fieldNames[$targetColumn], $this->_platform);
if ($relation->isOwningSide) {
$quotedTargetColumn = $targetClass->getQuotedColumnName($targetClass->fieldNames[$targetColumn], $this->_platform);
$sql .= $sourceTableAlias . '.' . $quotedSourceColumn
. ' = '
. $targetTableAlias . '.' . $quotedTargetColumn;
} else {
$quotedTargetColumn = $sourceClass->getQuotedColumnName($sourceClass->fieldNames[$targetColumn], $this->_platform);
$sql .= $sourceTableAlias . '.' . $quotedTargetColumn
. ' = '
. $targetTableAlias . '.' . $quotedSourceColumn;
......@@ -824,8 +821,7 @@ class SqlWalker implements TreeWalker
// 1) on Single Table Inheritance: always, since its marginal overhead
// 2) on Class Table Inheritance only if partial objects are disallowed,
// since it requires outer joining subtables.
if ($class->isInheritanceTypeSingleTable() || ! $this->_em->getConfiguration()->getAllowPartialObjects()
&& ! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) {
if ($class->isInheritanceTypeSingleTable() || ! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) {
foreach ($class->subClasses as $subClassName) {
$subClass = $this->_em->getClassMetadata($subClassName);
foreach ($subClass->fieldMappings as $fieldName => $mapping) {
......@@ -838,7 +834,7 @@ class SqlWalker implements TreeWalker
$sqlTableAlias = $this->getSqlTableAlias($subClass->primaryTable['name'], $dqlAlias);
$columnAlias = $this->getSqlColumnAlias($mapping['columnName']);
$sql .= $sqlTableAlias . '.' . $subClass->getQuotedColumnName($fieldName, $this->_platform)
. ' AS ' . $columnAlias;
. ' AS ' . $columnAlias;
$columnAlias = $this->_platform->getSqlResultCasing($columnAlias);
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName);
......
......@@ -559,11 +559,14 @@ class UnitOfWork implements PropertyChangedListener
// Look through the entities, and in any of their associations, for transient
// enities, recursively. ("Persistence by reachability")
if ($assoc->isOneToOne()) {
if ($value instanceof Proxy) {
return; // Ignore proxy objects
if ($value instanceof Proxy && ! $value->__isInitialized__()) {
return; // Ignore uninitialized proxy objects
}
$value = array($value);
} else if ($value instanceof PersistentCollection) {
$value = $value->unwrap();
}
$targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
foreach ($value as $entry) {
$state = $this->getEntityState($entry, self::STATE_NEW);
......@@ -728,7 +731,7 @@ class UnitOfWork implements PropertyChangedListener
$hasPostUpdateListeners = $this->_evm->hasListeners(Events::postUpdate);
foreach ($this->_entityUpdates as $oid => $entity) {
if (get_class($entity) == $className) {
if (get_class($entity) == $className || $entity instanceof Proxy && $entity instanceof $className) {
if ($hasPreUpdateLifecycleCallbacks) {
$class->invokeLifecycleCallbacks(Events::preUpdate, $entity);
if ( ! $hasPreUpdateListeners) {
......
......@@ -352,8 +352,6 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
public function testAddToCollectionDoesNotInitialize()
{
$this->_em->getConfiguration()->setAllowPartialObjects(false);
$user = new CmsUser;
$user->name = 'Guilherme';
$user->username = 'gblanco';
......@@ -382,15 +380,13 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
$gblanco->addPhonenumber($phone);
$this->assertFalse($gblanco->getPhonenumbers()->isInitialized());
$this->_em->flush();
$this->_em->clear();
$query = $this->_em->createQuery("select u, p from Doctrine\Tests\Models\CMS\CmsUser u join u.phonenumbers p where u.username='gblanco'");
$gblanco2 = $query->getSingleResult();
$this->assertEquals(4, $gblanco2->getPhonenumbers()->count());
$this->_em->getConfiguration()->setAllowPartialObjects(true);
}
public function testSetSetAssociationWithGetReference()
......@@ -417,7 +413,10 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
// that address to the user without actually loading it, using getReference().
$addressRef = $this->_em->getReference('Doctrine\Tests\Models\CMS\CmsAddress', $address->getId());
$user->setAddress($addressRef);
//$addressRef->getId();
//\Doctrine\Common\Util\Debug::dump($addressRef);
$user->setAddress($addressRef); // Ugh! Initializes address 'cause of $address->setUser($user)!
$this->_em->flush();
$this->_em->clear();
......@@ -425,7 +424,7 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
// Check with a fresh load that the association is indeed there
$query = $this->_em->createQuery("select u, a from Doctrine\Tests\Models\CMS\CmsUser u join u.address a where u.username='gblanco'");
$gblanco = $query->getSingleResult();
$this->assertTrue($gblanco instanceof CmsUser);
$this->assertTrue($gblanco->getAddress() instanceof CmsAddress);
$this->assertEquals('Berlin', $gblanco->getAddress()->getCity());
......
......@@ -5,6 +5,7 @@ namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Tests\Models\ECommerce\ECommerceProduct;
use Doctrine\Tests\Models\ECommerce\ECommerceCategory;
use Doctrine\ORM\Mapping\AssociationMapping;
use Doctrine\ORM\Query;
require_once __DIR__ . '/../../TestInit.php';
......@@ -77,7 +78,7 @@ class ManyToManyBidirectionalAssociationTest extends AbstractManyToManyAssociati
{
$this->_createLoadingFixture();
$products = $this->_findProducts();
$this->assertLoadingOfOwningSide($products);
$this->assertLoadingOfOwningSide($products);
}
public function testLazyLoadsCollectionOnTheInverseSide()
......@@ -128,6 +129,7 @@ class ManyToManyBidirectionalAssociationTest extends AbstractManyToManyAssociati
protected function _findProducts()
{
$query = $this->_em->createQuery('SELECT p, c FROM Doctrine\Tests\Models\ECommerce\ECommerceProduct p LEFT JOIN p.categories c ORDER BY p.id, c.id');
//$query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
return $query->getResult();
}
......
......@@ -37,7 +37,7 @@ class MappedSuperclassTest extends \Doctrine\Tests\OrmFunctionalTestCase
$e2 = $this->_em->find('Doctrine\Tests\ORM\Functional\EntitySubClass', 1);
$this->assertEquals(1, $e2->getId());
$this->assertEquals('Roman', $e2->getName());
$this->assertNull($e2->getMappedRelated1());
$this->assertTrue($e2->getMappedRelated1() instanceof MappedSuperclassRelated1);
$this->assertEquals(42, $e2->getMapped1());
$this->assertEquals('bar', $e2->getMapped2());
}
......
......@@ -107,7 +107,6 @@ class OneToManyBidirectionalAssociationTest extends \Doctrine\Tests\OrmFunctiona
public function testLazyLoadsObjectsOnTheInverseSide()
{
$this->_createFixture();
$this->_em->getConfiguration()->setAllowPartialObjects(false);
$metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceFeature');
$metadata->getAssociationMapping('product')->fetchMode = AssociationMapping::FETCH_LAZY;
......@@ -118,6 +117,13 @@ class OneToManyBidirectionalAssociationTest extends \Doctrine\Tests\OrmFunctiona
$this->assertTrue($product instanceof ECommerceProduct);
$this->assertSame('Doctrine Cookbook', $product->getName());
}
public function testJoinFromOwningSide()
{
$query = $this->_em->createQuery('select f,p from Doctrine\Tests\Models\ECommerce\ECommerceFeature f join f.product p');
$features = $query->getResult();
$this->assertEquals(0, count($features));
}
private function _createFixture()
{
......
......@@ -5,6 +5,7 @@ namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Tests\Models\ECommerce\ECommerceProduct;
use Doctrine\Tests\Models\ECommerce\ECommerceShipping;
use Doctrine\ORM\Mapping\AssociationMapping;
use Doctrine\ORM\Query;
require_once __DIR__ . '/../../TestInit.php';
......@@ -74,9 +75,10 @@ class OneToOneUnidirectionalAssociationTest extends \Doctrine\Tests\OrmFunctiona
public function testDoesNotLazyLoadObjectsIfConfigurationDoesNotAllowIt() {
$this->_createFixture();
$this->_em->getConfiguration()->setAllowPartialObjects(true);
$query = $this->_em->createQuery('select p from Doctrine\Tests\Models\ECommerce\ECommerceProduct p');
$query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
$result = $query->getResult();
$product = $result[0];
......
......@@ -2,6 +2,8 @@
namespace Doctrine\Tests\ORM\Functional;
use Doctrine\ORM\Query;
require_once __DIR__ . '/../../TestInit.php';
/**
......@@ -49,7 +51,7 @@ class SingleTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->clear();
$query = $this->_em->createQuery("select e from Doctrine\Tests\ORM\Functional\ParentEntity e order by e.data asc");
$query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
$entities = $query->getResult();
$this->assertEquals(2, count($entities));
......@@ -64,7 +66,6 @@ class SingleTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->clear();
$query = $this->_em->createQuery("select e from Doctrine\Tests\ORM\Functional\ChildEntity e");
$entities = $query->getResult();
$this->assertEquals(1, count($entities));
$this->assertTrue($entities[0] instanceof ChildEntity);
......
......@@ -37,9 +37,11 @@ class StandardEntityPersisterTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->clear();
unset($cart);
$class = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceCart');
$persister = $this->_em->getUnitOfWork()->getEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceCart');
$newCart = new ECommerceCart();
$persister->load(array('customer_id' => $customer->getId()), $newCart);
$persister->load(array('customer_id' => $customer->getId()), $newCart, $class->associationMappings['customer']);
$this->assertEquals('Credit card', $newCart->getPayment());
}
......
......@@ -6,6 +6,7 @@ use Doctrine\Tests\Mocks\HydratorMockStatement;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\ORM\Proxy\ProxyFactory;
use Doctrine\ORM\Mapping\AssociationMapping;
use Doctrine\ORM\Query;
require_once __DIR__ . '/../../TestInit.php';
......@@ -37,7 +38,7 @@ class ObjectHydratorTest extends HydrationTestCase
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm);
$result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
$this->assertEquals(2, count($result));
$this->assertTrue($result[0] instanceof \Doctrine\Tests\Models\CMS\CmsUser);
......@@ -81,7 +82,7 @@ class ObjectHydratorTest extends HydrationTestCase
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm);
$result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
$this->assertEquals(4, count($result));
......@@ -192,7 +193,7 @@ class ObjectHydratorTest extends HydrationTestCase
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm);
$result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
$this->assertEquals(2, count($result));
$this->assertTrue(is_array($result));
......@@ -251,7 +252,7 @@ class ObjectHydratorTest extends HydrationTestCase
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm);
$result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
$this->assertEquals(2, count($result));
$this->assertTrue(is_array($result));
......@@ -316,7 +317,7 @@ class ObjectHydratorTest extends HydrationTestCase
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm);
$result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
$this->assertEquals(2, count($result));
$this->assertTrue(is_array($result));
......@@ -430,7 +431,7 @@ class ObjectHydratorTest extends HydrationTestCase
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm);
$result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
$this->assertEquals(2, count($result));
$this->assertTrue(is_array($result));
......@@ -565,7 +566,7 @@ class ObjectHydratorTest extends HydrationTestCase
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm);
$result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
$this->assertEquals(2, count($result));
$this->assertTrue(is_array($result));
......@@ -672,7 +673,7 @@ class ObjectHydratorTest extends HydrationTestCase
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm);
$result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
$this->assertEquals(2, count($result));
$this->assertTrue($result[0] instanceof \Doctrine\Tests\Models\Forum\ForumCategory);
......@@ -710,7 +711,7 @@ class ObjectHydratorTest extends HydrationTestCase
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$iterableResult = $hydrator->iterate($stmt, $rsm);
$iterableResult = $hydrator->iterate($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
$rowNum = 0;
while (($row = $iterableResult->next()) !== false) {
......
......@@ -6,6 +6,7 @@ require_once __DIR__ . '/../../TestInit.php';
use Doctrine\Tests\Mocks\HydratorMockStatement;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\ORM\Query;
/**
* Tests to prevent serious performance regressions.
......@@ -24,7 +25,7 @@ class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
*
* MAXIMUM TIME: 2 seconds
*/
public function testSimpleQueryArrayHydrationPerformance()
public function testSimpleQueryArrayHydrationPerformance10000Rows()
{
$rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
......@@ -82,7 +83,7 @@ class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
*
* MAXIMUM TIME: 3 seconds
*/
public function testMixedQueryFetchJoinArrayHydrationPerformance()
public function testMixedQueryFetchJoinArrayHydrationPerformance10000Rows()
{
$rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
......@@ -154,7 +155,7 @@ class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
*
* MAXIMUM TIME: 3 seconds
*/
public function testSimpleQueryObjectHydrationPerformance()
public function testSimpleQueryPartialObjectHydrationPerformance10000Rows()
{
$rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
......@@ -200,6 +201,62 @@ class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
$this->setMaxRunningTime(3);
$s = microtime(true);
$result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
$e = microtime(true);
echo __FUNCTION__ . " - " . ($e - $s) . " seconds" . PHP_EOL;
}
/**
* [romanb: 10000 rows => 3 seconds]
*
* MAXIMUM TIME: 4.5 seconds
*/
public function testSimpleQueryFullObjectHydrationPerformance10000Rows()
{
$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\ObjectHydrator($this->_em);
$this->setMaxRunningTime(4);
$s = microtime(true);
$result = $hydrator->hydrateAll($stmt, $rsm);
$e = microtime(true);
echo __FUNCTION__ . " - " . ($e - $s) . " seconds" . PHP_EOL;
......@@ -210,7 +267,79 @@ class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
*
* MAXIMUM TIME: 1 second
*/
public function testMixedQueryFetchJoinObjectHydrationPerformance()
public function testMixedQueryFetchJoinPartialObjectHydrationPerformance2000Rows()
{
$rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
$rsm->addJoinedEntityResult(
'Doctrine\Tests\Models\CMS\CmsPhonenumber',
'p',
'u',
'phonenumbers'
);
$rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status');
$rsm->addFieldResult('u', 'u__username', 'username');
$rsm->addFieldResult('u', 'u__name', 'name');
$rsm->addScalarResult('sclr0', 'nameUpper');
$rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
// Faked result set
$resultSet = array(
//row1
array(
'u__id' => '1',
'u__status' => 'developer',
'u__username' => 'romanb',
'u__name' => 'Roman',
'sclr0' => 'ROMANB',
'p__phonenumber' => '42',
),
array(
'u__id' => '1',
'u__status' => 'developer',
'u__username' => 'romanb',
'u__name' => 'Roman',
'sclr0' => 'ROMANB',
'p__phonenumber' => '43',
),
array(
'u__id' => '2',
'u__status' => 'developer',
'u__username' => 'romanb',
'u__name' => 'Roman',
'sclr0' => 'JWAGE',
'p__phonenumber' => '91'
)
);
for ($i = 4; $i < 2000; ++$i) {
$resultSet[] = array(
'u__id' => $i,
'u__status' => 'developer',
'u__username' => 'jwage',
'u__name' => 'Jonathan',
'sclr0' => 'JWAGE' . $i,
'p__phonenumber' => '91'
);
}
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$this->setMaxRunningTime(1);
$s = microtime(true);
$result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
$e = microtime(true);
echo __FUNCTION__ . " - " . ($e - $s) . " seconds" . PHP_EOL;
}
/**
* [romanb: 2000 rows => 0.6 seconds]
*
* MAXIMUM TIME: 1 second
*/
public function testMixedQueryFetchJoinFullObjectHydrationPerformance200Rows()
{
$rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
......@@ -284,7 +413,7 @@ class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
*
* MAXIMUM TIME: 1 second
*/
public function testSimpleQueryScalarHydrationPerformance()
public function testSimpleQueryScalarHydrationPerformance10000Rows()
{
$rsm = new ResultSetMapping;
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
......
<?php
namespace Doctrine\Tests\ORM\Query;
use Doctrine\ORM\Query;
require_once __DIR__ . '/../../TestInit.php';
class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
......@@ -40,6 +42,7 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
public function parseDql($dql, $hints = array())
{
$query = $this->_em->createQuery($dql);
$query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
$query->setDql($dql);
foreach ($hints as $key => $value) {
......@@ -358,13 +361,8 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
*/
public function testPartialObjectLoad()
{
$oldValue = $this->_em->getConfiguration()->getAllowPartialObjects();
$this->_em->getConfiguration()->setAllowPartialObjects(false);
$this->parseDql('SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u', array(
\Doctrine\ORM\Query::HINT_FORCE_PARTIAL_LOAD => false
));
$this->_em->getConfiguration()->setAllowPartialObjects($oldValue);
}
}
\ No newline at end of file
......@@ -2,6 +2,8 @@
namespace Doctrine\Tests\ORM\Query;
use Doctrine\ORM\Query;
require_once __DIR__ . '/../../TestInit.php';
class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
......@@ -17,6 +19,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
{
try {
$query = $this->_em->createQuery($dqlToBeTested);
$query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
parent::assertEquals($sqlToBeConfirmed, $query->getSql());
$query->free();
} catch (Doctrine_Exception $e) {
......@@ -274,6 +277,8 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
{
// "Get all users who have $phone as a phonenumber." (*cough* doesnt really make sense...)
$q1 = $this->_em->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :param MEMBER OF u.phonenumbers');
$q1->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
$phone = new \Doctrine\Tests\Models\CMS\CmsPhonenumber;
$phone->phonenumber = 101;
$q1->setParameter('param', $phone);
......@@ -285,6 +290,8 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
// "Get all users who are members of $group."
$q2 = $this->_em->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :param MEMBER OF u.groups');
$q2->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
$group = new \Doctrine\Tests\Models\CMS\CmsGroup;
$group->id = 101;
$q2->setParameter('param', $group);
......@@ -310,20 +317,23 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
public function testSupportsCurrentDateFunction()
{
$q = $this->_em->createQuery('SELECT d.id FROM Doctrine\Tests\Models\Generic\DateTimeModel d WHERE d.datetime > current_date()');
$this->assertEquals('SELECT d0_.id AS id0 FROM date_time_model d0_ WHERE d0_.datetime > CURRENT_DATE', $q->getSql());
$q = $this->_em->createQuery('SELECT d.id FROM Doctrine\Tests\Models\Generic\DateTimeModel d WHERE d.datetime > current_date()');
$q->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
$this->assertEquals('SELECT d0_.id AS id0 FROM date_time_model d0_ WHERE d0_.datetime > CURRENT_DATE', $q->getSql());
}
public function testSupportsCurrentTimeFunction()
{
$q = $this->_em->createQuery('SELECT d.id FROM Doctrine\Tests\Models\Generic\DateTimeModel d WHERE d.time > current_time()');
$this->assertEquals('SELECT d0_.id AS id0 FROM date_time_model d0_ WHERE d0_.time > CURRENT_TIME', $q->getSql());
$q = $this->_em->createQuery('SELECT d.id FROM Doctrine\Tests\Models\Generic\DateTimeModel d WHERE d.time > current_time()');
$q->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
$this->assertEquals('SELECT d0_.id AS id0 FROM date_time_model d0_ WHERE d0_.time > CURRENT_TIME', $q->getSql());
}
public function testSupportsCurrentTimestampFunction()
{
$q = $this->_em->createQuery('SELECT d.id FROM Doctrine\Tests\Models\Generic\DateTimeModel d WHERE d.datetime > current_timestamp()');
$this->assertEquals('SELECT d0_.id AS id0 FROM date_time_model d0_ WHERE d0_.datetime > CURRENT_TIMESTAMP', $q->getSql());
$q = $this->_em->createQuery('SELECT d.id FROM Doctrine\Tests\Models\Generic\DateTimeModel d WHERE d.datetime > current_timestamp()');
$q->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
$this->assertEquals('SELECT d0_.id AS id0 FROM date_time_model d0_ WHERE d0_.datetime > CURRENT_TIMESTAMP', $q->getSql());
}
/*public function testExistsExpressionInWhereCorrelatedSubqueryAssocCondition()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment