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)
|
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();
|
$this->initialize();
|
||||||
|
|
||||||
return $this->coll->containsKey($key);
|
return $this->coll->containsKey($key);
|
||||||
|
@ -265,6 +265,15 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
|||||||
|
|
||||||
return $this->em->getUnitOfWork()->getEntityPersister($mapping['targetEntity'])->getManyToManyCollection($mapping, $coll->getOwner(), $offset, $length);
|
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}
|
* {@inheritdoc}
|
||||||
@ -319,6 +328,75 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
|||||||
return (bool) $this->conn->executeUpdate($sql, $params);
|
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 \Doctrine\ORM\PersistentCollection $coll
|
||||||
* @param object $element
|
* @param object $element
|
||||||
|
@ -131,6 +131,45 @@ class OneToManyPersister extends AbstractCollectionPersister
|
|||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function count(PersistentCollection $coll)
|
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();
|
$mapping = $coll->getMapping();
|
||||||
$targetClass = $this->em->getClassMetadata($mapping['targetEntity']);
|
$targetClass = $this->em->getClassMetadata($mapping['targetEntity']);
|
||||||
@ -149,30 +188,18 @@ class OneToManyPersister extends AbstractCollectionPersister
|
|||||||
: $id[$sourceClass->fieldNames[$joinColumn['referencedColumnName']]];
|
: $id[$sourceClass->fieldNames[$joinColumn['referencedColumnName']]];
|
||||||
}
|
}
|
||||||
|
|
||||||
$filterTargetClass = $this->em->getClassMetadata($targetClass->rootEntityName);
|
if ($addFilters) {
|
||||||
foreach ($this->em->getFilters()->getEnabledFilters() as $filter) {
|
$filterTargetClass = $this->em->getClassMetadata($targetClass->rootEntityName);
|
||||||
if ($filterExpr = $filter->addFilterConstraint($filterTargetClass, 't')) {
|
foreach ($this->em->getFilters()->getEnabledFilters() as $filter) {
|
||||||
$whereClauses[] = '(' . $filterExpr . ')';
|
if ($filterExpr = $filter->addFilterConstraint($filterTargetClass, 't')) {
|
||||||
|
$whereClauses[] = '(' . $filterExpr . ')';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$sql = 'SELECT count(*)'
|
$quotedJoinTable = $this->quoteStrategy->getTableName($targetClass, $this->platform) . ' t';
|
||||||
. ' FROM ' . $this->quoteStrategy->getTableName($targetClass, $this->platform) . ' t'
|
|
||||||
. ' WHERE ' . implode(' AND ', $whereClauses);
|
|
||||||
|
|
||||||
return $this->conn->fetchColumn($sql, $params);
|
return array($quotedJoinTable, $whereClauses, $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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -200,7 +227,7 @@ class OneToManyPersister extends AbstractCollectionPersister
|
|||||||
// only works with single id identifier entities. Will throw an
|
// only works with single id identifier entities. Will throw an
|
||||||
// exception in Entity Persisters if that is not the case for the
|
// exception in Entity Persisters if that is not the case for the
|
||||||
// 'mappedBy' field.
|
// 'mappedBy' field.
|
||||||
$id = current( $uow->getEntityIdentifier($coll->getOwner()));
|
$id = current($uow->getEntityIdentifier($coll->getOwner()));
|
||||||
|
|
||||||
return $persister->exists($element, array($mapping['mappedBy'] => $id));
|
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 = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup');
|
||||||
$class->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY;
|
$class->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY;
|
||||||
|
$class->associationMappings['users']['indexBy'] = 'username';
|
||||||
|
|
||||||
$this->loadFixture();
|
$this->loadFixture();
|
||||||
}
|
}
|
||||||
@ -539,7 +540,6 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
/* @var $user CmsUser */
|
/* @var $user CmsUser */
|
||||||
|
|
||||||
$queryCount = $this->getCurrentQueryCount();
|
$queryCount = $this->getCurrentQueryCount();
|
||||||
|
|
||||||
$phonenumber = $user->phonenumbers->get($this->phonenumber);
|
$phonenumber = $user->phonenumbers->get($this->phonenumber);
|
||||||
|
|
||||||
$this->assertFalse($user->phonenumbers->isInitialized());
|
$this->assertFalse($user->phonenumbers->isInitialized());
|
||||||
@ -576,6 +576,106 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
$this->assertNull($user->articles->get(-1));
|
$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()
|
private function loadFixture()
|
||||||
{
|
{
|
||||||
$user1 = new \Doctrine\Tests\Models\CMS\CmsUser();
|
$user1 = new \Doctrine\Tests\Models\CMS\CmsUser();
|
||||||
@ -646,6 +746,8 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
$this->_em->persist($phonenumber1);
|
$this->_em->persist($phonenumber1);
|
||||||
$this->_em->persist($phonenumber2);
|
$this->_em->persist($phonenumber2);
|
||||||
|
|
||||||
|
$user1->addPhonenumber($phonenumber1);
|
||||||
|
|
||||||
$this->_em->flush();
|
$this->_em->flush();
|
||||||
$this->_em->clear();
|
$this->_em->clear();
|
||||||
|
|
||||||
@ -655,5 +757,7 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
|
|
||||||
$this->topic = $article1->topic;
|
$this->topic = $article1->topic;
|
||||||
$this->phonenumber = $phonenumber1->phonenumber;
|
$this->phonenumber = $phonenumber1->phonenumber;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user