diff --git a/lib/Doctrine/ORM/PersistentCollection.php b/lib/Doctrine/ORM/PersistentCollection.php index 53ba1c1f2..a50cd8343 100644 --- a/lib/Doctrine/ORM/PersistentCollection.php +++ b/lib/Doctrine/ORM/PersistentCollection.php @@ -517,6 +517,17 @@ final class PersistentCollection implements Collection, Selectable */ public function get($key) { + if ( ! $this->initialized + && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY + && isset($this->association['indexBy']) + ) { + if (!$this->typeClass->isIdentifierComposite && $this->typeClass->isIdentifier($this->association['indexBy'])) { + return $this->em->find($this->typeClass->name, $key); + } + + return $this->em->getUnitOfWork()->getCollectionPersister($this->association)->get($this, $key); + } + $this->initialize(); return $this->coll->get($key); diff --git a/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php b/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php index d9f7e30ca..df46aa30a 100644 --- a/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php +++ b/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php @@ -33,6 +33,24 @@ use Doctrine\ORM\UnitOfWork; */ class ManyToManyPersister extends AbstractCollectionPersister { + /** + * {@inheritdoc} + * + * @override + */ + public function get(PersistentCollection $coll, $index) + { + $mapping = $coll->getMapping(); + $uow = $this->em->getUnitOfWork(); + $persister = $uow->getEntityPersister($mapping['targetEntity']); + + if (!isset($mapping['indexBy'])) { + throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections."); + } + + return $persister->load(array($mapping['indexBy'] => $index), null, null, array(), 0, 1); + } + /** * {@inheritdoc} * diff --git a/lib/Doctrine/ORM/Persisters/OneToManyPersister.php b/lib/Doctrine/ORM/Persisters/OneToManyPersister.php index 911d699f6..120ad548d 100644 --- a/lib/Doctrine/ORM/Persisters/OneToManyPersister.php +++ b/lib/Doctrine/ORM/Persisters/OneToManyPersister.php @@ -32,6 +32,24 @@ use Doctrine\ORM\UnitOfWork; */ class OneToManyPersister extends AbstractCollectionPersister { + /** + * {@inheritdoc} + * + * @override + */ + public function get(PersistentCollection $coll, $index) + { + $mapping = $coll->getMapping(); + $uow = $this->em->getUnitOfWork(); + $persister = $uow->getEntityPersister($mapping['targetEntity']); + + if (!isset($mapping['indexBy'])) { + throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections."); + } + + return $persister->load(array($mapping['indexBy'] => $index), null, null, array(), 0, 1); + } + /** * Generates the SQL UPDATE that updates a particular row's foreign * key to null. diff --git a/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php b/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php index b6c7a0f1e..5d8fa0f2a 100644 --- a/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php @@ -17,6 +17,10 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase private $groupId; private $articleId; + private $groupname; + private $topic; + private $phonenumber; + public function setUp() { $this->useModelSet('cms'); @@ -24,7 +28,11 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); $class->associationMappings['groups']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY; + $class->associationMappings['groups']['indexBy'] = 'name'; $class->associationMappings['articles']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY; + $class->associationMappings['articles']['indexBy'] = 'topic'; + $class->associationMappings['phonenumbers']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY; + $class->associationMappings['phonenumbers']['indexBy'] = 'phonenumber'; $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup'); $class->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY; @@ -39,6 +47,11 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); $class->associationMappings['groups']['fetch'] = ClassMetadataInfo::FETCH_LAZY; $class->associationMappings['articles']['fetch'] = ClassMetadataInfo::FETCH_LAZY; + $class->associationMappings['phonenumbers']['fetch'] = ClassMetadataInfo::FETCH_LAZY; + + unset($class->associationMappings['groups']['indexBy']); + unset($class->associationMappings['articles']['indexBy']); + unset($class->associationMappings['phonenumbers']['indexBy']); $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup'); $class->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_LAZY; @@ -174,8 +187,8 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase $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])); + $this->assertTrue($user->groups->contains(array_shift($someGroups))); + $this->assertTrue($user->groups->contains(array_shift($someGroups))); } /** @@ -512,6 +525,72 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertEquals($qc + 1, $this->getCurrentQueryCount()); } + /** + * @group DDC-1398 + */ + public function testGetIndexByIdentifier() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + /* @var $user CmsUser */ + + $queryCount = $this->getCurrentQueryCount(); + + $phonenumber = $user->phonenumbers->get($this->phonenumber); + + $this->assertFalse($user->phonenumbers->isInitialized()); + $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount()); + $this->assertSame($phonenumber, $this->_em->find('Doctrine\Tests\Models\CMS\CmsPhonenumber', $this->phonenumber)); + + $article = $user->phonenumbers->get($this->phonenumber); + $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Getting the same entity should not cause an extra query to be executed"); + } + + /** + * @group DDC-1398 + */ + public function testGetIndexByOneToMany() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + /* @var $user CmsUser */ + + $queryCount = $this->getCurrentQueryCount(); + + $article = $user->articles->get($this->topic); + + $this->assertFalse($user->articles->isInitialized()); + $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount()); + $this->assertSame($article, $this->_em->find('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId)); + } + + /** + * @group DDC-1398 + */ + public function testGetIndexByManyToMany() + { + $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 + */ + public function testGetNonExistentIndexBy() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + /* @var $user CmsUser */ + + $this->assertNull($user->articles->get(-1)); + $this->assertNull($user->groups->get(-1)); + } + private function loadFixture() { $user1 = new \Doctrine\Tests\Models\CMS\CmsUser(); @@ -561,23 +640,36 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->_em->persist($group3); $article1 = new \Doctrine\Tests\Models\CMS\CmsArticle(); - $article1->topic = "Test"; - $article1->text = "Test"; + $article1->topic = "Test1"; + $article1->text = "Test1"; $article1->setAuthor($user1); $article2 = new \Doctrine\Tests\Models\CMS\CmsArticle(); - $article2->topic = "Test"; - $article2->text = "Test"; + $article2->topic = "Test2"; + $article2->text = "Test2"; $article2->setAuthor($user1); $this->_em->persist($article1); $this->_em->persist($article2); + $phonenumber1 = new \Doctrine\Tests\Models\CMS\CmsPhonenumber(); + $phonenumber1->phonenumber = '12345'; + + $phonenumber2 = new \Doctrine\Tests\Models\CMS\CmsPhonenumber(); + $phonenumber2->phonenumber = '67890'; + + $this->_em->persist($phonenumber1); + $this->_em->persist($phonenumber2); + $this->_em->flush(); $this->_em->clear(); $this->articleId = $article1->id; $this->userId = $user1->getId(); $this->groupId = $group1->id; + + $this->groupname = $group1->name; + $this->topic = $article1->topic; + $this->phonenumber = $phonenumber1->phonenumber; } } \ No newline at end of file