From 20dc72ef9ae0d7c4afead35c249c224b95570aa7 Mon Sep 17 00:00:00 2001
From: Michael Ridgway <mcridgway@gmail.com>
Date: Tue, 29 Mar 2011 20:35:01 -0400
Subject: [PATCH] First pass on RSM helper functions for adding entities

---
 lib/Doctrine/ORM/Query/ResultSetMapping.php   | 38 ++++++++-
 .../Tests/ORM/Functional/NativeQueryTest.php  | 81 +++++++++++++++++++
 2 files changed, 117 insertions(+), 2 deletions(-)

diff --git a/lib/Doctrine/ORM/Query/ResultSetMapping.php b/lib/Doctrine/ORM/Query/ResultSetMapping.php
index 7066405df..ededf1153 100644
--- a/lib/Doctrine/ORM/Query/ResultSetMapping.php
+++ b/lib/Doctrine/ORM/Query/ResultSetMapping.php
@@ -1,7 +1,5 @@
 <?php
 /*
- *  $Id$
- *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -21,6 +19,8 @@
 
 namespace Doctrine\ORM\Query;
 
+use Doctrine\ORM\Mapping\ClassMetadata;
+
 /**
  * A ResultSetMapping describes how a result set of an SQL query maps to a Doctrine result.
  *
@@ -392,5 +392,39 @@ class ResultSetMapping
         $this->metaMappings[$columnName] = $fieldName;
         $this->columnOwnerMap[$columnName] = $alias;
     }
+
+    /**
+     * Adds a root entity and all of its fields to the result set.
+     *
+     * @param ClassMetadata $classMetadata
+     * @param string $alias The unique alias to use for the root entity.
+     * @param string $prefix Prefix for columns
+     */
+    public function addRootEntityFromClassMetadata(ClassMetadata $classMetadata, $alias, $prefix = '')
+    {
+        $this->addEntityResult($classMetadata->getReflectionClass()->getName(), $alias);
+        foreach ($classMetadata->getColumnNames() AS $columnName) {
+            // $columnName should use DBAL\Platforms\AbstractPlatform::getSQLResultCasing() but we don't have the EM
+            $this->addFieldResult($alias, $prefix . $columnName, $classMetadata->getFieldName($columnName));
+        }
+    }
+
+    /**
+     * Adds a joined entity and all of its fields to the result set.
+     *
+     * @param ClassMetadata $classMetadata
+     * @param string $alias The unique alias to use for the joined entity.
+     * @param string $parentAlias The alias of the entity result that is the parent of this joined result.
+     * @param object $relation The association field that connects the parent entity result with the joined entity result.
+     * @param string $prefix Prefix for columns
+     */
+    public function addJoinedEntityFromClassMetadata(ClassMetadata $classMetadata, $alias, $parentAlias, $relation, $prefix = '')
+    {
+        $this->addJoinedEntityResult($classMetadata->getReflectionClass()->getName(), $alias, $parentAlias, $relation);
+        foreach ($classMetadata->getColumnNames() AS $columnName) {
+            // $columnName should use DBAL\Platforms\AbstractPlatform::getSQLResultCasing() but we don't have the EM
+            $this->addFieldResult($alias, $prefix . $columnName, $classMetadata->getFieldName($columnName));
+        }
+    }
 }
 
diff --git a/tests/Doctrine/Tests/ORM/Functional/NativeQueryTest.php b/tests/Doctrine/Tests/ORM/Functional/NativeQueryTest.php
index 23dfa3a73..65778badf 100644
--- a/tests/Doctrine/Tests/ORM/Functional/NativeQueryTest.php
+++ b/tests/Doctrine/Tests/ORM/Functional/NativeQueryTest.php
@@ -156,5 +156,86 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
 
         $this->assertSame($q, $q2);
     }
+
+    public function testJoinedOneToManyNativeQueryWithRSMHelper()
+    {
+        $user = new CmsUser;
+        $user->name = 'Roman';
+        $user->username = 'romanb';
+        $user->status = 'dev';
+
+        $phone = new CmsPhonenumber;
+        $phone->phonenumber = 424242;
+
+        $user->addPhonenumber($phone);
+
+        $this->_em->persist($user);
+        $this->_em->flush();
+
+        $this->_em->clear();
+
+        $rsm = new ResultSetMapping;
+        $userMetadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
+        $phoneMetadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber');
+        $rsm->addRootEntityFromClassMetadata($userMetadata, 'u');
+        $rsm->addJoinedEntityFromClassMetadata($phoneMetadata, 'p', 'u', 'phonenumbers', 'p_');
+        $query = $this->_em->createNativeQuery('SELECT u.*, p.phonenumber AS p_phonenumber FROM cms_users u INNER JOIN cms_phonenumbers p ON u.id = p.user_id WHERE username = ?', $rsm);
+        $query->setParameter(1, 'romanb');
+
+        $users = $query->getResult();
+        $this->assertEquals(1, count($users));
+        $this->assertTrue($users[0] instanceof CmsUser);
+        $this->assertEquals('Roman', $users[0]->name);
+        $this->assertTrue($users[0]->getPhonenumbers() instanceof \Doctrine\ORM\PersistentCollection);
+        $this->assertTrue($users[0]->getPhonenumbers()->isInitialized());
+        $this->assertEquals(1, count($users[0]->getPhonenumbers()));
+        $phones = $users[0]->getPhonenumbers();
+        $this->assertEquals(424242, $phones[0]->phonenumber);
+        $this->assertTrue($phones[0]->getUser() === $users[0]);
+    }
+
+    public function testJoinedOneToOneNativeQueryWithRSMHelper()
+    {
+        $user = new CmsUser;
+        $user->name = 'Roman';
+        $user->username = 'romanb';
+        $user->status = 'dev';
+
+        $addr = new CmsAddress;
+        $addr->country = 'germany';
+        $addr->zip = 10827;
+        $addr->city = 'Berlin';
+
+
+        $user->setAddress($addr);
+
+        $this->_em->persist($user);
+        $this->_em->flush();
+
+        $this->_em->clear();
+
+
+        $rsm = new ResultSetMapping;
+        $userMetadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
+        $addressMetadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress');
+        $rsm->addRootEntityFromClassMetadata($userMetadata, 'u');
+        $rsm->addJoinedEntityFromClassMetadata($addressMetadata, 'a', 'u', 'address', 'a_');
+
+        $query = $this->_em->createNativeQuery('SELECT u.id, u.name, u.status, a.id AS a_id, a.country AS a_country, a.zip AS a_zip, a.city AS a_city FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id WHERE u.username = ?', $rsm);
+        $query->setParameter(1, 'romanb');
+
+        $users = $query->getResult();
+
+        $this->assertEquals(1, count($users));
+        $this->assertTrue($users[0] instanceof CmsUser);
+        $this->assertEquals('Roman', $users[0]->name);
+        $this->assertTrue($users[0]->getPhonenumbers() instanceof \Doctrine\ORM\PersistentCollection);
+        $this->assertFalse($users[0]->getPhonenumbers()->isInitialized());
+        $this->assertTrue($users[0]->getAddress() instanceof CmsAddress);
+        $this->assertTrue($users[0]->getAddress()->getUser() == $users[0]);
+        $this->assertEquals('germany', $users[0]->getAddress()->getCountry());
+        $this->assertEquals(10827, $users[0]->getAddress()->getZipCode());
+        $this->assertEquals('Berlin', $users[0]->getAddress()->getCity());
+    }
 }