1
0
mirror of synced 2025-02-20 22:23:14 +03:00

Merge branch 'DDC-546'

This commit is contained in:
Benjamin Eberlei 2011-01-02 15:14:40 +01:00
commit 7a2c99353a
14 changed files with 729 additions and 56 deletions

View File

@ -121,6 +121,7 @@
<xs:restriction base="xs:token">
<xs:enumeration value="EAGER"/>
<xs:enumeration value="LAZY"/>
<xs:enumeration value="EXTRALAZY"/>
</xs:restriction>
</xs:simpleType>

View File

@ -121,6 +121,12 @@ class ClassMetadataInfo
* association is fetched.
*/
const FETCH_EAGER = 3;
/**
* Specifies that an association is to be fetched lazy (on first access) and that
* commands such as Collection#count, Collection#slice are issued directly against
* the database if the collection is not yet initialized.
*/
const FETCH_EXTRA_LAZY = 4;
/**
* Identifies a one-to-one association.
*/

View File

@ -59,7 +59,7 @@ final class PersistentCollection implements Collection
* The association mapping the collection belongs to.
* This is currently either a OneToManyMapping or a ManyToManyMapping.
*
* @var Doctrine\ORM\Mapping\AssociationMapping
* @var array
*/
private $association;
@ -404,22 +404,12 @@ final class PersistentCollection implements Collection
*/
public function contains($element)
{
/* DRAFT
if ($this->initialized) {
return $this->coll->contains($element);
} else {
if ($element is MANAGED) {
if ($this->coll->contains($element)) {
return true;
}
$exists = check db for existence;
if ($exists) {
$this->coll->add($element);
}
return $exists;
}
return false;
}*/
if (!$this->initialized && $this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
return $this->coll->contains($element) ||
$this->em->getUnitOfWork()
->getCollectionPersister($this->association)
->contains($this, $element);
}
$this->initialize();
return $this->coll->contains($element);
@ -475,6 +465,12 @@ final class PersistentCollection implements Collection
*/
public function count()
{
if (!$this->initialized && $this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
return $this->em->getUnitOfWork()
->getCollectionPersister($this->association)
->count($this) + $this->coll->count();
}
$this->initialize();
return $this->coll->count();
}
@ -675,6 +671,12 @@ final class PersistentCollection implements Collection
*/
public function slice($offset, $length = null)
{
if (!$this->initialized && $this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
return $this->em->getUnitOfWork()
->getCollectionPersister($this->association)
->slice($this, $offset, $length);
}
$this->initialize();
return $this->coll->slice($offset, $length);
}

View File

@ -125,6 +125,31 @@ abstract class AbstractCollectionPersister
}
}
public function count(PersistentCollection $coll)
{
throw new \BadMethodCallException("Counting the size of this persistent collection is not supported by this CollectionPersister.");
}
public function slice(PersistentCollection $coll, $offset, $length = null)
{
throw new \BadMethodCallException("Slicing elements is not supported by this CollectionPersister.");
}
public function contains(PersistentCollection $coll, $element)
{
throw new \BadMethodCallException("Checking for existance of an element is not supported by this CollectionPersister.");
}
public function containsKey(PersistentCollection $coll, $key)
{
throw new \BadMethodCallException("Checking for existance of a key is not supported by this CollectionPersister.");
}
public function get(PersistentCollection $coll, $index)
{
throw new \BadMethodCallException("Selecting a collection by index is not supported by this CollectionPersister.");
}
/**
* Gets the SQL statement used for deleting a row from the collection.
*

View File

@ -717,15 +717,49 @@ class BasicEntityPersister
return $entities;
}
/**
* Get (sliced or full) elements of the given collection.
*
* @param array $assoc
* @param object $sourceEntity
* @param int|null $offset
* @param int|null $limit
* @return array
*/
public function getManyToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null)
{
$stmt = $this->getManyToManyStatement($assoc, $sourceEntity, $offset, $limit);
$entities = array();
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
$entities[] = $this->_createEntity($result);
}
$stmt->closeCursor();
return $entities;
}
/**
* Loads a collection of entities of a many-to-many association.
*
* @param ManyToManyMapping $assoc The association mapping of the association being loaded.
* @param object $sourceEntity The entity that owns the collection.
* @param PersistentCollection $coll The collection to fill.
* @param int|null $offset
* @param int|null $limit
* @return array
*/
public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
{
{
$stmt = $this->getManyToManyStatement($assoc, $sourceEntity);
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
$coll->hydrateAdd($this->_createEntity($result));
}
$stmt->closeCursor();
}
private function getManyToManyStatement(array $assoc, $sourceEntity, $offset = null, $limit = null)
{
$criteria = array();
$sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']);
$joinTableConditions = array();
@ -769,13 +803,9 @@ class BasicEntityPersister
}
}
$sql = $this->_getSelectEntitiesSQL($criteria, $assoc);
$sql = $this->_getSelectEntitiesSQL($criteria, $assoc, 0, $limit, $offset);
list($params, $types) = $this->expandParameters($criteria);
$stmt = $this->_conn->executeQuery($sql, $params, $types);
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
$coll->hydrateAdd($this->_createEntity($result));
}
$stmt->closeCursor();
return $this->_conn->executeQuery($sql, $params, $types);
}
/**
@ -854,7 +884,7 @@ class BasicEntityPersister
* @return string
* @todo Refactor: _getSelectSQL(...)
*/
protected function _getSelectEntitiesSQL(array $criteria, $assoc = null, $lockMode = 0)
protected function _getSelectEntitiesSQL(array $criteria, $assoc = null, $lockMode = 0, $limit = null, $offset = null)
{
$joinSql = $assoc != null && $assoc['type'] == ClassMetadata::MANY_TO_MANY ?
$this->_getSelectManyToManyJoinSQL($assoc) : '';
@ -872,12 +902,12 @@ class BasicEntityPersister
$lockSql = ' ' . $this->_platform->getWriteLockSql();
}
return 'SELECT ' . $this->_getSelectColumnListSQL()
return $this->_platform->modifyLimitQuery('SELECT ' . $this->_getSelectColumnListSQL()
. $this->_platform->appendLockHint(' FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' '
. $this->_getSQLTableAlias($this->_class->name), $lockMode)
. $joinSql
. ($conditionSql ? ' WHERE ' . $conditionSql : '')
. $orderBySql
. $orderBySql, $limit, $offset)
. $lockSql;
}
@ -1175,14 +1205,56 @@ class BasicEntityPersister
return $conditionSql;
}
/**
* Return an array with (sliced or full list) of elements in the specified collection.
*
* @param array $assoc
* @param object $sourceEntity
* @param int $offset
* @param int $limit
* @return array
*/
public function getOneToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null)
{
$stmt = $this->getOneToManyStatement($assoc, $sourceEntity, $offset, $limit);
$entities = array();
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
$entities[] = $this->_createEntity($result);
}
$stmt->closeCursor();
return $entities;
}
/**
* Loads a collection of entities in a one-to-many association.
*
* @param OneToManyMapping $assoc
* @param array $criteria The criteria by which to select the entities.
* @param PersistentCollection The collection to load/fill.
* @param array $assoc
* @param object $sourceEntity
* @param PersistentCollection $coll The collection to load/fill.
* @param int|null $offset
* @param int|null $limit
*/
public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
{
$stmt = $this->getOneToManyStatement($assoc, $sourceEntity);
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
$coll->hydrateAdd($this->_createEntity($result));
}
$stmt->closeCursor();
}
/**
* Build criteria and execute SQL statement to fetch the one to many entities from.
*
* @param array $assoc
* @param object $sourceEntity
* @param int|null $offset
* @param int|null $limit
* @return Doctrine\DBAL\Statement
*/
private function getOneToManyStatement(array $assoc, $sourceEntity, $offset = null, $limit = null)
{
$criteria = array();
$owningAssoc = $this->_class->associationMappings[$assoc['mappedBy']];
@ -1201,13 +1273,9 @@ class BasicEntityPersister
}
}
$sql = $this->_getSelectEntitiesSQL($criteria, $assoc);
$sql = $this->_getSelectEntitiesSQL($criteria, $assoc, 0, $limit, $offset);
list($params, $types) = $this->expandParameters($criteria);
$stmt = $this->_conn->executeQuery($sql, $params, $types);
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
$coll->hydrateAdd($this->_createEntity($result));
}
$stmt->closeCursor();
return $this->_conn->executeQuery($sql, $params, $types);
}
/**
@ -1237,19 +1305,17 @@ class BasicEntityPersister
* @param object $entity
* @return boolean TRUE if the entity exists in the database, FALSE otherwise.
*/
public function exists($entity)
public function exists($entity, array $extraConditions = array())
{
$criteria = $this->_class->getIdentifierValues($entity);
if ($extraConditions) {
$criteria = array_merge($criteria, $extraConditions);
}
$sql = 'SELECT 1 FROM ' . $this->_class->getQuotedTableName($this->_platform)
. ' ' . $this->_getSQLTableAlias($this->_class->name)
. ' WHERE ' . $this->_getSelectConditionSQL($criteria);
return (bool) $this->_conn->fetchColumn($sql, array_values($criteria));
}
//TODO
/*protected function _getOneToOneEagerFetchSQL()
{
}*/
}

View File

@ -20,7 +20,8 @@
namespace Doctrine\ORM\Persisters;
use Doctrine\ORM\ORMException,
Doctrine\ORM\Mapping\ClassMetadata;
Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\DBAL\LockMode;
/**
* The joined subclass persister maps a single entity instance to several tables in the
@ -239,7 +240,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
/**
* {@inheritdoc}
*/
protected function _getSelectEntitiesSQL(array $criteria, $assoc = null, $lockMode = 0)
protected function _getSelectEntitiesSQL(array $criteria, $assoc = null, $lockMode = 0, $limit = null, $offset = null)
{
$idColumns = $this->_class->getIdentifierColumnNames();
$baseTableAlias = $this->_getSQLTableAlias($this->_class->name);
@ -348,10 +349,18 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
$this->_selectColumnListSql = $columnList;
}
return 'SELECT ' . $this->_selectColumnListSql
$lockSql = '';
if ($lockMode == LockMode::PESSIMISTIC_READ) {
$lockSql = ' ' . $this->_platform->getReadLockSql();
} else if ($lockMode == LockMode::PESSIMISTIC_WRITE) {
$lockSql = ' ' . $this->_platform->getWriteLockSql();
}
return $this->_platform->modifyLimitQuery('SELECT ' . $this->_selectColumnListSql
. ' FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' ' . $baseTableAlias
. $joinSql
. ($conditionSql != '' ? ' WHERE ' . $conditionSql : '') . $orderBySql;
. ($conditionSql != '' ? ' WHERE ' . $conditionSql : '') . $orderBySql, $limit, $offset)
. $lockSql;
}
/**

View File

@ -21,7 +21,8 @@
namespace Doctrine\ORM\Persisters;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\PersistentCollection,
Doctrine\ORM\UnitOfWork;
/**
* Persister for many-to-many collections.
@ -181,4 +182,119 @@ class ManyToManyPersister extends AbstractCollectionPersister
return $params;
}
/**
* {@inheritdoc}
*/
public function count(PersistentCollection $coll)
{
$params = array();
$mapping = $coll->getMapping();
$class = $this->_em->getClassMetadata($mapping['sourceEntity']);
$id = $this->_em->getUnitOfWork()->getEntityIdentifier($coll->getOwner());
if ($mapping['isOwningSide']) {
$joinTable = $mapping['joinTable'];
$joinColumns = $mapping['relationToSourceKeyColumns'];
} else {
$mapping = $this->_em->getClassMetadata($mapping['targetEntity'])->associationMappings[$mapping['mappedBy']];
$joinTable = $mapping['joinTable'];
$joinColumns = $mapping['relationToTargetKeyColumns'];
}
$whereClause = '';
foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
if (isset($joinColumns[$joinTableColumn])) {
if ($whereClause !== '') {
$whereClause .= ' AND ';
}
$whereClause .= "$joinTableColumn = ?";
if ($class->containsForeignIdentifier) {
$params[] = $id[$class->getFieldForColumn($joinColumns[$joinTableColumn])];
} else {
$params[] = $id[$class->fieldNames[$joinColumns[$joinTableColumn]]];
}
}
}
$sql = 'SELECT count(*) FROM ' . $joinTable['name'] . ' WHERE ' . $whereClause;
return $this->_conn->fetchColumn($sql, $params);
}
/**
* @param PersistentCollection $coll
* @param int $offset
* @param int $length
* @return array
*/
public function slice(PersistentCollection $coll, $offset, $length = null)
{
$mapping = $coll->getMapping();
return $this->_em->getUnitOfWork()
->getEntityPersister($mapping['targetEntity'])
->getManyToManyCollection($mapping, $coll->getOwner(), $offset, $length);
}
/**
* @param PersistentCollection $coll
* @param object $element
*/
public function contains(PersistentCollection $coll, $element)
{
$uow = $this->_em->getUnitOfWork();
// shortcut for new entities
if ($uow->getEntityState($element, UnitOfWork::STATE_NEW) == UnitOfWork::STATE_NEW) {
return false;
}
$params = array();
$mapping = $coll->getMapping();
if (!$mapping['isOwningSide']) {
$sourceClass = $this->_em->getClassMetadata($mapping['targetEntity']);
$targetClass = $this->_em->getClassMetadata($mapping['sourceEntity']);
$sourceId = $uow->getEntityIdentifier($element);
$targetId = $uow->getEntityIdentifier($coll->getOwner());
$mapping = $sourceClass->associationMappings[$mapping['mappedBy']];
} else {
$sourceClass = $this->_em->getClassMetadata($mapping['sourceEntity']);
$targetClass = $this->_em->getClassMetadata($mapping['targetEntity']);
$sourceId = $uow->getEntityIdentifier($coll->getOwner());
$targetId = $uow->getEntityIdentifier($element);
}
$joinTable = $mapping['joinTable'];
$whereClause = '';
foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
if (isset($mapping['relationToTargetKeyColumns'][$joinTableColumn])) {
if ($whereClause !== '') {
$whereClause .= ' AND ';
}
$whereClause .= "$joinTableColumn = ?";
if ($targetClass->containsForeignIdentifier) {
$params[] = $targetId[$targetClass->getFieldForColumn($mapping['relationToTargetKeyColumns'][$joinTableColumn])];
} else {
$params[] = $targetId[$targetClass->fieldNames[$mapping['relationToTargetKeyColumns'][$joinTableColumn]]];
}
} else if (isset($mapping['relationToSourceKeyColumns'][$joinTableColumn])) {
if ($whereClause !== '') {
$whereClause .= ' AND ';
}
$whereClause .= "$joinTableColumn = ?";
if ($sourceClass->containsForeignIdentifier) {
$params[] = $sourceId[$sourceClass->getFieldForColumn($mapping['relationToSourceKeyColumns'][$joinTableColumn])];
} else {
$params[] = $sourceId[$sourceClass->fieldNames[$mapping['relationToSourceKeyColumns'][$joinTableColumn]]];
}
}
}
$sql = 'SELECT 1 FROM ' . $joinTable['name'] . ' WHERE ' . $whereClause;
return (bool)$this->_conn->fetchColumn($sql, $params);
}
}

View File

@ -21,7 +21,8 @@
namespace Doctrine\ORM\Persisters;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\PersistentCollection,
Doctrine\ORM\UnitOfWork;
/**
* Persister for one-to-many collections.
@ -116,4 +117,67 @@ class OneToManyPersister extends AbstractCollectionPersister
*/
protected function _getDeleteRowSQLParameters(PersistentCollection $coll, $element)
{}
/**
* {@inheritdoc}
*/
public function count(PersistentCollection $coll)
{
$mapping = $coll->getMapping();
$class = $this->_em->getClassMetadata($mapping['targetEntity']);
$params = array();
$id = $this->_em->getUnitOfWork()->getEntityIdentifier($coll->getOwner());
$where = '';
foreach ($class->associationMappings[$mapping['mappedBy']]['joinColumns'] AS $joinColumn) {
if ($where != '') {
$where .= ' AND ';
}
$where .= $joinColumn['name'] . " = ?";
if ($class->containsForeignIdentifier) {
$params[] = $id[$class->getFieldForColumn($joinColumn['referencedColumnName'])];
} else {
$params[] = $id[$class->fieldNames[$joinColumn['referencedColumnName']]];
}
}
$sql = "SELECT count(*) FROM " . $class->getQuotedTableName($this->_conn->getDatabasePlatform()) . " WHERE " . $where;
return $this->_conn->fetchColumn($sql, $params);
}
/**
* @param PersistentCollection $coll
* @param int $offset
* @param int $length
* @return \Doctrine\Common\Collections\ArrayCollection
*/
public function slice(PersistentCollection $coll, $offset, $length = null)
{
$mapping = $coll->getMapping();
return $this->_em->getUnitOfWork()
->getEntityPersister($mapping['targetEntity'])
->getOneToManyCollection($mapping, $coll->getOwner(), $offset, $length);
}
/**
* @param PersistentCollection $coll
* @param object $element
*/
public function contains(PersistentCollection $coll, $element)
{
$mapping = $coll->getMapping();
$uow = $this->_em->getUnitOfWork();
// shortcut for new entities
if ($uow->getEntityState($element, UnitOfWork::STATE_NEW) == UnitOfWork::STATE_NEW) {
return false;
}
// only works with single id identifier entities. Will throw an exception in Entity Persisters
// if that is not the case for the 'mappedBy' field.
$id = current( $uow->getEntityIdentifier($coll->getOwner()) );
return $uow->getEntityPersister($mapping['targetEntity'])
->exists($element, array($mapping['mappedBy'] => $id));
}
}

View File

@ -1958,11 +1958,11 @@ class UnitOfWork implements PropertyChangedListener
$reflField = $class->reflFields[$field];
$reflField->setValue($entity, $pColl);
if ($assoc['fetch'] == ClassMetadata::FETCH_LAZY) {
$pColl->setInitialized(false);
} else {
if ($assoc['fetch'] == ClassMetadata::FETCH_EAGER) {
$this->loadCollection($pColl);
$pColl->takeSnapshot();
} else {
$pColl->setInitialized(false);
}
$this->originalEntityData[$oid][$field] = $pColl;
}
@ -2123,7 +2123,7 @@ class UnitOfWork implements PropertyChangedListener
* Gets the EntityPersister for an Entity.
*
* @param string $entityName The name of the Entity.
* @return Doctrine\ORM\Persister\AbstractEntityPersister
* @return Doctrine\ORM\Persisters\AbstractEntityPersister
*/
public function getEntityPersister($entityName)
{

View File

@ -59,7 +59,7 @@ class EntityPersisterMock extends \Doctrine\ORM\Persisters\BasicEntityPersister
$this->_updates[] = $entity;
}
public function exists($entity)
public function exists($entity, array $extraConditions = array())
{
$this->existsCalled = true;
}

View File

@ -55,6 +55,7 @@ class AllTests
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\IdentityMapTest');
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\DatabaseDriverTest');
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\PostgreSQLIdentityStrategyTest');
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\ExtraLazyCollectionTest');
$suite->addTest(Locking\AllTests::suite());
$suite->addTest(Ticket\AllTests::suite());

View File

@ -9,8 +9,6 @@ use Doctrine\Tests\Models\CMS\CmsAddress;
require_once __DIR__ . '/../../TestInit.php';
/**
* Description of DetachedEntityTest
*
* @author robo
*/
class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase

View File

@ -0,0 +1,375 @@
<?php
namespace Doctrine\Tests\ORM\Functional;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
require_once __DIR__ . '/../../TestInit.php';
/**
* Description of ExtraLazyCollectionTest
*
* @author beberlei
*/
class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
{
private $userId;
private $groupId;
private $articleId;
public function setUp()
{
$this->useModelSet('cms');
parent::setUp();
$class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$class->associationMappings['groups']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY;
$class->associationMappings['articles']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY;
$class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup');
$class->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY;
$this->loadFixture();
}
public function tearDown()
{
parent::tearDown();
$class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$class->associationMappings['groups']['fetch'] = ClassMetadataInfo::FETCH_LAZY;
$class->associationMappings['articles']['fetch'] = ClassMetadataInfo::FETCH_LAZY;
$class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup');
$class->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_LAZY;
}
/**
* @group DDC-546
*/
public function testCountNotInitializesCollection()
{
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
$queryCount = $this->getCurrentQueryCount();
$this->assertFalse($user->groups->isInitialized());
$this->assertEquals(3, count($user->groups));
$this->assertFalse($user->groups->isInitialized());
foreach ($user->groups AS $group) { }
$this->assertEquals($queryCount + 2, $this->getCurrentQueryCount(), "Expecting two queries to be fired for count, then iteration.");
}
/**
* @group DDC-546
*/
public function testCountWhenNewEntitysPresent()
{
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
$newGroup = new \Doctrine\Tests\Models\CMS\CmsGroup();
$newGroup->name = "Test4";
$user->addGroup($newGroup);
$this->_em->persist($newGroup);
$this->assertFalse($user->groups->isInitialized());
$this->assertEquals(4, count($user->groups));
$this->assertFalse($user->groups->isInitialized());
}
/**
* @group DDC-546
*/
public function testCountWhenInitialized()
{
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
$queryCount = $this->getCurrentQueryCount();
foreach ($user->groups AS $group) { }
$this->assertTrue($user->groups->isInitialized());
$this->assertEquals(3, count($user->groups));
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Should only execute one query to initialize colleciton, no extra query for count() more.");
}
/**
* @group DDC-546
*/
public function testCountInverseCollection()
{
$group = $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId);
$this->assertFalse($group->users->isInitialized(), "Pre-Condition");
$this->assertEquals(4, count($group->users));
$this->assertFalse($group->users->isInitialized(), "Extra Lazy collection should not be initialized by counting the collection.");
}
/**
* @group DDC-546
*/
public function testCountOneToMany()
{
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
$this->assertFalse($user->groups->isInitialized(), "Pre-Condition");
$this->assertEquals(2, count($user->articles));
}
/**
* @group DDC-546
*/
public function testFullSlice()
{
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
$this->assertFalse($user->groups->isInitialized(), "Pre-Condition: Collection is not initialized.");
$someGroups = $user->groups->slice(null);
$this->assertEquals(3, count($someGroups));
}
/**
* @group DDC-546
*/
public function testSlice()
{
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
$this->assertFalse($user->groups->isInitialized(), "Pre-Condition: Collection is not initialized.");
$queryCount = $this->getCurrentQueryCount();
$someGroups = $user->groups->slice(0, 2);
$this->assertContainsOnly('Doctrine\Tests\Models\CMS\CmsGroup', $someGroups);
$this->assertEquals(2, count($someGroups));
$this->assertFalse($user->groups->isInitialized(), "Slice should not initialize the collection if it wasn't before!");
$otherGroup = $user->groups->slice(2, 1);
$this->assertContainsOnly('Doctrine\Tests\Models\CMS\CmsGroup', $otherGroup);
$this->assertEquals(1, count($otherGroup));
$this->assertFalse($user->groups->isInitialized());
foreach ($user->groups AS $group) { }
$this->assertTrue($user->groups->isInitialized());
$this->assertEquals(3, count($user->groups));
$this->assertEquals($queryCount + 3, $this->getCurrentQueryCount());
}
/**
* @group DDC-546
*/
public function testSliceInitializedCollection()
{
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
$queryCount = $this->getCurrentQueryCount();
foreach ($user->groups AS $group) { }
$someGroups = $user->groups->slice(0, 2);
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount());
$this->assertEquals(2, count($someGroups));
$this->assertTrue($user->groups->contains($someGroups[0]));
$this->assertTrue($user->groups->contains($someGroups[1]));
}
/**
* @group DDC-546
*/
public function testSliceInverseCollection()
{
$group = $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId);
$this->assertFalse($group->users->isInitialized(), "Pre-Condition");
$queryCount = $this->getCurrentQueryCount();
$someUsers = $group->users->slice(0, 2);
$otherUsers = $group->users->slice(2, 2);
$this->assertContainsOnly('Doctrine\Tests\Models\CMS\CmsUser', $someUsers);
$this->assertContainsOnly('Doctrine\Tests\Models\CMS\CmsUser', $otherUsers);
$this->assertEquals(2, count($someUsers));
$this->assertEquals(2, count($otherUsers));
// +2 queries executed by slice, +4 are executed by EAGER fetching of User Address.
$this->assertEquals($queryCount + 2 + 4, $this->getCurrentQueryCount());
}
/**
* @group DDC-546
*/
public function testSliceOneToMany()
{
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
$this->assertFalse($user->articles->isInitialized(), "Pre-Condition: Collection is not initialized.");
$queryCount = $this->getCurrentQueryCount();
$someArticle = $user->articles->slice(0, 1);
$otherArticle = $user->articles->slice(1, 1);
$this->assertEquals($queryCount + 2, $this->getCurrentQueryCount());
}
/**
* @group DDC-546
*/
public function testContainsOneToMany()
{
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
$this->assertFalse($user->articles->isInitialized(), "Pre-Condition: Collection is not initialized.");
$article = $this->_em->find('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId);
$queryCount = $this->getCurrentQueryCount();
$this->assertTrue($user->articles->contains($article));
$this->assertFalse($user->articles->isInitialized(), "Post-Condition: Collection is not initialized.");
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount());
$article = new \Doctrine\Tests\Models\CMS\CmsArticle();
$article->topic = "Testnew";
$article->text = "blub";
$queryCount = $this->getCurrentQueryCount();
$this->assertFalse($user->articles->contains($article));
$this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Checking for contains of new entity should cause no query to be executed.");
$this->_em->persist($article);
$this->_em->flush();
$queryCount = $this->getCurrentQueryCount();
$this->assertFalse($user->articles->contains($article));
$this->assertEquals($queryCount+1, $this->getCurrentQueryCount(), "Checking for contains of managed entity should cause one query to be executed.");
$this->assertFalse($user->articles->isInitialized(), "Post-Condition: Collection is not initialized.");
}
/**
* @group DDC-546
*/
public function testContainsManyToMany()
{
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
$this->assertFalse($user->groups->isInitialized(), "Pre-Condition: Collection is not initialized.");
$group = $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId);
$queryCount = $this->getCurrentQueryCount();
$this->assertTrue($user->groups->contains($group));
$this->assertEquals($queryCount+1, $this->getCurrentQueryCount(), "Checking for contains of managed entity should cause one query to be executed.");
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
$group = new \Doctrine\Tests\Models\CMS\CmsGroup();
$group->name = "A New group!";
$queryCount = $this->getCurrentQueryCount();
$this->assertFalse($user->groups->contains($group));
$this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Checking for contains of new entity should cause no query to be executed.");
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
$this->_em->persist($group);
$this->_em->flush();
$queryCount = $this->getCurrentQueryCount();
$this->assertFalse($user->groups->contains($group));
$this->assertEquals($queryCount+1, $this->getCurrentQueryCount(), "Checking for contains of managed entity should cause one query to be executed.");
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
}
/**
* @group DDC-546
*/
public function testContainsManyToManyInverse()
{
$group = $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId);
$this->assertFalse($group->users->isInitialized(), "Pre-Condition: Collection is not initialized.");
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
$queryCount = $this->getCurrentQueryCount();
$this->assertTrue($group->users->contains($user));
$this->assertEquals($queryCount+1, $this->getCurrentQueryCount(), "Checking for contains of managed entity should cause one query to be executed.");
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
$newUser = new \Doctrine\Tests\Models\CMS\CmsUser();
$newUser->name = "A New group!";
$queryCount = $this->getCurrentQueryCount();
$this->assertFalse($group->users->contains($newUser));
$this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Checking for contains of new entity should cause no query to be executed.");
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
}
private function loadFixture()
{
$user1 = new \Doctrine\Tests\Models\CMS\CmsUser();
$user1->username = "beberlei";
$user1->name = "Benjamin";
$user1->status = "active";
$user2 = new \Doctrine\Tests\Models\CMS\CmsUser();
$user2->username = "jwage";
$user2->name = "Jonathan";
$user2->status = "active";
$user3 = new \Doctrine\Tests\Models\CMS\CmsUser();
$user3->username = "romanb";
$user3->name = "Roman";
$user3->status = "active";
$user4 = new \Doctrine\Tests\Models\CMS\CmsUser();
$user4->username = "gblanco";
$user4->name = "Guilherme";
$user4->status = "active";
$this->_em->persist($user1);
$this->_em->persist($user2);
$this->_em->persist($user3);
$this->_em->persist($user4);
$group1 = new \Doctrine\Tests\Models\CMS\CmsGroup();
$group1->name = "Test1";
$group2 = new \Doctrine\Tests\Models\CMS\CmsGroup();
$group2->name = "Test2";
$group3 = new \Doctrine\Tests\Models\CMS\CmsGroup();
$group3->name = "Test3";
$user1->addGroup($group1);
$user1->addGroup($group2);
$user1->addGroup($group3);
$user2->addGroup($group1);
$user3->addGroup($group1);
$user4->addGroup($group1);
$this->_em->persist($group1);
$this->_em->persist($group2);
$this->_em->persist($group3);
$article1 = new \Doctrine\Tests\Models\CMS\CmsArticle();
$article1->topic = "Test";
$article1->text = "Test";
$article1->setAuthor($user1);
$article2 = new \Doctrine\Tests\Models\CMS\CmsArticle();
$article2->topic = "Test";
$article2->text = "Test";
$article2->setAuthor($user1);
$this->_em->persist($article1);
$this->_em->persist($article2);
$this->_em->flush();
$this->_em->clear();
$this->articleId = $article1->id;
$this->userId = $user1->getId();
$this->groupId = $group1->id;
}
}

View File

@ -314,4 +314,14 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
}
throw $e;
}
/**
* Using the SQL Logger Stack this method retrieves the current query count executed in this test.
*
* @return int
*/
protected function getCurrentQueryCount()
{
return count($this->_sqlLoggerStack->queries);
}
}