Skip to content

Commit e531738

Browse files
Mediagonegreg0ire
authored andcommitted
Fix Hidden fields triggering error when using getSingleScalarResult() (#8340)
* Fix Hidden fields triggering error when using getSingleScalarResult() Fixes #4257 HIDDEN fields was causing the "unicity" check to fail (NonUniqueResultException), because we was counting raw data instead of gathered row data. * Fix Coding Standards (7.4) * Fix Coding Standards (7.4) #2 * Fix Coding Standards (7.4) - Fix whitespaces * Fix Coding Standards (7.4) - Fix whitespaces in tests * Fix Coding Standards (7.4) - Fix more things * Refactor tests into separate methods * Fix Coding Standards (7.4) - Equals sign not aligned with surrounding assignments
1 parent 02356d0 commit e531738

File tree

2 files changed

+138
-45
lines changed

2 files changed

+138
-45
lines changed

lib/Doctrine/ORM/Internal/Hydration/SingleScalarHydrator.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ protected function hydrateAllData()
3232
throw new NonUniqueResultException('The query returned multiple rows. Change the query or use a different result function like getScalarResult().');
3333
}
3434

35-
if (count($data[key($data)]) > 1) {
35+
$result = $this->gatherScalarRowData($data[key($data)]);
36+
37+
if (count($result) > 1) {
3638
throw new NonUniqueResultException('The query returned a row containing multiple columns. Change the query or use a different result function like getScalarResult().');
3739
}
3840

39-
$result = $this->gatherScalarRowData($data[key($data)]);
40-
4141
return array_shift($result);
4242
}
4343
}

tests/Doctrine/Tests/ORM/Hydration/SingleScalarHydratorTest.php

+135-42
Original file line numberDiff line numberDiff line change
@@ -9,56 +9,147 @@
99
use Doctrine\ORM\Query\ResultSetMapping;
1010
use Doctrine\Tests\Mocks\ArrayResultFactory;
1111
use Doctrine\Tests\Models\CMS\CmsUser;
12+
use Generator;
1213

1314
use function in_array;
1415

1516
class SingleScalarHydratorTest extends HydrationTestCase
1617
{
17-
/** Result set provider for the HYDRATE_SINGLE_SCALAR tests */
18-
public static function singleScalarResultSetProvider(): array
18+
/**
19+
* @return Generator<int, array{list<array<string,mixed>>,mixed}>
20+
*/
21+
public static function validResultSetProvider(): Generator
1922
{
20-
return [
21-
// valid
22-
'valid' => [
23-
'name' => 'result1',
24-
'resultSet' => [
25-
['u__name' => 'romanb'],
23+
// SELECT u.name FROM CmsUser u WHERE u.id = 1
24+
yield [
25+
[
26+
['u__name' => 'romanb'],
27+
],
28+
'romanb',
29+
];
30+
31+
// SELECT u.id FROM CmsUser u WHERE u.id = 1
32+
yield [
33+
[
34+
['u__id' => '1'],
35+
],
36+
1,
37+
];
38+
39+
// SELECT
40+
// u.id,
41+
// COUNT(u.postsCount + u.likesCount) AS HIDDEN score
42+
// FROM CmsUser u
43+
// WHERE u.id = 1
44+
yield [
45+
[
46+
[
47+
'u__id' => '1',
48+
'score' => 10, // Ignored since not part of ResultSetMapping (cf. HIDDEN keyword)
2649
],
2750
],
28-
// valid
51+
1,
52+
];
53+
}
54+
55+
/**
56+
* @param list<array<string, mixed>> $resultSet
57+
* @param mixed $expectedResult
58+
*
59+
* @dataProvider validResultSetProvider
60+
*/
61+
public function testHydrateSingleScalarFromFieldMappingWithValidResultSet(array $resultSet, $expectedResult): void
62+
{
63+
$rsm = new ResultSetMapping();
64+
$rsm->addEntityResult(CmsUser::class, 'u');
65+
$rsm->addFieldResult('u', 'u__id', 'id');
66+
$rsm->addFieldResult('u', 'u__name', 'name');
67+
68+
$stmt = ArrayResultFactory::createFromArray($resultSet);
69+
$hydrator = new SingleScalarHydrator($this->entityManager);
70+
71+
$result = $hydrator->hydrateAll($stmt, $rsm);
72+
$this->assertEquals($expectedResult, $result);
73+
}
74+
75+
/**
76+
* @param list<array<string, mixed>> $resultSet
77+
* @param mixed $expectedResult
78+
*
79+
* @dataProvider validResultSetProvider
80+
*/
81+
public function testHydrateSingleScalarFromScalarMappingWithValidResultSet(array $resultSet, $expectedResult): void
82+
{
83+
$rsm = new ResultSetMapping();
84+
$rsm->addScalarResult('u__id', 'id', 'string');
85+
$rsm->addScalarResult('u__name', 'name', 'string');
86+
87+
$stmt = ArrayResultFactory::createFromArray($resultSet);
88+
$hydrator = new SingleScalarHydrator($this->entityManager);
89+
90+
$result = $hydrator->hydrateAll($stmt, $rsm);
91+
$this->assertEquals($expectedResult, $result);
92+
}
93+
94+
/**
95+
* @return Generator<int, array{list<array<string,mixed>>}>
96+
*/
97+
public static function invalidResultSetProvider(): Generator
98+
{
99+
// Single row (OK), multiple columns (NOT OK)
100+
yield [
29101
[
30-
'name' => 'result2',
31-
'resultSet' => [
32-
['u__id' => '1'],
102+
[
103+
'u__id' => '1',
104+
'u__name' => 'romanb',
33105
],
34106
],
35-
// invalid
107+
];
108+
109+
// Multiple rows (NOT OK), single column (OK)
110+
yield [
111+
[
112+
['u__id' => '1'],
113+
['u__id' => '2'],
114+
],
115+
];
116+
117+
// Multiple rows (NOT OK), single column with HIDDEN result (OK)
118+
yield [
36119
[
37-
'name' => 'result3',
38-
'resultSet' => [
39-
[
40-
'u__id' => '1',
41-
'u__name' => 'romanb',
42-
],
120+
[
121+
'u__id' => '1',
122+
'score' => 10, // Ignored since not part of ResultSetMapping
123+
],
124+
[
125+
'u__id' => '2',
126+
'score' => 10, // Ignored since not part of ResultSetMapping
43127
],
44128
],
45-
// invalid
129+
1,
130+
];
131+
132+
// Multiple row (NOT OK), multiple columns (NOT OK)
133+
yield [
46134
[
47-
'name' => 'result4',
48-
'resultSet' => [
49-
['u__id' => '1'],
50-
['u__id' => '2'],
135+
[
136+
'u__id' => '1',
137+
'u__name' => 'romanb',
138+
],
139+
[
140+
'u__id' => '2',
141+
'u__name' => 'romanb',
51142
],
52143
],
53144
];
54145
}
55146

56147
/**
57-
* select u.name from CmsUser u where u.id = 1
148+
* @param list<array<string, mixed>> $resultSet
58149
*
59-
* @dataProvider singleScalarResultSetProvider
150+
* @dataProvider invalidResultSetProvider
60151
*/
61-
public function testHydrateSingleScalar($name, $resultSet): void
152+
public function testHydrateSingleScalarFromFieldMappingWithInvalidResultSet(array $resultSet): void
62153
{
63154
$rsm = new ResultSetMapping();
64155
$rsm->addEntityResult(CmsUser::class, 'u');
@@ -68,23 +159,25 @@ public function testHydrateSingleScalar($name, $resultSet): void
68159
$stmt = ArrayResultFactory::createFromArray($resultSet);
69160
$hydrator = new SingleScalarHydrator($this->entityManager);
70161

71-
if ($name === 'result1') {
72-
$result = $hydrator->hydrateAll($stmt, $rsm);
73-
self::assertEquals('romanb', $result);
74-
75-
return;
76-
}
162+
$this->expectException(NonUniqueResultException::class);
163+
$hydrator->hydrateAll($stmt, $rsm);
164+
}
77165

78-
if ($name === 'result2') {
79-
$result = $hydrator->hydrateAll($stmt, $rsm);
80-
self::assertEquals(1, $result);
166+
/**
167+
* @param list<array<string, mixed>> $resultSet
168+
*
169+
* @dataProvider invalidResultSetProvider
170+
*/
171+
public function testHydrateSingleScalarFromScalarMappingWithInvalidResultSet(array $resultSet): void
172+
{
173+
$rsm = new ResultSetMapping();
174+
$rsm->addScalarResult('u__id', 'id', 'string');
175+
$rsm->addScalarResult('u__name', 'name', 'string');
81176

82-
return;
83-
}
177+
$stmt = ArrayResultFactory::createFromArray($resultSet);
178+
$hydrator = new SingleScalarHydrator($this->entityManager);
84179

85-
if (in_array($name, ['result3', 'result4'], true)) {
86-
$this->expectException(NonUniqueResultException::class);
87-
$hydrator->hydrateAll($stmt, $rsm);
88-
}
180+
$this->expectException(NonUniqueResultException::class);
181+
$hydrator->hydrateAll($stmt, $rsm);
89182
}
90183
}

0 commit comments

Comments
 (0)