Entra-lazy for containsKey on collections
This commit is contained in:
parent
626efdafd4
commit
557686aa0a
@ -471,6 +471,13 @@ final class PersistentCollection implements Collection, Selectable
|
||||
*/
|
||||
public function containsKey($key)
|
||||
{
|
||||
|
||||
if (! $this->initialized && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY
|
||||
&& isset($this->association['indexBy'])) {
|
||||
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
|
||||
|
||||
return $this->coll->containsKey($key) || $persister->containsKey($this, $key);
|
||||
}
|
||||
$this->initialize();
|
||||
|
||||
return $this->coll->containsKey($key);
|
||||
@ -778,7 +785,7 @@ final class PersistentCollection implements Collection, Selectable
|
||||
public function next()
|
||||
{
|
||||
$this->initialize();
|
||||
|
||||
|
||||
return $this->coll->next();
|
||||
}
|
||||
|
||||
|
@ -265,7 +265,16 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
||||
|
||||
return $this->em->getUnitOfWork()->getEntityPersister($mapping['targetEntity'])->getManyToManyCollection($mapping, $coll->getOwner(), $offset, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function containsKey(PersistentCollection $coll, $key)
|
||||
{
|
||||
list($quotedJoinTable, $whereClauses, $params) = $this->getJoinTableRestrictionsWithKey($coll, $key, true);
|
||||
$sql = 'SELECT 1 FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses);
|
||||
return (bool) $this->conn->fetchColumn($sql, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -319,6 +328,75 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
||||
return (bool) $this->conn->executeUpdate($sql, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\PersistentCollection $coll
|
||||
* @param string $key
|
||||
* @param boolean $addFilters Whether the filter SQL should be included or not.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getJoinTableRestrictionsWithKey(PersistentCollection $coll, $key, $addFilters)
|
||||
{
|
||||
$uow = $this->em->getUnitOfWork();
|
||||
$filterMapping = $coll->getMapping();
|
||||
$mapping = $filterMapping;
|
||||
$indexBy = $mapping['indexBy'];
|
||||
$wasOwning = $mapping['isOwningSide'];
|
||||
$id = $uow->getEntityIdentifier($coll->getOwner());
|
||||
|
||||
$targetEntity = $this->em->getClassMetadata($mapping['targetEntity']);
|
||||
|
||||
if (! $mapping['isOwningSide']) {
|
||||
$associationSourceClass = $this->em->getClassMetadata($mapping['targetEntity']);
|
||||
$mapping = $associationSourceClass->associationMappings[$mapping['mappedBy']];
|
||||
} else {
|
||||
$associationSourceClass = $this->em->getClassMetadata($mapping['sourceEntity']);
|
||||
}
|
||||
|
||||
$quotedJoinTable = $this->quoteStrategy->getJoinTableName($mapping, $associationSourceClass, $this->platform). ' t';
|
||||
$whereClauses = array();
|
||||
$params = array();
|
||||
|
||||
$joinNeeded = !in_array($indexBy, $targetEntity->identifier);
|
||||
|
||||
if ($joinNeeded) { // extra join needed if indexBy is not a @id
|
||||
$joinConditions = array();
|
||||
foreach ($wasOwning?$mapping['joinTable']['inverseJoinColumns']:$mapping['joinTable']['joinColumns'] as $joinTableColumn) {
|
||||
$joinConditions[] = 't.'.$joinTableColumn['name'].' = tr.'.$joinTableColumn['referencedColumnName'];
|
||||
}
|
||||
$tableName = $this->quoteStrategy->getTableName($targetEntity, $this->platform);
|
||||
$quotedJoinTable .= ' JOIN '. $tableName. ' tr ON '.implode(' AND ', $joinConditions);
|
||||
|
||||
$whereClauses[] = 'tr.'.$targetEntity->getColumnName($indexBy).' = ?';
|
||||
$params[] = $key;
|
||||
|
||||
}
|
||||
|
||||
foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
|
||||
|
||||
|
||||
if (isset($mapping['relationToTargetKeyColumns'][$joinTableColumn])) {
|
||||
$whereClauses[] = 't.' . $joinTableColumn . ' = ?';
|
||||
$params[] = $targetEntity->containsForeignIdentifier
|
||||
? $id[$targetEntity->getFieldForColumn($mapping['relationToTargetKeyColumns'][$joinTableColumn])]
|
||||
: $id[$targetEntity->fieldNames[$mapping['relationToTargetKeyColumns'][$joinTableColumn]]];
|
||||
} elseif (!$joinNeeded) {
|
||||
$whereClauses[] = 't.' . $joinTableColumn . ' = ?';
|
||||
$params[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
if ($addFilters) {
|
||||
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($filterMapping);
|
||||
|
||||
if ($filterSql) {
|
||||
$quotedJoinTable .= ' ' . $joinTargetEntitySQL;
|
||||
$whereClauses[] = $filterSql;
|
||||
}
|
||||
}
|
||||
|
||||
return array($quotedJoinTable, $whereClauses, $params);
|
||||
}
|
||||
/**
|
||||
* @param \Doctrine\ORM\PersistentCollection $coll
|
||||
* @param object $element
|
||||
|
@ -131,6 +131,45 @@ class OneToManyPersister extends AbstractCollectionPersister
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function count(PersistentCollection $coll)
|
||||
{
|
||||
list($quotedJoinTable, $whereClauses, $params) = $this->getJoinTableRestrictions($coll, true);
|
||||
|
||||
$sql = 'SELECT count(*) FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses);
|
||||
|
||||
return $this->conn->fetchColumn($sql, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function slice(PersistentCollection $coll, $offset, $length = null)
|
||||
{
|
||||
$mapping = $coll->getMapping();
|
||||
$uow = $this->em->getUnitOfWork();
|
||||
$persister = $uow->getEntityPersister($mapping['targetEntity']);
|
||||
|
||||
return $persister->getOneToManyCollection($mapping, $coll->getOwner(), $offset, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function containsKey(PersistentCollection $coll, $key)
|
||||
{
|
||||
list($quotedJoinTable, $whereClauses, $params) = $this->getJoinTableRestrictions($coll, true);
|
||||
|
||||
$mapping = $coll->getMapping();
|
||||
$sourceClass = $this->em->getClassMetadata($mapping['sourceEntity']);
|
||||
|
||||
$whereClauses[] = $sourceClass->getColumnName($mapping['indexBy']) . ' = ?';
|
||||
$params[] = $key;
|
||||
|
||||
$sql = 'SELECT 1 FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses);
|
||||
|
||||
return (bool) $this->conn->fetchColumn($sql, $params);
|
||||
}
|
||||
|
||||
private function getJoinTableRestrictions(PersistentCollection $coll, $addFilters)
|
||||
{
|
||||
$mapping = $coll->getMapping();
|
||||
$targetClass = $this->em->getClassMetadata($mapping['targetEntity']);
|
||||
@ -149,30 +188,18 @@ class OneToManyPersister extends AbstractCollectionPersister
|
||||
: $id[$sourceClass->fieldNames[$joinColumn['referencedColumnName']]];
|
||||
}
|
||||
|
||||
$filterTargetClass = $this->em->getClassMetadata($targetClass->rootEntityName);
|
||||
foreach ($this->em->getFilters()->getEnabledFilters() as $filter) {
|
||||
if ($filterExpr = $filter->addFilterConstraint($filterTargetClass, 't')) {
|
||||
$whereClauses[] = '(' . $filterExpr . ')';
|
||||
if ($addFilters) {
|
||||
$filterTargetClass = $this->em->getClassMetadata($targetClass->rootEntityName);
|
||||
foreach ($this->em->getFilters()->getEnabledFilters() as $filter) {
|
||||
if ($filterExpr = $filter->addFilterConstraint($filterTargetClass, 't')) {
|
||||
$whereClauses[] = '(' . $filterExpr . ')';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sql = 'SELECT count(*)'
|
||||
. ' FROM ' . $this->quoteStrategy->getTableName($targetClass, $this->platform) . ' t'
|
||||
. ' WHERE ' . implode(' AND ', $whereClauses);
|
||||
$quotedJoinTable = $this->quoteStrategy->getTableName($targetClass, $this->platform) . ' t';
|
||||
|
||||
return $this->conn->fetchColumn($sql, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function slice(PersistentCollection $coll, $offset, $length = null)
|
||||
{
|
||||
$mapping = $coll->getMapping();
|
||||
$uow = $this->em->getUnitOfWork();
|
||||
$persister = $uow->getEntityPersister($mapping['targetEntity']);
|
||||
|
||||
return $persister->getOneToManyCollection($mapping, $coll->getOwner(), $offset, $length);
|
||||
return array($quotedJoinTable, $whereClauses, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -200,7 +227,7 @@ class OneToManyPersister extends AbstractCollectionPersister
|
||||
// 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()));
|
||||
$id = current($uow->getEntityIdentifier($coll->getOwner()));
|
||||
|
||||
return $persister->exists($element, array($mapping['mappedBy'] => $id));
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
$class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup');
|
||||
$class->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY;
|
||||
$class->associationMappings['users']['indexBy'] = 'username';
|
||||
|
||||
$this->loadFixture();
|
||||
}
|
||||
@ -539,7 +540,6 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
/* @var $user CmsUser */
|
||||
|
||||
$queryCount = $this->getCurrentQueryCount();
|
||||
|
||||
$phonenumber = $user->phonenumbers->get($this->phonenumber);
|
||||
|
||||
$this->assertFalse($user->phonenumbers->isInitialized());
|
||||
@ -576,6 +576,106 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertNull($user->articles->get(-1));
|
||||
}
|
||||
|
||||
public function testContainsKeyIndexByOneToMany()
|
||||
{
|
||||
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||
/* @var $user CmsUser */
|
||||
|
||||
$queryCount = $this->getCurrentQueryCount();
|
||||
|
||||
$contains = $user->articles->containsKey($this->topic);
|
||||
|
||||
$this->assertTrue($contains);
|
||||
$this->assertFalse($user->articles->isInitialized());
|
||||
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount());
|
||||
}
|
||||
|
||||
public function testContainsKeyIndexByManyToMany()
|
||||
{
|
||||
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||
|
||||
$group = $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId);
|
||||
|
||||
$queryCount = $this->getCurrentQueryCount();
|
||||
|
||||
$contains = $user->groups->containsKey($group->name);
|
||||
|
||||
$this->assertTrue($contains, "The item is not into collection");
|
||||
$this->assertFalse($user->groups->isInitialized(), "The collection must not be initialized");
|
||||
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount());
|
||||
}
|
||||
public function testContainsKeyIndexByManyToManyNonOwning()
|
||||
{
|
||||
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||
$group = $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId);
|
||||
|
||||
$queryCount = $this->getCurrentQueryCount();
|
||||
|
||||
$contains = $group->users->containsKey($user->username);
|
||||
|
||||
$this->assertTrue($contains, "The item is not into collection");
|
||||
$this->assertFalse($group->users->isInitialized(), "The collection must not be initialized");
|
||||
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount());
|
||||
}
|
||||
|
||||
public function testContainsKeyIndexByWithPkManyToMany()
|
||||
{
|
||||
$class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
$class->associationMappings['groups']['indexBy'] = 'id';
|
||||
|
||||
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||
|
||||
$queryCount = $this->getCurrentQueryCount();
|
||||
|
||||
$contains = $user->groups->containsKey($this->groupId);
|
||||
|
||||
$this->assertTrue($contains, "The item is not into collection");
|
||||
$this->assertFalse($user->groups->isInitialized(), "The collection must not be initialized");
|
||||
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount());
|
||||
}
|
||||
public function testContainsKeyIndexByWithPkManyToManyNonOwning()////
|
||||
{
|
||||
$class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup');
|
||||
$class->associationMappings['users']['indexBy'] = 'id';
|
||||
|
||||
$group = $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId);
|
||||
|
||||
$queryCount = $this->getCurrentQueryCount();
|
||||
|
||||
$contains = $group->users->containsKey($this->userId);
|
||||
|
||||
$this->assertTrue($contains, "The item is not into collection");
|
||||
$this->assertFalse($group->users->isInitialized(), "The collection must not be initialized");
|
||||
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount());
|
||||
}
|
||||
|
||||
public function testContainsKeyNonExistentIndexByOneToMany()
|
||||
{
|
||||
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||
|
||||
$queryCount = $this->getCurrentQueryCount();
|
||||
|
||||
$contains = $user->articles->containsKey("NonExistentTopic");
|
||||
|
||||
$this->assertFalse($contains);
|
||||
$this->assertFalse($user->articles->isInitialized());
|
||||
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount());
|
||||
}
|
||||
|
||||
public function testContainsKeyNonExistentIndexByManyToMany()
|
||||
{
|
||||
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||
|
||||
|
||||
$queryCount = $this->getCurrentQueryCount();
|
||||
|
||||
$contains = $user->groups->containsKey("NonExistentTopic");
|
||||
|
||||
$this->assertFalse($contains);
|
||||
$this->assertFalse($user->groups->isInitialized());
|
||||
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount());
|
||||
}
|
||||
|
||||
private function loadFixture()
|
||||
{
|
||||
$user1 = new \Doctrine\Tests\Models\CMS\CmsUser();
|
||||
@ -646,6 +746,8 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->_em->persist($phonenumber1);
|
||||
$this->_em->persist($phonenumber2);
|
||||
|
||||
$user1->addPhonenumber($phonenumber1);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
@ -655,5 +757,7 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
$this->topic = $article1->topic;
|
||||
$this->phonenumber = $phonenumber1->phonenumber;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user