Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

ObjectHydrator: fix entity namespaces. #614

Closed
wants to merge 4 commits into from

5 participants

Jelmer Snoeck doctrinebot Benjamin Eberlei Christophe Coevoet Michael Moravec
Jelmer Snoeck

Object Hydrator: fix entity namespaces

If you are using Entity Namespace aliases, the ObjectHydrator will throw a notice for an undefined index of your entity namespace.

Problem

The problem lies in the fact that the prepare() method uses the "className", used in the aliasMap (where you use the namespace alias) to store the local ClassMetadata cache. Though, in a later stage the actual namespace is being used to find this same item.

Fix

I've changed the way this ClassMetadata cache is built. It now uses the full Entity namespace.

doctrinebot
Collaborator

Hello,

thank you for positing this Pull Request. I have automatically opened an issue on our Jira Bug Tracker for you with the details of this Pull-Request. See the Link:

http://doctrine-project.org/jira/browse/DDC-2350

Jelmer Snoeck jelmersnoeck referenced this pull request in doctrine/DoctrineBundle
Closed

ResultSetMapping #167

Christophe Coevoet stof commented on the diff
lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php
@@ -101,9 +101,10 @@ protected function prepare()
101 101 foreach ($this->_rsm->aliasMap as $dqlAlias => $className) {
102 102 $this->identifierMap[$dqlAlias] = array();
103 103 $this->idTemplate[$dqlAlias] = '';
  104 + $classMetadata = $this->_em->getClassMetadata($className);
1
Christophe Coevoet
stof added a note

This defeats the cache as you are always fetching it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php
((5 lines not shown))
104 105
105   - if ( ! isset($this->ce[$className])) {
106   - $this->ce[$className] = $this->_em->getClassMetadata($className);
  106 + if ( ! isset($this->ce[$classMetadata->name])) {
  107 + $this->ce[$classMetadata->name] = $this->_em->getClassMetadata($className);
1
Michael Moravec
Majkl578 added a note

You defined $classMetadata above, but now you refuse to use it and ask EM for them again?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Benjamin Eberlei
Owner

This should be fixed as part of the SqlWalker process instead of in every hydration. This way this can be cached, the hydrator doesnt have to change. AFAIK this was done by another PR very recently.

Benjamin Eberlei beberlei closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
11 lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php
@@ -101,9 +101,10 @@ protected function prepare()
101 101 foreach ($this->_rsm->aliasMap as $dqlAlias => $className) {
102 102 $this->identifierMap[$dqlAlias] = array();
103 103 $this->idTemplate[$dqlAlias] = '';
  104 + $classMetadata = $this->_em->getClassMetadata($className);
104 105
105   - if ( ! isset($this->ce[$className])) {
106   - $this->ce[$className] = $this->_em->getClassMetadata($className);
  106 + if ( ! isset($this->ce[$classMetadata->name])) {
  107 + $this->ce[$classMetadata->name] = $classMetadata;
107 108 }
108 109
109 110 // Remember which associations are "fetch joined", so that we know where to inject
@@ -135,7 +136,7 @@ protected function prepare()
135 136
136 137 // handle fetch-joined owning side bi-directional one-to-one associations
137 138 if ($assoc['inversedBy']) {
138   - $class = $this->ce[$className];
  139 + $class = $this->ce[$classMetadata->name];
139 140 $inverseAssoc = $class->associationMappings[$assoc['inversedBy']];
140 141
141 142 if ( ! ($inverseAssoc['type'] & ClassMetadata::TO_ONE)) {
@@ -247,7 +248,9 @@ private function initRelatedCollection($entity, $class, $fieldName, $parentDqlAl
247 248 */
248 249 private function getEntity(array $data, $dqlAlias)
249 250 {
250   - $className = $this->_rsm->aliasMap[$dqlAlias];
  251 + $classAliasMap = $this->_rsm->aliasMap[$dqlAlias];
  252 + $classMetadata = $this->_em->getClassMetadata($classAliasMap);
  253 + $className = $classMetadata->name;
251 254
252 255 if (isset($this->_rsm->discriminatorColumns[$dqlAlias])) {
253 256
2  tests/Doctrine/Tests/Mocks/HydratorMockStatement.php
@@ -78,7 +78,7 @@ public function bindValue($param, $value, $type = null)
78 78 /**
79 79 * {@inheritdoc}
80 80 */
81   - public function bindParam($column, &$variable, $type = null)
  81 + public function bindParam($column, &$variable, $type = null, $length = null)
82 82 {
83 83 }
84 84
122 tests/Doctrine/Tests/ORM/Hydration/ObjectHydratorTest.php
@@ -1928,4 +1928,126 @@ public function testMissingDiscriminatorColumnException()
1928 1928 $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
1929 1929 $hydrator->hydrateAll($stmt, $rsm);
1930 1930 }
  1931 +
  1932 + /**
  1933 + * SELECT PARTIAL u.{id, status}, PARTIAL p.{phonenumber}, UPPER(u.name) nameUpper
  1934 + * FROM Doctrine\Tests\Models\CMS\CmsUser u
  1935 + * JOIN u.phonenumbers p
  1936 + *
  1937 + * @group EntityNamespaces
  1938 + * @dataProvider provideDataForUserEntityResult
  1939 + */
  1940 + public function testMixedQueryNormalJoinWithEntityNamespaces($userEntityKey)
  1941 + {
  1942 + $this->_em->getConfiguration()->addEntityNamespace('DoctrineCmsModels', 'Doctrine\Tests\Models\CMS');
  1943 +
  1944 + $rsm = new ResultSetMapping;
  1945 + $rsm->addEntityResult('DoctrineCmsModels:CmsUser', 'u', $userEntityKey ?: null);
  1946 + $rsm->addJoinedEntityResult(
  1947 + 'DoctrineCmsModels:CmsPhonenumber',
  1948 + 'p',
  1949 + 'u',
  1950 + 'phonenumbers'
  1951 + );
  1952 + $rsm->addFieldResult('u', 'u__id', 'id');
  1953 + $rsm->addFieldResult('u', 'u__status', 'status');
  1954 + $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
  1955 + $rsm->addScalarResult('sclr0', 'nameUpper');
  1956 +
  1957 + // Faked result set
  1958 + $resultSet = array(
  1959 + //row1
  1960 + array(
  1961 + 'u__id' => '1',
  1962 + 'u__status' => 'developer',
  1963 + 'p__phonenumber' => '42',
  1964 + 'sclr0' => 'ROMANB',
  1965 + ),
  1966 + array(
  1967 + 'u__id' => '1',
  1968 + 'u__status' => 'developer',
  1969 + 'p__phonenumber' => '43',
  1970 + 'sclr0' => 'ROMANB',
  1971 + ),
  1972 + array(
  1973 + 'u__id' => '2',
  1974 + 'u__status' => 'developer',
  1975 + 'p__phonenumber' => '91',
  1976 + 'sclr0' => 'JWAGE',
  1977 + )
  1978 + );
  1979 +
  1980 + $stmt = new HydratorMockStatement($resultSet);
  1981 + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
  1982 + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
  1983 +
  1984 + $this->assertEquals(2, count($result));
  1985 +
  1986 + $this->assertInternalType('array', $result);
  1987 + $this->assertInternalType('array', $result[0]);
  1988 + $this->assertInternalType('array', $result[1]);
  1989 +
  1990 + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0][$userEntityKey]);
  1991 + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $result[0][$userEntityKey]->phonenumbers);
  1992 + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsPhonenumber', $result[0][$userEntityKey]->phonenumbers[0]);
  1993 +
  1994 + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[1][$userEntityKey]);
  1995 + $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $result[1][$userEntityKey]->phonenumbers);
  1996 + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsPhonenumber', $result[0][$userEntityKey]->phonenumbers[1]);
  1997 +
  1998 + // first user => 2 phonenumbers
  1999 + $this->assertEquals(2, count($result[0][$userEntityKey]->phonenumbers));
  2000 + $this->assertEquals('ROMANB', $result[0]['nameUpper']);
  2001 +
  2002 + // second user => 1 phonenumber
  2003 + $this->assertEquals(1, count($result[1][$userEntityKey]->phonenumbers));
  2004 + $this->assertEquals('JWAGE', $result[1]['nameUpper']);
  2005 +
  2006 + $this->assertEquals(42, $result[0][$userEntityKey]->phonenumbers[0]->phonenumber);
  2007 + $this->assertEquals(43, $result[0][$userEntityKey]->phonenumbers[1]->phonenumber);
  2008 + $this->assertEquals(91, $result[1][$userEntityKey]->phonenumbers[0]->phonenumber);
  2009 + }
  2010 +
  2011 + /**
  2012 + * SELECT PARTIAL u.{id,name}
  2013 + * FROM Doctrine\Tests\Models\CMS\CmsUser u
  2014 + *
  2015 + * @group EntityNamespaces
  2016 + */
  2017 + public function testSimpleEntityQueryWithEntityNamespaces()
  2018 + {
  2019 + $this->_em->getConfiguration()->addEntityNamespace('DoctrineCmsModels', 'Doctrine\Tests\Models\CMS');
  2020 +
  2021 + $rsm = new ResultSetMapping;
  2022 + $rsm->addEntityResult('DoctrineCmsModels:CmsUser', 'u');
  2023 + $rsm->addFieldResult('u', 'u__id', 'id');
  2024 + $rsm->addFieldResult('u', 'u__name', 'name');
  2025 +
  2026 + // Faked result set
  2027 + $resultSet = array(
  2028 + array(
  2029 + 'u__id' => '1',
  2030 + 'u__name' => 'romanb'
  2031 + ),
  2032 + array(
  2033 + 'u__id' => '2',
  2034 + 'u__name' => 'jwage'
  2035 + )
  2036 + );
  2037 +
  2038 + $stmt = new HydratorMockStatement($resultSet);
  2039 + $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
  2040 + $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
  2041 +
  2042 + $this->assertEquals(2, count($result));
  2043 +
  2044 + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0]);
  2045 + $this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[1]);
  2046 +
  2047 + $this->assertEquals(1, $result[0]->id);
  2048 + $this->assertEquals('romanb', $result[0]->name);
  2049 +
  2050 + $this->assertEquals(2, $result[1]->id);
  2051 + $this->assertEquals('jwage', $result[1]->name);
  2052 + }
1931 2053 }

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.