Merge pull request #1249 from doctrine/extra-lazy-get-m2m
Support for extra lazy get for both owning and inverse side on many to many associations.
This commit is contained in:
commit
55a75bfb1b
@ -524,7 +524,6 @@ final class PersistentCollection implements Collection, Selectable
|
|||||||
public function get($key)
|
public function get($key)
|
||||||
{
|
{
|
||||||
if ( ! $this->initialized
|
if ( ! $this->initialized
|
||||||
&& $this->association['type'] === Mapping\ClassMetadataInfo::ONE_TO_MANY
|
|
||||||
&& $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY
|
&& $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY
|
||||||
&& isset($this->association['indexBy'])
|
&& isset($this->association['indexBy'])
|
||||||
) {
|
) {
|
||||||
|
@ -1619,14 +1619,29 @@ class BasicEntityPersister implements EntityPersister
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isset($this->class->associationMappings[$field])) {
|
if (isset($this->class->associationMappings[$field])) {
|
||||||
|
$association = $this->class->associationMappings[$field];
|
||||||
|
|
||||||
if ( ! $this->class->associationMappings[$field]['isOwningSide']) {
|
// Many-To-Many requires join table check for joinColumn
|
||||||
|
if ($association['type'] === ClassMetadata::MANY_TO_MANY) {
|
||||||
|
if ( ! $association['isOwningSide']) {
|
||||||
|
$association = $assoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
$joinTableName = $this->quoteStrategy->getJoinTableName($association, $this->class, $this->platform);
|
||||||
|
$joinColumn = $assoc['isOwningSide']
|
||||||
|
? $association['joinTable']['joinColumns'][0]
|
||||||
|
: $association['joinTable']['inverseJoinColumns'][0];
|
||||||
|
|
||||||
|
return $joinTableName . '.' . $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! $association['isOwningSide']) {
|
||||||
throw ORMException::invalidFindByInverseAssociation($this->class->name, $field);
|
throw ORMException::invalidFindByInverseAssociation($this->class->name, $field);
|
||||||
}
|
}
|
||||||
|
|
||||||
$joinColumn = $this->class->associationMappings[$field]['joinColumns'][0];
|
$joinColumn = $association['joinColumns'][0];
|
||||||
$className = (isset($this->class->associationMappings[$field]['inherited']))
|
$className = (isset($association['inherited']))
|
||||||
? $this->class->associationMappings[$field]['inherited']
|
? $association['inherited']
|
||||||
: $this->class->name;
|
: $this->class->name;
|
||||||
|
|
||||||
return $this->getSQLTableAlias($className) . '.' . $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform);
|
return $this->getSQLTableAlias($className) . '.' . $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform);
|
||||||
@ -1765,6 +1780,28 @@ class BasicEntityPersister implements EntityPersister
|
|||||||
$type = $this->class->fieldMappings[$field]['type'];
|
$type = $this->class->fieldMappings[$field]['type'];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case (isset($this->class->associationMappings[$field]) && $this->class->associationMappings[$field]['type'] === ClassMetadata::MANY_TO_MANY):
|
||||||
|
$assoc = $this->class->associationMappings[$field];
|
||||||
|
$targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
|
||||||
|
|
||||||
|
if ( ! $assoc['isOwningSide']) {
|
||||||
|
$assoc = $targetClass->associationMappings[$assoc['mappedBy']];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($assoc['relationToTargetKeyColumns']) > 1) {
|
||||||
|
throw Query\QueryException::associationPathCompositeKeyNotSupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
$targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
|
||||||
|
$targetColumn = $assoc['joinTable']['inverseJoinColumns'][0]['referencedColumnName'];
|
||||||
|
$type = null;
|
||||||
|
|
||||||
|
if (isset($targetClass->fieldNames[$targetColumn])) {
|
||||||
|
$type = $targetClass->fieldMappings[$targetClass->fieldNames[$targetColumn]]['type'];
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case (isset($this->class->associationMappings[$field])):
|
case (isset($this->class->associationMappings[$field])):
|
||||||
$assoc = $this->class->associationMappings[$field];
|
$assoc = $this->class->associationMappings[$field];
|
||||||
|
|
||||||
|
@ -77,7 +77,19 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
|||||||
*/
|
*/
|
||||||
public function get(PersistentCollection $coll, $index)
|
public function get(PersistentCollection $coll, $index)
|
||||||
{
|
{
|
||||||
throw new \BadMethodCallException("Selecting a collection by index is not supported by this CollectionPersister.");
|
$mapping = $coll->getMapping();
|
||||||
|
|
||||||
|
if ( ! isset($mapping['indexBy'])) {
|
||||||
|
throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$persister = $this->uow->getEntityPersister($mapping['targetEntity']);
|
||||||
|
|
||||||
|
if ( ! $mapping['isOwningSide']) {
|
||||||
|
return $persister->load(array($mapping['mappedBy'] => $coll->getOwner(), $mapping['indexBy'] => $index), null, $mapping, array(), 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $persister->load(array($mapping['inversedBy'] => $coll->getOwner(), $mapping['indexBy'] => $index), null, $mapping, array(), 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -138,6 +150,12 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
|||||||
*/
|
*/
|
||||||
public function containsKey(PersistentCollection $coll, $key)
|
public function containsKey(PersistentCollection $coll, $key)
|
||||||
{
|
{
|
||||||
|
$mapping = $coll->getMapping();
|
||||||
|
|
||||||
|
if ( ! isset($mapping['indexBy'])) {
|
||||||
|
throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections.");
|
||||||
|
}
|
||||||
|
|
||||||
list($quotedJoinTable, $whereClauses, $params) = $this->getJoinTableRestrictionsWithKey($coll, $key, true);
|
list($quotedJoinTable, $whereClauses, $params) = $this->getJoinTableRestrictionsWithKey($coll, $key, true);
|
||||||
|
|
||||||
$sql = 'SELECT 1 FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses);
|
$sql = 'SELECT 1 FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses);
|
||||||
|
@ -60,24 +60,15 @@ class OneToManyPersister extends AbstractCollectionPersister
|
|||||||
*/
|
*/
|
||||||
public function get(PersistentCollection $coll, $index)
|
public function get(PersistentCollection $coll, $index)
|
||||||
{
|
{
|
||||||
$mapping = $coll->getMapping();
|
$mapping = $coll->getMapping();
|
||||||
$persister = $this->uow->getEntityPersister($mapping['targetEntity']);
|
|
||||||
|
|
||||||
if (!isset($mapping['indexBy'])) {
|
if ( ! isset($mapping['indexBy'])) {
|
||||||
throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections.");
|
throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return $persister->load(
|
$persister = $this->uow->getEntityPersister($mapping['targetEntity']);
|
||||||
array(
|
|
||||||
$mapping['mappedBy'] => $coll->getOwner(),
|
return $persister->load(array($mapping['mappedBy'] => $coll->getOwner(), $mapping['indexBy'] => $index), null, $mapping, array(), null, 1);
|
||||||
$mapping['indexBy'] => $index
|
|
||||||
),
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
array(),
|
|
||||||
null,
|
|
||||||
1
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -112,7 +103,12 @@ class OneToManyPersister extends AbstractCollectionPersister
|
|||||||
*/
|
*/
|
||||||
public function containsKey(PersistentCollection $coll, $key)
|
public function containsKey(PersistentCollection $coll, $key)
|
||||||
{
|
{
|
||||||
$mapping = $coll->getMapping();
|
$mapping = $coll->getMapping();
|
||||||
|
|
||||||
|
if ( ! isset($mapping['indexBy'])) {
|
||||||
|
throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections.");
|
||||||
|
}
|
||||||
|
|
||||||
$persister = $this->uow->getEntityPersister($mapping['targetEntity']);
|
$persister = $this->uow->getEntityPersister($mapping['targetEntity']);
|
||||||
|
|
||||||
// only works with single id identifier entities. Will throw an
|
// only works with single id identifier entities. Will throw an
|
||||||
|
@ -20,6 +20,8 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
private $ddc2504OtherClassId;
|
private $ddc2504OtherClassId;
|
||||||
private $ddc2504ChildClassId;
|
private $ddc2504ChildClassId;
|
||||||
|
|
||||||
|
private $username;
|
||||||
|
private $groupname;
|
||||||
private $topic;
|
private $topic;
|
||||||
private $phonenumber;
|
private $phonenumber;
|
||||||
|
|
||||||
@ -59,6 +61,8 @@ 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_LAZY;
|
$class->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_LAZY;
|
||||||
|
|
||||||
|
unset($class->associationMappings['users']['indexBy']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -769,6 +773,40 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
$this->assertSame($article, $this->_em->find('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId));
|
$this->assertSame($article, $this->_em->find('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group DDC-1398
|
||||||
|
*/
|
||||||
|
public function testGetIndexByManyToManyInverseSide()
|
||||||
|
{
|
||||||
|
$group = $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId);
|
||||||
|
/* @var $group CmsGroup */
|
||||||
|
|
||||||
|
$queryCount = $this->getCurrentQueryCount();
|
||||||
|
|
||||||
|
$user = $group->users->get($this->username);
|
||||||
|
|
||||||
|
$this->assertFalse($group->users->isInitialized());
|
||||||
|
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount());
|
||||||
|
$this->assertSame($user, $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group DDC-1398
|
||||||
|
*/
|
||||||
|
public function testGetIndexByManyToManyOwningSide()
|
||||||
|
{
|
||||||
|
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||||
|
/* @var $user CmsUser */
|
||||||
|
|
||||||
|
$queryCount = $this->getCurrentQueryCount();
|
||||||
|
|
||||||
|
$group = $user->groups->get($this->groupname);
|
||||||
|
|
||||||
|
$this->assertFalse($user->groups->isInitialized());
|
||||||
|
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount());
|
||||||
|
$this->assertSame($group, $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @group DDC-1398
|
* @group DDC-1398
|
||||||
*/
|
*/
|
||||||
@ -776,6 +814,7 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
{
|
{
|
||||||
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||||
$this->assertNull($user->articles->get(-1));
|
$this->assertNull($user->articles->get(-1));
|
||||||
|
$this->assertNull($user->groups->get(-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testContainsKeyIndexByOneToMany()
|
public function testContainsKeyIndexByOneToMany()
|
||||||
@ -988,11 +1027,13 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
$this->userId = $user1->getId();
|
$this->userId = $user1->getId();
|
||||||
$this->userId2 = $user2->getId();
|
$this->userId2 = $user2->getId();
|
||||||
$this->groupId = $group1->id;
|
$this->groupId = $group1->id;
|
||||||
|
|
||||||
$this->topic = $article1->topic;
|
|
||||||
$this->phonenumber = $phonenumber1->phonenumber;
|
|
||||||
$this->ddc2504OtherClassId = $otherClass->id;
|
$this->ddc2504OtherClassId = $otherClass->id;
|
||||||
$this->ddc2504ChildClassId = $childClass1->id;
|
$this->ddc2504ChildClassId = $childClass1->id;
|
||||||
|
|
||||||
|
$this->username = $user1->username;
|
||||||
|
$this->groupname = $group1->name;
|
||||||
|
$this->topic = $article1->topic;
|
||||||
|
$this->phonenumber = $phonenumber1->phonenumber;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user