From 140ddf5098a7ffdf6bc3f3dd9d444c85fc09f8aa Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Mon, 27 Sep 2010 22:13:14 +0200 Subject: [PATCH] DDC-817 - Add possibility to query by owning side association join column ids and tests for plain entities, single- and joined table inheritance --- lib/Doctrine/ORM/EntityRepository.php | 5 +- lib/Doctrine/ORM/ORMException.php | 8 ++ .../ORM/Persisters/BasicEntityPersister.php | 13 +++ .../Functional/ClassTableInheritanceTest.php | 32 +++++++ .../ORM/Functional/EntityRepositoryTest.php | 91 ++++++++++++++++++- .../Functional/SingleTableInheritanceTest.php | 24 +++++ 6 files changed, 170 insertions(+), 3 deletions(-) diff --git a/lib/Doctrine/ORM/EntityRepository.php b/lib/Doctrine/ORM/EntityRepository.php index b458a0aeb..81680647c 100644 --- a/lib/Doctrine/ORM/EntityRepository.php +++ b/lib/Doctrine/ORM/EntityRepository.php @@ -185,13 +185,14 @@ class EntityRepository ); } - if ( ! array_key_exists(0, $arguments)) { + if ( !isset($arguments[0])) { + // we dont even want to allow null at this point, because we cannot (yet) transform it into IS NULL. throw ORMException::findByRequiresParameter($method.$by); } $fieldName = lcfirst(\Doctrine\Common\Util\Inflector::classify($by)); - if ($this->_class->hasField($fieldName)) { + if ($this->_class->hasField($fieldName) || $this->_class->hasAssociation($fieldName)) { return $this->$method(array($fieldName => $arguments[0])); } else { throw ORMException::invalidFindByCall($this->_entityName, $fieldName, $method.$by); diff --git a/lib/Doctrine/ORM/ORMException.php b/lib/Doctrine/ORM/ORMException.php index a4a593470..c84dec41e 100644 --- a/lib/Doctrine/ORM/ORMException.php +++ b/lib/Doctrine/ORM/ORMException.php @@ -78,6 +78,14 @@ class ORMException extends Exception ); } + public static function invalidFindByInverseAssociation($entityName, $associationFieldName) + { + return new self( + "You cannot search for the association field '".$entityName."#".$associationFieldName."', ". + "because it is the inverse side of an association. Find methods only work on owning side associations." + ); + } + public static function invalidResultCacheDriver() { return new self("Invalid result cache driver; it must implement \Doctrine\Common\Cache\Cache."); } diff --git a/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php index cc381e27b..51d5c5121 100644 --- a/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php @@ -1120,6 +1120,19 @@ class BasicEntityPersister $conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.'; } $conditionSql .= $this->_class->getQuotedColumnName($field, $this->_platform); + } else if (isset($this->_class->associationMappings[$field])) { + if (!$this->_class->associationMappings[$field]['isOwningSide']) { + throw ORMException::invalidFindByInverseAssociation($this->_class->name, $field); + } + + if (isset($this->_class->associationMappings[$field]['inherited'])) { + $conditionSql .= $this->_getSQLTableAlias($this->_class->associationMappings[$field]['inherited']) . '.'; + } else { + $conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.'; + } + + + $conditionSql .= $this->_class->associationMappings[$field]['joinColumns'][0]['name']; } else if ($assoc !== null) { if ($assoc['type'] == ClassMetadata::MANY_TO_MANY) { $owningAssoc = $assoc['isOwningSide'] ? $assoc : $this->_em->getClassMetadata($assoc['targetEntity']) diff --git a/tests/Doctrine/Tests/ORM/Functional/ClassTableInheritanceTest.php b/tests/Doctrine/Tests/ORM/Functional/ClassTableInheritanceTest.php index 86075e854..24a4e4ad7 100644 --- a/tests/Doctrine/Tests/ORM/Functional/ClassTableInheritanceTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/ClassTableInheritanceTest.php @@ -353,4 +353,36 @@ class ClassTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertEquals($manager->getId(), $dqlManager->getId()); $this->assertEquals($person->getId(), $dqlManager->getSpouse()->getId()); } + + /** + * @group DDC-817 + */ + public function testFindByAssociation() + { + $manager = new CompanyManager(); + $manager->setName('gblanco'); + $manager->setSalary(1234); + $manager->setTitle('Awesome!'); + $manager->setDepartment('IT'); + + $person = new CompanyPerson(); + $person->setName('spouse'); + + $manager->setSpouse($person); + + $this->_em->persist($manager); + $this->_em->persist($person); + $this->_em->flush(); + $this->_em->clear(); + + $repos = $this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyManager'); + $pmanager = $repos->findOneBy(array('spouse' => $person->getId())); + + $this->assertEquals($manager->getId(), $pmanager->getId()); + + $repos = $this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyPerson'); + $pmanager = $repos->findOneBy(array('spouse' => $person->getId())); + + $this->assertEquals($manager->getId(), $pmanager->getId()); + } } diff --git a/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php b/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php index 8916d0a54..d6c29e016 100644 --- a/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php @@ -4,6 +4,7 @@ namespace Doctrine\Tests\ORM\Functional; use Doctrine\Tests\Models\CMS\CmsUser; use Doctrine\Tests\Models\CMS\CmsPhonenumber; +use Doctrine\Tests\Models\CMS\CmsAddress; require_once __DIR__ . '/../../TestInit.php'; @@ -187,8 +188,8 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->loadFixture(); $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + $this->setExpectedException('Doctrine\ORM\ORMException'); $users = $repos->findByStatus(null); - $this->assertEquals(0, count($users)); } /** @@ -201,5 +202,93 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); $repos->foo(); } + + public function loadAssociatedFixture() + { + $address = new CmsAddress(); + $address->city = "Berlin"; + $address->country = "Germany"; + $address->street = "Foostreet"; + $address->zip = "12345"; + + $user = new CmsUser(); + $user->name = 'Roman'; + $user->username = 'romanb'; + $user->status = 'freak'; + $user->setAddress($address); + + $this->_em->persist($user); + $this->_em->persist($address); + $this->_em->flush(); + $this->_em->clear(); + + return array($user->id, $address->id); + } + + /** + * @group DDC-817 + */ + public function testFindByAssociationKey_ExceptionOnInverseSide() + { + list($userId, $addressId) = $this->loadAssociatedFixture(); + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + + $this->setExpectedException('Doctrine\ORM\ORMException', "You cannot search for the association field 'Doctrine\Tests\Models\CMS\CmsUser#address', because it is the inverse side of an association. Find methods only work on owning side associations."); + $user = $repos->findBy(array('address' => $addressId)); + } + + /** + * @group DDC-817 + */ + public function testFindOneByAssociationKey() + { + list($userId, $addressId) = $this->loadAssociatedFixture(); + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress'); + $address = $repos->findOneBy(array('user' => $userId)); + + $this->assertType('Doctrine\Tests\Models\CMS\CmsAddress', $address); + $this->assertEquals($addressId, $address->id); + } + + /** + * @group DDC-817 + */ + public function testFindByAssociationKey() + { + list($userId, $addressId) = $this->loadAssociatedFixture(); + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress'); + $addresses = $repos->findBy(array('user' => $userId)); + + $this->assertContainsOnly('Doctrine\Tests\Models\CMS\CmsAddress', $addresses); + $this->assertEquals(1, count($addresses)); + $this->assertEquals($addressId, $addresses[0]->id); + } + + /** + * @group DDC-817 + */ + public function testFindAssociationByMagicCall() + { + list($userId, $addressId) = $this->loadAssociatedFixture(); + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress'); + $addresses = $repos->findByUser($userId); + + $this->assertContainsOnly('Doctrine\Tests\Models\CMS\CmsAddress', $addresses); + $this->assertEquals(1, count($addresses)); + $this->assertEquals($addressId, $addresses[0]->id); + } + + /** + * @group DDC-817 + */ + public function testFindOneAssociationByMagicCall() + { + list($userId, $addressId) = $this->loadAssociatedFixture(); + $repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress'); + $address = $repos->findOneByUser($userId); + + $this->assertType('Doctrine\Tests\Models\CMS\CmsAddress', $address); + $this->assertEquals($addressId, $address->id); + } } diff --git a/tests/Doctrine/Tests/ORM/Functional/SingleTableInheritanceTest.php b/tests/Doctrine/Tests/ORM/Functional/SingleTableInheritanceTest.php index fb9c93abf..fc303039f 100644 --- a/tests/Doctrine/Tests/ORM/Functional/SingleTableInheritanceTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/SingleTableInheritanceTest.php @@ -308,4 +308,28 @@ class SingleTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertNull($this->_em->find(get_class($this->fix), $this->fix->getId()), "Contract should not be present in the database anymore."); } + + /** + * @group DDC-817 + */ + public function testFindByAssociation() + { + $this->loadFullFixture(); + + $repos = $this->_em->getRepository("Doctrine\Tests\Models\Company\CompanyContract"); + $contracts = $repos->findBy(array('salesPerson' => $this->salesPerson->getId())); + $this->assertEquals(3, count($contracts), "There should be 3 entities related to " . $this->salesPerson->getId() . " for 'Doctrine\Tests\Models\Company\CompanyContract'"); + + $repos = $this->_em->getRepository("Doctrine\Tests\Models\Company\CompanyFixContract"); + $contracts = $repos->findBy(array('salesPerson' => $this->salesPerson->getId())); + $this->assertEquals(1, count($contracts), "There should be 1 entities related to " . $this->salesPerson->getId() . " for 'Doctrine\Tests\Models\Company\CompanyFixContract'"); + + $repos = $this->_em->getRepository("Doctrine\Tests\Models\Company\CompanyFlexContract"); + $contracts = $repos->findBy(array('salesPerson' => $this->salesPerson->getId())); + $this->assertEquals(2, count($contracts), "There should be 2 entities related to " . $this->salesPerson->getId() . " for 'Doctrine\Tests\Models\Company\CompanyFlexContract'"); + + $repos = $this->_em->getRepository("Doctrine\Tests\Models\Company\CompanyFlexUltraContract"); + $contracts = $repos->findBy(array('salesPerson' => $this->salesPerson->getId())); + $this->assertEquals(1, count($contracts), "There should be 1 entities related to " . $this->salesPerson->getId() . " for 'Doctrine\Tests\Models\Company\CompanyFlexUltraContract'"); + } }