Skip to content

Commit bdb8df2

Browse files
fix(#424): address unintentional loss of string data type when retrieving PHP array item values from a stored TextArray value (#443)
1 parent d213967 commit bdb8df2

File tree

4 files changed

+137
-9
lines changed

4 files changed

+137
-9
lines changed

src/MartinGeorgiev/Doctrine/DBAL/Types/TextArray.php

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,31 @@ public function convertToPHPValue($value, AbstractPlatform $platform): ?array
6262

6363
protected function transformFromPostgresTextArray(string $postgresValue): array
6464
{
65-
if ($postgresValue === '{}') {
66-
return [];
65+
$values = PostgresArrayToPHPArrayTransformer::transformPostgresArrayToPHPArray($postgresValue);
66+
67+
// No matter what the original PHP array items' data types were,
68+
// once they are stored in PostgreSQL, all of them will become strings.
69+
// Therefore, we need to ensure all items in the returned PHP array are strings.
70+
foreach ($values as $key => $value) {
71+
if (\is_string($value)) {
72+
continue;
73+
}
74+
75+
if (\is_bool($value)) {
76+
$values[$key] = $value ? 'true' : 'false';
77+
78+
continue;
79+
}
80+
81+
if ($value === null) {
82+
$values[$key] = 'null';
83+
84+
continue;
85+
}
86+
87+
$values[$key] = (string) $value; // @phpstan-ignore-line
6788
}
6889

69-
return PostgresArrayToPHPArrayTransformer::transformPostgresArrayToPHPArray($postgresValue);
90+
return $values;
7091
}
7192
}

tests/Integration/MartinGeorgiev/Doctrine/DBAL/Types/TextArrayTypeTest.php

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ protected function getPostgresTypeName(): string
2020
}
2121

2222
#[DataProvider('provideValidTransformations')]
23+
#[DataProvider('provideGithubIssue424TestCases')]
2324
#[Test]
2425
public function can_handle_array_values(string $testName, array $arrayValue): void
2526
{
@@ -29,12 +30,57 @@ public function can_handle_array_values(string $testName, array $arrayValue): vo
2930
public static function provideValidTransformations(): array
3031
{
3132
return [
32-
'simple text array' => ['simple text array', ['foo', 'bar', 'baz']],
33-
'text array with special chars' => ['text array with special chars', ['foo"bar', 'baz\qux', 'with,comma']],
34-
'text array with empty strings' => ['text array with empty strings', ['', 'not empty', '']],
35-
'text array with unicode' => ['text array with unicode', ['café', 'naïve', 'résumé']],
36-
'text array with numbers as strings' => ['text array with numbers as strings', ['123', '456', '789']],
37-
'text array with null elements' => ['text array with null elements', ['foo', null, 'baz']],
33+
'simple text array' => [
34+
'simple text array',
35+
['foo', 'bar', 'baz'],
36+
],
37+
'text array with special chars' => [
38+
'text array with special chars',
39+
['foo"bar', 'baz\qux', 'with,comma'],
40+
],
41+
'text array with empty strings' => [
42+
'text array with empty strings',
43+
['', 'not empty', ''],
44+
],
45+
'text array with unicode' => [
46+
'text array with unicode',
47+
['café', 'naïve', 'résumé'],
48+
],
49+
'text array with numbers as strings' => [
50+
'text array with numbers as strings',
51+
['123', '456', '789'],
52+
],
53+
'text array with null element as string' => [
54+
'text array with null elements',
55+
['foo', 'null', 'baz'],
56+
],
57+
];
58+
}
59+
60+
/**
61+
* This test scenarios specifically verify the scenarios from GitHub issue #424
62+
* where PostgreSQL optimizes {"1","test"} to {1,test} and we have to ensure
63+
* that TextArray correctly preserves string types when converted back for PHP.
64+
*/
65+
public static function provideGithubIssue424TestCases(): array
66+
{
67+
return [
68+
'numeric values' => [
69+
'Numeric values should be preserved as strings',
70+
['1', 'test'],
71+
],
72+
'mixed values' => [
73+
'Mixed numeric values should be preserved as strings',
74+
['1', '2.5', '3.14', 'test', 'true', ''],
75+
],
76+
'boolean values' => [
77+
'Boolean values should be converted to strings',
78+
['1', '', '1', ''],
79+
],
80+
'null values' => [
81+
'Null values should be converted to strings',
82+
['', 'null', 'NULL'],
83+
],
3884
];
3985
}
4086
}

tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/TextArrayTest.php

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,61 @@ public function can_handle_backslashes_correctly(): void
122122

123123
$this->assertEquals($expectedPhpValue, $this->fixture->convertToPHPValue($postgresValue, $this->platform));
124124
}
125+
126+
#[DataProvider('provideGithubIssue424TestCases')]
127+
#[Test]
128+
public function can_preserve_string_types_retrieved_from_database_for_github_issue_424(string $testName, string $postgresValue, array $expectedResult): void
129+
{
130+
$result = $this->fixture->convertToPHPValue($postgresValue, $this->platform);
131+
132+
$this->assertSame($expectedResult, $result, $testName);
133+
134+
// Verify all values are strings
135+
foreach ($result as $value) {
136+
$this->assertIsString($value, $testName.' - all values should be strings');
137+
}
138+
}
139+
140+
/**
141+
* @return list<array{
142+
* testName: string,
143+
* postgresValue: string,
144+
* expectedResult: array{string}
145+
* }>
146+
*/
147+
public static function provideGithubIssue424TestCases(): array
148+
{
149+
return [
150+
[
151+
'testName' => 'Numeric values should be preserved as strings',
152+
'postgresValue' => '{1,test}',
153+
'expectedResult' => ['1', 'test'],
154+
],
155+
[
156+
'testName' => 'Mixed values should be preserved as strings',
157+
'postgresValue' => '{1,2.5,3.14,test,true,false}',
158+
'expectedResult' => ['1', '2.5', '3.14', 'test', 'true', 'false'],
159+
],
160+
[
161+
'testName' => 'Boolean-like values should be converted to strings',
162+
'postgresValue' => '{true,false}',
163+
'expectedResult' => ['true', 'false'],
164+
],
165+
[
166+
'testName' => 'Quoted boolean-like values should remain as strings',
167+
'postgresValue' => '{"true","false","t","f"}',
168+
'expectedResult' => ['true', 'false', 't', 'f'],
169+
],
170+
[
171+
'testName' => 'Mixed quoted/unquoted values should all be strings',
172+
'postgresValue' => '{1,"2",true,"false",3.14,"test"}',
173+
'expectedResult' => ['1', '2', 'true', 'false', '3.14', 'test'],
174+
],
175+
[
176+
'testName' => 'Null values should be converted to strings',
177+
'postgresValue' => '{"",null,"null","NULL"}',
178+
'expectedResult' => ['', 'null', 'null', 'NULL'],
179+
],
180+
];
181+
}
125182
}

tests/Unit/MartinGeorgiev/Utils/PostgresArrayToPHPArrayTransformerTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ public static function provideValidTransformations(): array
166166
'phpValue' => [' foo '],
167167
'postgresValue' => '{" foo "}',
168168
],
169+
'github #424 regression: numeric strings should be preserved as strings when unquoted' => [
170+
'phpValue' => ['1', 'test', 'true'],
171+
'postgresValue' => '{1,test,true}',
172+
],
169173
];
170174
}
171175

0 commit comments

Comments
 (0)