diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php index 798b011e7..52f847f4f 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -1991,7 +1991,7 @@ class ClassMetadataInfo implements ClassMetadata $queryMapping['resultClass'] = $this->namespace . '\\' . $queryMapping['resultClass']; } - $mapping['targetEntity'] = ltrim($queryMapping['resultClass'], '\\'); + $queryMapping['resultClass'] = ltrim($queryMapping['resultClass'], '\\'); } $this->namedNativeQueries[$queryMapping['name']] = $queryMapping; @@ -2027,6 +2027,23 @@ class ClassMetadataInfo implements ClassMetadata } $resultMapping['entities'][$key]['entityClass'] = ltrim($entityResult['entityClass'], '\\'); + + if (isset($entityResult['fields'])) { + foreach ($entityResult['fields'] as $k => $field) { + if (!isset($field['name'])) { + throw MappingException::missingResultSetMappingFieldName($this->name, $resultMapping['name']); + } + + if (!isset($field['column'])) { + $fieldName = $field['name']; + if(strpos($fieldName, '.')){ + list(, $fieldName) = explode('.', $fieldName); + } + + $resultMapping['entities'][$key]['fields'][$k]['column'] = $fieldName; + } + } + } } } diff --git a/lib/Doctrine/ORM/Mapping/MappingException.php b/lib/Doctrine/ORM/Mapping/MappingException.php index c76138582..5c3ed8ef2 100644 --- a/lib/Doctrine/ORM/Mapping/MappingException.php +++ b/lib/Doctrine/ORM/Mapping/MappingException.php @@ -117,6 +117,11 @@ class MappingException extends \Doctrine\ORM\ORMException { return new self('Result set mapping named "'.$resultName.'" in "'.$entity.' requires a entity class name.'); } + + public static function missingResultSetMappingFieldName($entity, $resultName) + { + return new self('Result set mapping named "'.$resultName.'" in "'.$entity.' requires a field name.'); + } public static function nameIsMandatoryForSqlResultSetMapping($className) { diff --git a/lib/Doctrine/ORM/Query/ResultSetMappingBuilder.php b/lib/Doctrine/ORM/Query/ResultSetMappingBuilder.php index fcb12ecc2..bfc1826c0 100644 --- a/lib/Doctrine/ORM/Query/ResultSetMappingBuilder.php +++ b/lib/Doctrine/ORM/Query/ResultSetMappingBuilder.php @@ -149,11 +149,31 @@ class ResultSetMappingBuilder extends ResultSetMapping $alias = strtolower($shortName[0]) . $key; $this->addEntityResult($classMetadata->name, $alias); - if (isset($entityMapping['fields']) && !empty($entityMapping['fields'])) { foreach ($entityMapping['fields'] as $field) { - $this->addFieldResult($alias, $field['column'], $field['name'], $classMetadata->name); + $fieldName = $field['name']; + $relation = null; + + if(strpos($fieldName, '.')){ + list($relation, $fieldName) = explode('.', $fieldName); + } + + if (isset($classMetadata->associationMappings[$relation])) { + if($relation) { + $associationMapping = $classMetadata->associationMappings[$relation]; + $joinAlias = $alias.$relation; + $parentAlias = $alias; + + $this->addJoinedEntityResult($associationMapping['targetEntity'], $joinAlias, $parentAlias, $relation); + $this->addFieldResult($joinAlias, $field['column'], $fieldName); + }else { + $this->addFieldResult($alias, $field['column'], $fieldName, $classMetadata->name); + } + } else { + $this->addFieldResult($alias, $field['column'], $fieldName, $classMetadata->name); + } } + } else { foreach ($classMetadata->getColumnNames() as $columnName) { $propertyName = $classMetadata->getFieldName($columnName); diff --git a/tests/Doctrine/Tests/Models/CMS/CmsUser.php b/tests/Doctrine/Tests/Models/CMS/CmsUser.php index a388081e6..5f8441247 100644 --- a/tests/Doctrine/Tests/Models/CMS/CmsUser.php +++ b/tests/Doctrine/Tests/Models/CMS/CmsUser.php @@ -22,6 +22,50 @@ use Doctrine\Common\Collections\ArrayCollection; * resultClass = "CmsUser", * query = "SELECT * FROM cms_users WHERE username = ?" * ), + * @NamedNativeQuery( + * name = "fetchJoinedAddressWithResultSetMapping", + * resultSetMapping= "mappingJoinedAddress", + * query = "SELECT u.id, u.name, u.status, a.id AS a_id, a.country, a.zip, a.city FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id WHERE u.username = ?" + * ), + * @NamedNativeQuery( + * name = "fetchJoinedPhonenumberWithResultSetMapping", + * resultSetMapping= "mappingJoinedPhonenumber", + * query = "SELECT id, name, status, phonenumber AS number FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username = ?" + * ), + * }) + * + * @SqlResultSetMappings({ + * @SqlResultSetMapping( + * name = "mappingJoinedAddress", + * entities= { + * @EntityResult( + * entityClass = "__CLASS__", + * fields = { + * @FieldResult(name = "id"), + * @FieldResult(name = "name"), + * @FieldResult(name = "status"), + * @FieldResult(name = "address.zip"), + * @FieldResult(name = "address.city"), + * @FieldResult(name = "address.country"), + * @FieldResult(name = "address.id", column = "a_id"), + * } + * ) + * } + * ), + * @SqlResultSetMapping( + * name = "mappingJoinedPhonenumber", + * entities= { + * @EntityResult( + * entityClass = "CmsUser", + * fields = { + * @FieldResult(name = "id"), + * @FieldResult(name = "name"), + * @FieldResult(name = "status"), + * @FieldResult(name = "phonenumbers.phonenumber" , column = "number"), + * } + * ) + * } + * ) * }) */ class CmsUser diff --git a/tests/Doctrine/Tests/ORM/Functional/NativeQueryTest.php b/tests/Doctrine/Tests/ORM/Functional/NativeQueryTest.php index 80c580366..79d8e8a50 100644 --- a/tests/Doctrine/Tests/ORM/Functional/NativeQueryTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/NativeQueryTest.php @@ -370,7 +370,7 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase /** * @group DDC-1663 */ - public function testBasicNativeQueryWithResultClass() + public function testBasicNativeNamedQueryWithResultClass() { //$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger); @@ -393,8 +393,9 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); - $result = $repository->createNativeNamedQuery('fetchIdAndUsernameWithResultClass') + $result = $repository->createNativeNamedQuery('fetchIdAndUsernameWithResultClass') ->setParameter(1, 'FabioBatSilva')->getResult(); + $this->assertEquals(1, count($result)); $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0]); $this->assertNull($result[0]->name); @@ -405,7 +406,7 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->_em->clear(); - $result = $repository->createNativeNamedQuery('fetchAllColumnsWithResultClass') + $result = $repository->createNativeNamedQuery('fetchAllColumnsWithResultClass') ->setParameter(1, 'FabioBatSilva')->getResult(); $this->assertEquals(1, count($result)); @@ -415,10 +416,82 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertEquals('FabioBatSilva', $result[0]->username); $this->assertEquals('dev', $result[0]->status); $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsEmail', $result[0]->email); + } + public function testJoinedOneToOneNativeNamedQueryWithResultSetMapping() + { + $user = new CmsUser; + $user->name = 'Fabio B. Silva'; + $user->username = 'FabioBatSilva'; + $user->status = 'dev'; + + $addr = new CmsAddress; + $addr->country = 'Brazil'; + $addr->zip = 10827; + $addr->city = 'São Paulo'; + + + $user->setAddress($addr); + + $this->_em->persist($user); + $this->_em->flush(); + $this->_em->clear(); + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + + + $result = $repository->createNativeNamedQuery('fetchJoinedAddressWithResultSetMapping') + ->setParameter(1, 'FabioBatSilva')->getResult(); + + $this->assertEquals(1, count($result)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0]); + $this->assertEquals('Fabio B. Silva', $result[0]->name); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $result[0]->getPhonenumbers()); + $this->assertFalse($result[0]->getPhonenumbers()->isInitialized()); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress', $result[0]->getAddress()); + $this->assertTrue($result[0]->getAddress()->getUser() == $result[0]); + $this->assertEquals('Brazil', $result[0]->getAddress()->getCountry()); + $this->assertEquals(10827, $result[0]->getAddress()->getZipCode()); + $this->assertEquals('São Paulo', $result[0]->getAddress()->getCity()); } + + + public function testJoinedOneToManyNativeNamedQueryWithResultSetMapping() + { + $user = new CmsUser; + $user->name = 'Fabio B. Silva'; + $user->username = 'FabioBatSilva'; + $user->status = 'dev'; + + $phone = new CmsPhonenumber; + $phone->phonenumber = 424242; + + $user->addPhonenumber($phone); + + $this->_em->persist($user); + $this->_em->flush(); + + $this->_em->clear(); + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + + $result = $repository->createNativeNamedQuery('fetchJoinedPhonenumberWithResultSetMapping') + ->setParameter(1, 'FabioBatSilva')->getResult(); + + $this->assertEquals(1, count($result)); + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0]); + $this->assertEquals('Fabio B. Silva', $result[0]->name); + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $result[0]->getPhonenumbers()); + $this->assertTrue($result[0]->getPhonenumbers()->isInitialized()); + $this->assertEquals(1, count($result[0]->getPhonenumbers())); + $phones = $result[0]->getPhonenumbers(); + $this->assertEquals(424242, $phones[0]->phonenumber); + $this->assertTrue($phones[0]->getUser() === $result[0]); + } + + + }