Commit 4fc1781d authored by romanb's avatar romanb

[2.0][DDC-22] Fixed. Also cleaned up association handling. More to come:...

[2.0][DDC-22] Fixed. Also cleaned up association handling. More to come: exception refactorings, proxy simplifications (single proxy class, not two).
parent e832d172
......@@ -100,12 +100,12 @@ class DoctrineException extends \Exception
if (($message = self::getExceptionMessage($messageKey)) !== false) {
$message = sprintf($message, $arguments);
} else {
$dumper = function ($value) { return var_export($value, true); };
//$dumper = function ($value) { return var_export($value, true); };
$message = strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', $method));
$message = ucfirst(str_replace('_', ' ', $message));
if ($arguments) {
/*if ($arguments) {
$message .= ' (' . implode(', ', array_map($dumper, $arguments)) . ')';
}
}*/
}
return new $class($message, $innerException);
......
<?php
namespace Doctrine\DBAL;
class DBALException extends \Exception {}
\ No newline at end of file
......@@ -22,7 +22,7 @@
namespace Doctrine\ORM\Id;
use Doctrine\ORM\EntityManager;
use Doctrine\Common\DoctrineException;
use Doctrine\ORM\ORMException;
/**
* Special generator for application-assigned identifiers (doesnt really generate anything).
......@@ -62,7 +62,7 @@ class Assigned extends AbstractIdGenerator
}
if ( ! $identifier) {
throw DoctrineException::entityMissingAssignedId($entity);
throw ORMException::entityMissingAssignedId($entity);
}
return $identifier;
......
......@@ -78,10 +78,11 @@ abstract class AbstractHydrator
* @param object $resultSetMapping
* @return IterableResult
*/
public function iterate($stmt, $resultSetMapping)
public function iterate($stmt, $resultSetMapping, array $hints = array())
{
$this->_stmt = $stmt;
$this->_rsm = $resultSetMapping;
$this->_hints = $hints;
$this->_prepare();
return new IterableResult($this);
}
......
......@@ -26,7 +26,7 @@ use Doctrine\DBAL\Connection;
/**
* Hydrator that produces flat, rectangular results of scalar data.
* The created result is almost the same as a regular SQL result set, except
* that column names are mapped to field names and data type conversions.
* that column names are mapped to field names and data type conversions take place.
*
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
......@@ -49,10 +49,4 @@ class ScalarHydrator extends AbstractHydrator
{
$result[] = $this->_gatherScalarRowData($data, $cache);
}
/** @override */
protected function _getRowContainer()
{
return array();
}
}
\ No newline at end of file
......@@ -169,6 +169,15 @@ final class ClassMetadata extends ClassMetadataInfo
return $this->reflFields[$this->identifier[0]]->getValue($entity);
}
}
public function getColumnValues($entity, array $columns)
{
$values = array();
foreach ($columns as $column) {
$values[] = $this->reflFields[$this->fieldNames[$column]]->getValue($entity);
}
return $values;
}
/**
* Populates the entity identifier of an entity.
......
......@@ -221,7 +221,6 @@ class OneToOneMapping extends AssociationMapping
if ($this->isOwningSide) {
foreach ($this->sourceToTargetKeyColumns as $sourceKeyColumn => $targetKeyColumn) {
// getting customer_id
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
$conditions[$targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
} else {
......@@ -240,7 +239,6 @@ class OneToOneMapping extends AssociationMapping
$owningAssoc = $em->getClassMetadata($this->targetEntityName)->getAssociationMapping($this->mappedByFieldName);
// TRICKY: since the association is specular source and target are flipped
foreach ($owningAssoc->targetToSourceKeyColumns as $sourceKeyColumn => $targetKeyColumn) {
// getting id
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
$conditions[$targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
} else {
......@@ -250,7 +248,12 @@ class OneToOneMapping extends AssociationMapping
$targetEntity = $em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->load($conditions, $targetEntity, $this);
$targetClass->setFieldValue($targetEntity, $this->mappedByFieldName, $sourceEntity);
if ($targetEntity !== null) {
$targetClass->setFieldValue($targetEntity, $this->mappedByFieldName, $sourceEntity);
}
}
return $targetEntity;
}
}
<?php
namespace Doctrine\ORM;
class ORMException extends \Exception
{
public static function entityMissingAssignedId($entity)
{
return new self("Entity of type " . get_class($entity) . " is missing an assigned ID.");
}
}
......@@ -34,7 +34,7 @@ use Doctrine\Common\DoctrineException,
/**
* Base class for all EntityPersisters. An EntityPersister is a class that knows
* how to persist (and to some extent how to load) entities of a specific type.
* how to persist and load entities of a specific type.
*
* @author Roman Borschel <roman@code-factory.org>
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
......@@ -410,6 +410,13 @@ class StandardEntityPersister
public function load(array $criteria, $entity = null, $assoc = null)
{
$stmt = $this->_conn->prepare($this->_getSelectEntitiesSql($criteria, $assoc));
if ($stmt === null) {
try {
throw new \Exception();
} catch (\Exception $e) {
var_dump($e->getTraceAsString());
}
}
$stmt->execute(array_values($criteria));
$result = $stmt->fetch(Connection::FETCH_ASSOC);
$stmt->closeCursor();
......@@ -417,6 +424,88 @@ class StandardEntityPersister
return $this->_createEntity($result, $entity);
}
/**
* Refreshes an entity.
*
* @param array $id The identifier of the entity as an associative array from column names to values.
* @param object $entity The entity to refresh.
*/
public function refresh(array $id, $entity)
{
$stmt = $this->_conn->prepare($this->_getSelectEntitiesSql($id));
$stmt->execute(array_values($id));
$result = $stmt->fetch(Connection::FETCH_ASSOC);
$stmt->closeCursor();
$metaColumns = array();
$newData = array();
// Refresh simple state
foreach ($result as $column => $value) {
$column = $this->_class->resultColumnNames[$column];
if (isset($this->_class->fieldNames[$column])) {
$fieldName = $this->_class->fieldNames[$column];
$type = Type::getType($this->_class->fieldMappings[$fieldName]['type']);
$newValue = $type->convertToPHPValue($value, $this->_platform);
$this->_class->reflFields[$fieldName]->setValue($entity, $newValue);
$newData[$fieldName] = $newValue;
} else {
$metaColumns[$column] = $value;
}
}
// Refresh associations
foreach ($this->_class->associationMappings as $field => $assoc) {
$value = $this->_class->reflFields[$field]->getValue($entity);
if ($assoc->isOneToOne()) {
if ($value instanceof Proxy && ! $value->__isInitialized()) {
continue; // skip uninitialized proxies
}
if ($assoc->isOwningSide) {
$joinColumnValues = array();
$targetColumns = array();
foreach ($assoc->targetToSourceKeyColumns as $targetColumn => $srcColumn) {
if ($metaColumns[$srcColumn] !== null) {
$joinColumnValues[] = $metaColumns[$srcColumn];
}
$targetColumns[] = $targetColumn;
}
if ( ! $joinColumnValues && $value !== null) {
$this->_class->reflFields[$field]->setValue($entity, null);
$newData[$field] = null;
} else if ($value !== null) {
// Check identity map first, if the entity is not there,
// place a proxy in there instead.
$targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
if ($found = $this->_em->getUnitOfWork()->tryGetById($joinColumnValues, $targetClass->rootEntityName)) {
$this->_class->reflFields[$field]->setValue($entity, $found);
// Complete inverse side, if necessary.
if (isset($targetClass->inverseMappings[$this->_class->name][$field])) {
$inverseAssoc = $targetClass->inverseMappings[$this->_class->name][$field];
$targetClass->reflFields[$inverseAssoc->sourceFieldName]->setValue($found, $entity);
}
$newData[$field] = $found;
} else if ((array)$this->_class->getIdentifierValues($value) != $joinColumnValues) {
$proxy = $this->_em->getProxyFactory()->getAssociationProxy($entity, $assoc, $joinColumnValues);
$this->_class->reflFields[$field]->setValue($entity, $proxy);
$newData[$field] = $proxy;
}
}
} else {
// Inverse side of 1-1/1-x can never be lazy
$assoc->load($entity, null, $this->_em);
$newData[$field] = $this->_class->reflFields[$field]->getValue($entity);
}
} else if ($value instanceof PersistentCollection && $value->isInitialized()) {
$value->setInitialized(false);
$newData[$field] = $value;
}
}
$this->_em->getUnitOfWork()->setOriginalEntityData($entity, $newData);
}
/**
* Loads all entities by a list of field criteria.
*
......
......@@ -1443,16 +1443,13 @@ class UnitOfWork implements PropertyChangedListener
$visited[$oid] = $entity; // mark visited
$class = $this->_em->getClassMetadata(get_class($entity));
switch ($this->getEntityState($entity)) {
case self::STATE_MANAGED:
$this->getEntityPersister($class->name)->load(
array_combine($class->identifier, $this->_entityIdentifiers[$oid]),
$entity
);
//TODO: refresh (initialized) associations
break;
default:
throw new \InvalidArgumentException("Entity is not MANAGED.");
if ($this->getEntityState($entity) == self::STATE_MANAGED) {
$this->getEntityPersister($class->name)->refresh(
array_combine($class->getIdentifierColumnNames(), $this->_entityIdentifiers[$oid]),
$entity
);
} else {
throw new \InvalidArgumentException("Entity is not MANAGED.");
}
$this->_cascadeRefresh($entity, $visited);
......@@ -1651,6 +1648,7 @@ class UnitOfWork implements PropertyChangedListener
* @param array $data The data for the entity.
* @return object The created entity instance.
* @internal Highly performance-sensitive method.
* @todo Rename: getOrCreateEntity
*/
public function createEntity($className, array $data, &$hints = array())
{
......@@ -1698,25 +1696,31 @@ class UnitOfWork implements PropertyChangedListener
// Properly initialize any unfetched associations, if partial objects are not allowed.
if ( ! isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) {
foreach ($class->associationMappings as $field => $assoc) {
// Check if the association is not among the fetch-joined associatons already.
// Check if the association is not among the fetch-joined associations already.
if ( ! isset($hints['fetched'][$className][$field])) {
if ($assoc->isOneToOne()) {
$joinColumns = array();
if ($assoc->isOwningSide) {
$joinColumns = array();
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
$joinColumns[$srcColumn] = $data[$assoc->joinColumnFieldNames[$srcColumn]];
$joinColumnValue = $data[$assoc->joinColumnFieldNames[$srcColumn]];
if ($joinColumnValue !== null) {
$joinColumns[$srcColumn] = $joinColumnValue;
}
}
if ( ! $joinColumns) {
$class->reflFields[$field]->setValue($entity, null);
$this->_originalEntityData[$oid][$field] = null;
} else {
//TODO: If its in the identity map just get it from there if possible!
// Inject proxy
$proxy = $this->_em->getProxyFactory()->getAssociationProxy($entity, $assoc, $joinColumns);
$this->_originalEntityData[$oid][$field] = $proxy;
$class->reflFields[$field]->setValue($entity, $proxy);
}
}
//TODO: If its in the identity map just get it from there if possible!
if ($assoc->isLazilyFetched() /*&& $assoc->isOwningSide)*/) {
// Inject proxy
$proxy = $this->_em->getProxyFactory()->getAssociationProxy($entity, $assoc, $joinColumns);
$this->_originalEntityData[$oid][$field] = $proxy;
$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, $joinColumns);
// Inverse side can never be lazy.
$targetEntity = $assoc->load($entity, new $assoc->targetEntityName, $this->_em);
$class->reflFields[$field]->setValue($entity, $targetEntity);
}
} else {
// Inject collection
......@@ -1778,6 +1782,14 @@ class UnitOfWork implements PropertyChangedListener
}
return array();
}
/**
* @ignore
*/
public function setOriginalEntityData($entity, array $data)
{
$this->_originalEntityData[spl_object_hash($entity)] = $data;
}
/**
* INTERNAL:
......
......@@ -6,12 +6,12 @@ require_once __DIR__ . '/../TestInit.php';
class DoctrineExceptionTest extends \Doctrine\Tests\DoctrineTestCase
{
public function testStaticCall()
/*public function testStaticCall()
{
$e = \Doctrine\Common\DoctrineException::testingStaticCallBuildsErrorMessageWithParams('param1', 'param2');
$this->assertEquals($e->getMessage(), "Testing static call builds error message with params ('param1', 'param2')");
}
}*/
public function testInnerException()
{
......
......@@ -23,8 +23,81 @@ class IdentityMapTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->useModelSet('cms');
parent::setUp();
}
public function testBasicIdentityManagement()
{
$user = new CmsUser;
$user->status = 'dev';
$user->username = 'romanb';
$user->name = 'Roman B.';
$address = new CmsAddress;
$address->country = 'de';
$address->zip = 1234;
$address->city = 'Berlin';
$user->setAddress($address);
$this->_em->persist($user);
$this->_em->flush();
$this->_em->clear();
$user2 = $this->_em->find(get_class($user), $user->getId());
$this->assertTrue($user2 !== $user);
$user3 = $this->_em->find(get_class($user), $user->getId());
$this->assertTrue($user2 === $user3);
$address2 = $this->_em->find(get_class($address), $address->getId());
$this->assertTrue($address2 !== $address);
$address3 = $this->_em->find(get_class($address), $address->getId());
$this->assertTrue($address2 === $address3);
$this->assertTrue($user2->getAddress() === $address2); // !!!
}
public function testSingleValuedAssociationIdentityMapBehaviorWithRefresh()
{
$address = new CmsAddress;
$address->country = 'de';
$address->zip = '12345';
$address->city = 'Berlin';
$user1 = new CmsUser;
$user1->status = 'dev';
$user1->username = 'romanb';
$user1->name = 'Roman B.';
public function testSingleValuedAssociationIdentityMapBehavior()
$user2 = new CmsUser;
$user2->status = 'dev';
$user2->username = 'gblanco';
$user2->name = 'Guilherme Blanco';
$address->setUser($user1);
$this->_em->persist($address);
$this->_em->persist($user1);
$this->_em->persist($user2);
$this->_em->flush();
$this->assertSame($user1, $address->user);
//external update to CmsAddress
$this->_em->getConnection()->executeUpdate('update cms_addresses set user_id = ?', array($user2->getId()));
// But we want to have this external change!
// Solution 1: refresh(), broken atm!
$this->_em->refresh($address);
// Now the association should be "correct", referencing $user2
$this->assertSame($user2, $address->user);
$this->assertSame($user2->address, $address); // check back reference also
// Attention! refreshes can result in broken bidirectional associations! this is currently expected!
// $user1 still points to $address!
$this->assertSame($user1->address, $address);
}
public function testSingleValuedAssociationIdentityMapBehaviorWithRefreshQuery()
{
$address = new CmsAddress;
$address->country = 'de';
......@@ -65,8 +138,6 @@ class IdentityMapTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertTrue($user2->address === null);
// But we want to have this external change!
// Solution 1: refresh(), broken atm!
//$this->_em->refresh($address2);
// Solution 2: Alternatively, a refresh query should work
$q = $this->_em->createQuery('select a, u from Doctrine\Tests\Models\CMS\CmsAddress a join a.user u');
$q->setHint(Query::HINT_REFRESH, true);
......@@ -83,7 +154,7 @@ class IdentityMapTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertSame($user1->address, $address2);
}
public function testCollectionValuedAssociationIdentityMapBehavior()
public function testCollectionValuedAssociationIdentityMapBehaviorWithRefreshQuery()
{
$user = new CmsUser;
$user->status = 'dev';
......@@ -133,5 +204,52 @@ class IdentityMapTest extends \Doctrine\Tests\OrmFunctionalTestCase
// Now the collection should be refreshed with correct count
$this->assertEquals(4, count($user3->getPhonenumbers()));
}
public function testCollectionValuedAssociationIdentityMapBehaviorWithRefresh()
{
$user = new CmsUser;
$user->status = 'dev';
$user->username = 'romanb';
$user->name = 'Roman B.';
$phone1 = new CmsPhonenumber;
$phone1->phonenumber = 123;
$phone2 = new CmsPhonenumber;
$phone2->phonenumber = 234;
$phone3 = new CmsPhonenumber;
$phone3->phonenumber = 345;
$user->addPhonenumber($phone1);
$user->addPhonenumber($phone2);
$user->addPhonenumber($phone3);
$this->_em->persist($user); // cascaded to phone numbers
$this->_em->flush();
$this->assertEquals(3, count($user->getPhonenumbers()));
//external update to CmsAddress
$this->_em->getConnection()->executeUpdate('insert into cms_phonenumbers (phonenumber, user_id) VALUES (?,?)', array(999, $user->getId()));
//select
$q = $this->_em->createQuery('select u, p from Doctrine\Tests\Models\CMS\CmsUser u join u.phonenumbers p');
$user2 = $q->getSingleResult();
$this->assertSame($user, $user2);
// Should still be the same 3 phonenumbers
$this->assertEquals(3, count($user2->getPhonenumbers()));
// But we want to have this external change!
// Solution 1: refresh().
$this->_em->refresh($user2);
$this->assertSame($user, $user2); // should still be the same, always from identity map
// Now the collection should be refreshed with correct count
$this->assertEquals(4, count($user2->getPhonenumbers()));
}
}
......@@ -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->assertTrue($e2->getMappedRelated1() instanceof MappedSuperclassRelated1);
$this->assertNull($e2->getMappedRelated1());
$this->assertEquals(42, $e2->getMapped1());
$this->assertEquals('bar', $e2->getMapped2());
}
......
......@@ -78,7 +78,7 @@ class OneToOneBidirectionalAssociationTest extends \Doctrine\Tests\OrmFunctional
$this->assertEquals('Giorgio', $cart->getCustomer()->getName());
}
public function testLazyLoadsObjectsOnTheInverseSide()
public function testInverseSideIsNeverLazy()
{
$this->_createFixture();
$metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceCustomer');
......@@ -90,7 +90,7 @@ class OneToOneBidirectionalAssociationTest extends \Doctrine\Tests\OrmFunctional
$this->assertNull($customer->getMentor());
$this->assertTrue($customer->getCart() instanceof ECommerceCart);
$this->assertTrue($customer->getCart() instanceof \Doctrine\ORM\Proxy\Proxy);
$this->assertFalse($customer->getCart() instanceof \Doctrine\ORM\Proxy\Proxy);
$this->assertEquals('paypal', $customer->getCart()->getPayment());
}
......
......@@ -4,9 +4,9 @@ namespace Doctrine\Tests\ORM\Performance;
require_once __DIR__ . '/../../TestInit.php';
use Doctrine\Tests\Mocks\HydratorMockStatement;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\ORM\Query;
use Doctrine\Tests\Mocks\HydratorMockStatement,
Doctrine\ORM\Query\ResultSetMapping,
Doctrine\ORM\Query;
/**
* Tests to prevent serious performance regressions.
......@@ -18,6 +18,64 @@ use Doctrine\ORM\Query;
*/
class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
{
/**
* Times for comparison:
*
* [romanb: 10000 rows => 0.7 seconds]
*
* MAXIMUM TIME: 1 second
*/
public function testSimpleQueryScalarHydrationPerformance10000Rows()
{
$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;
}
/**
* Times for comparison:
*
......@@ -219,6 +277,16 @@ class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
$rsm->addFieldResult('u', 'u__status', 'status');
$rsm->addFieldResult('u', 'u__username', 'username');
$rsm->addFieldResult('u', 'u__name', 'name');
$rsm->addJoinedEntityResult(
'Doctrine\Tests\Models\CMS\CmsAddress',
'a',
'u',
'address'
);
$rsm->addFieldResult('a', 'a__id', 'id');
//$rsm->addFieldResult('a', 'a__country', 'country');
//$rsm->addFieldResult('a', 'a__zip', 'zip');
//$rsm->addFieldResult('a', 'a__city', 'city');
// Faked result set
$resultSet = array(
......@@ -228,27 +296,17 @@ class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
'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',
'a__id' => '1'
)
);
for ($i = 4; $i < 10000; ++$i) {
for ($i = 2; $i < 10000; ++$i) {
$resultSet[] = array(
'u__id' => $i,
'u__status' => 'developer',
'u__username' => 'jwage',
'u__name' => 'Jonathan',
'a__id' => $i
);
}
......@@ -355,6 +413,13 @@ class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
$rsm->addFieldResult('u', 'u__name', 'name');
$rsm->addScalarResult('sclr0', 'nameUpper');
$rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
$rsm->addJoinedEntityResult(
'Doctrine\Tests\Models\CMS\CmsAddress',
'a',
'u',
'address'
);
$rsm->addFieldResult('a', 'a__id', 'id');
// Faked result set
$resultSet = array(
......@@ -366,33 +431,19 @@ class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
'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'
'a__id' => '1'
)
);
for ($i = 4; $i < 2000; ++$i) {
for ($i = 2; $i < 2000; ++$i) {
$resultSet[] = array(
'u__id' => $i,
'u__status' => 'developer',
'u__username' => 'jwage',
'u__name' => 'Jonathan',
'sclr0' => 'JWAGE' . $i,
'p__phonenumber' => '91'
'p__phonenumber' => '91',
'a__id' => $i
);
}
......@@ -405,63 +456,5 @@ class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
$e = microtime(true);
echo __FUNCTION__ . " - " . ($e - $s) . " seconds" . PHP_EOL;
}
/**
* Times for comparison:
*
* [romanb: 10000 rows => 0.7 seconds]
*
* MAXIMUM TIME: 1 second
*/
public function testSimpleQueryScalarHydrationPerformance10000Rows()
{
$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;
}
}
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