Skip to content

Commit 6f4f3c0

Browse files
committed
[SCA] Restrict the possible values for the casing options under the Portability\ NS
1 parent 2c8afad commit 6f4f3c0

File tree

8 files changed

+56
-32
lines changed

8 files changed

+56
-32
lines changed

psalm.xml.dist

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,9 @@
611611
<errorLevel type="suppress">
612612
<!-- See https://github.com/vimeo/psalm/issues/5472 -->
613613
<file name="src/Portability/Converter.php"/>
614+
615+
<!-- See https://github.com/vimeo/psalm/issues/3399 -->
616+
<file name="tests/Functional/PortabilityTest.php"/>
614617
</errorLevel>
615618
</InvalidDocblock>
616619
<InvalidNullableReturnType>

src/Portability/Converter.php

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,14 @@
1010
use function is_string;
1111
use function rtrim;
1212

13+
use const CASE_LOWER;
14+
use const CASE_UPPER;
15+
1316
final class Converter
1417
{
18+
public const CASE_LOWER = CASE_LOWER;
19+
public const CASE_UPPER = CASE_UPPER;
20+
1521
/** @var callable */
1622
private $convertNumeric;
1723

@@ -31,10 +37,12 @@ final class Converter
3137
private $convertFirstColumn;
3238

3339
/**
34-
* @param bool $convertEmptyStringToNull Whether each empty string should be converted to NULL
35-
* @param bool $rightTrimString Whether each string should right-trimmed
36-
* @param int|null $case Convert the case of the column names
37-
* (one of {@see CASE_LOWER} and {@see CASE_UPPER})
40+
* @param bool $convertEmptyStringToNull Whether each empty string should
41+
* be converted to NULL
42+
* @param bool $rightTrimString Whether each string should right-trimmed
43+
* @param self::CASE_LOWER|self::CASE_UPPER|null $case Convert the case of the column names
44+
* (one of {@see self::CASE_LOWER} and
45+
* {@see self::CASE_UPPER})
3846
*/
3947
public function __construct(bool $convertEmptyStringToNull, bool $rightTrimString, ?int $case)
4048
{
@@ -182,8 +190,8 @@ private function createConvertValue(bool $convertEmptyStringToNull, bool $rightT
182190
/**
183191
* Creates a function that will convert each array-row retrieved from the database
184192
*
185-
* @param callable|null $function The function that will convert each value
186-
* @param int|null $case Column name case
193+
* @param callable|null $function The function that will convert each value
194+
* @param self::CASE_LOWER|self::CASE_UPPER|null $case Column name case
187195
*
188196
* @return callable|null The resulting function or NULL if no conversion is needed
189197
*/

src/Portability/Driver.php

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,19 @@
1111

1212
use function method_exists;
1313

14-
use const CASE_LOWER;
15-
use const CASE_UPPER;
16-
1714
final class Driver extends AbstractDriverMiddleware
1815
{
1916
private int $mode;
2017

18+
/** @var 0|ColumnCase::LOWER|ColumnCase::UPPER */
2119
private int $case;
2220

21+
/**
22+
* @param 0|ColumnCase::LOWER|ColumnCase::UPPER $case Determines how the column case will be treated.
23+
* 0: The case will be left as is in the database.
24+
* {@see ColumnCase::LOWER}: The case will be lowercased.
25+
* {@see ColumnCase::UPPER}: The case will be uppercased.
26+
*/
2327
public function __construct(DriverInterface $driver, int $mode, int $case)
2428
{
2529
parent::__construct($driver);
@@ -55,9 +59,12 @@ public function connect(
5559

5660
if ($nativeConnection instanceof PDO) {
5761
$portability &= ~Connection::PORTABILITY_FIX_CASE;
58-
$nativeConnection->setAttribute(PDO::ATTR_CASE, $this->case);
62+
$nativeConnection->setAttribute(
63+
PDO::ATTR_CASE,
64+
$this->case === ColumnCase::LOWER ? PDO::CASE_LOWER : PDO::CASE_UPPER
65+
);
5966
} else {
60-
$case = $this->case === ColumnCase::LOWER ? CASE_LOWER : CASE_UPPER;
67+
$case = $this->case === ColumnCase::LOWER ? Converter::CASE_LOWER : Converter::CASE_UPPER;
6168
}
6269
}
6370

src/Portability/Middleware.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,18 @@
44

55
namespace Doctrine\DBAL\Portability;
66

7+
use Doctrine\DBAL\ColumnCase;
78
use Doctrine\DBAL\Driver as DriverInterface;
89
use Doctrine\DBAL\Driver\Middleware as MiddlewareInterface;
910

1011
final class Middleware implements MiddlewareInterface
1112
{
1213
private int $mode;
1314

15+
/** @var 0|ColumnCase::LOWER|ColumnCase::UPPER */
1416
private int $case;
1517

18+
/** @param 0|ColumnCase::LOWER|ColumnCase::UPPER $case */
1619
public function __construct(int $mode, int $case)
1720
{
1821
$this->mode = $mode;

src/Portability/OptimizeFlags.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ final class OptimizeFlags
1717
* Platform-specific portability flags that need to be excluded from the user-provided mode
1818
* since the platform already operates in this mode to avoid unnecessary conversion overhead.
1919
*
20-
* @var array<string,int>
20+
* @var array<class-string, int>
2121
*/
2222
private static array $platforms = [
2323
DB2Platform::class => 0,

tests/Functional/PortabilityTest.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ public function testFullFetchMode(): void
4646
}
4747

4848
/**
49-
* @param list<string> $expected
49+
* @param 0|ColumnCase::LOWER|ColumnCase::UPPER $case
50+
* @param list<string> $expected
5051
*
5152
* @dataProvider caseProvider
5253
*/
@@ -61,7 +62,7 @@ public function testCaseConversion(int $case, array $expected): void
6162
self::assertSame($expected, array_keys($row));
6263
}
6364

64-
/** @return iterable<string, array{int, list<string>}> */
65+
/** @return iterable<string, array{ColumnCase::LOWER|ColumnCase::UPPER, list<string>}> */
6566
public static function caseProvider(): iterable
6667
{
6768
yield 'lower' => [ColumnCase::LOWER, ['test_int', 'test_string', 'test_null']];
@@ -137,6 +138,7 @@ public function testGetDatabaseName(): void
137138
self::assertNotNull($this->connection->getDatabase());
138139
}
139140

141+
/** @param 0|ColumnCase::LOWER|ColumnCase::UPPER $case */
140142
private function connectWithPortability(int $mode, int $case): void
141143
{
142144
// closing the default connection prior to 4.0.0 to prevent connection leak

tests/Portability/ConnectionTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public function testGetServerVersion(): void
1818
->method('getServerVersion')
1919
->willReturn('1.2.3');
2020

21-
$connection = new Connection($driverConnection, new Converter(false, false, 0));
21+
$connection = new Connection($driverConnection, new Converter(false, false, Converter::CASE_LOWER));
2222

2323
self::assertSame('1.2.3', $connection->getServerVersion());
2424
}
@@ -27,7 +27,7 @@ public function testGetServerVersionFailsWithLegacyConnection(): void
2727
{
2828
$connection = new Connection(
2929
$this->createMock(DriverConnection::class),
30-
new Converter(false, false, 0),
30+
new Converter(false, false, Converter::CASE_LOWER),
3131
);
3232

3333
$this->expectException(LogicException::class);
@@ -43,7 +43,7 @@ public function testGetNativeConnection(): void
4343
$driverConnection->method('getNativeConnection')
4444
->willReturn($nativeConnection);
4545

46-
$connection = new Connection($driverConnection, new Converter(false, false, 0));
46+
$connection = new Connection($driverConnection, new Converter(false, false, Converter::CASE_LOWER));
4747

4848
self::assertSame($nativeConnection, $connection->getNativeConnection());
4949
}
@@ -52,7 +52,7 @@ public function testGetNativeConnectionFailsWithLegacyConnection(): void
5252
{
5353
$connection = new Connection(
5454
$this->createMock(DriverConnection::class),
55-
new Converter(false, false, 0),
55+
new Converter(false, false, Converter::CASE_LOWER),
5656
);
5757

5858
$this->expectException(LogicException::class);

tests/Portability/ConverterTest.php

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
use Doctrine\DBAL\Portability\Converter;
66
use PHPUnit\Framework\TestCase;
77

8-
use const CASE_LOWER;
9-
108
class ConverterTest extends TestCase
119
{
1210
/**
@@ -61,8 +59,9 @@ public static function convertNumericProvider(): iterable
6159
}
6260

6361
/**
64-
* @param array<string,mixed>|false $row
65-
* @param array<string,mixed>|false $expected
62+
* @param array<string,mixed>|false $row
63+
* @param Converter::CASE_LOWER|Converter::CASE_UPPER|null $case
64+
* @param array<string,mixed>|false $expected
6665
*
6766
* @dataProvider convertAssociativeProvider
6867
*/
@@ -136,7 +135,7 @@ public static function convertAssociativeProvider(): iterable
136135
$row,
137136
false,
138137
false,
139-
CASE_LOWER,
138+
Converter::CASE_LOWER,
140139
[
141140
'foo' => '',
142141
'bar' => 'X ',
@@ -147,7 +146,7 @@ public static function convertAssociativeProvider(): iterable
147146
$row,
148147
false,
149148
true,
150-
CASE_LOWER,
149+
Converter::CASE_LOWER,
151150
[
152151
'foo' => '',
153152
'bar' => 'X',
@@ -158,7 +157,7 @@ public static function convertAssociativeProvider(): iterable
158157
$row,
159158
true,
160159
false,
161-
CASE_LOWER,
160+
Converter::CASE_LOWER,
162161
[
163162
'foo' => null,
164163
'bar' => 'X ',
@@ -169,7 +168,7 @@ public static function convertAssociativeProvider(): iterable
169168
$row,
170169
true,
171170
true,
172-
CASE_LOWER,
171+
Converter::CASE_LOWER,
173172
[
174173
'foo' => null,
175174
'bar' => 'X',
@@ -276,8 +275,9 @@ public static function convertAllNumericProvider(): iterable
276275
}
277276

278277
/**
279-
* @param list<array<string,mixed>> $row
280-
* @param list<array<string,mixed>> $expected
278+
* @param list<array<string,mixed>> $row
279+
* @param Converter::CASE_LOWER|Converter::CASE_UPPER|null $case
280+
* @param list<array<string,mixed>> $expected
281281
*
282282
* @dataProvider convertAllAssociativeProvider
283283
*/
@@ -381,7 +381,7 @@ public static function convertAllAssociativeProvider(): iterable
381381
$data,
382382
false,
383383
false,
384-
CASE_LOWER,
384+
Converter::CASE_LOWER,
385385
[
386386
[
387387
'foo' => 'X ',
@@ -398,7 +398,7 @@ public static function convertAllAssociativeProvider(): iterable
398398
$data,
399399
false,
400400
true,
401-
CASE_LOWER,
401+
Converter::CASE_LOWER,
402402
[
403403
[
404404
'foo' => 'X',
@@ -415,7 +415,7 @@ public static function convertAllAssociativeProvider(): iterable
415415
$data,
416416
true,
417417
false,
418-
CASE_LOWER,
418+
Converter::CASE_LOWER,
419419
[
420420
[
421421
'foo' => 'X ',
@@ -432,7 +432,7 @@ public static function convertAllAssociativeProvider(): iterable
432432
$data,
433433
true,
434434
true,
435-
CASE_LOWER,
435+
Converter::CASE_LOWER,
436436
[
437437
[
438438
'foo' => 'X',
@@ -499,6 +499,7 @@ public static function convertFirstColumnProvider(): iterable
499499
];
500500
}
501501

502+
/** @param Converter::CASE_LOWER|Converter::CASE_UPPER|null $case */
502503
private function createConverter(bool $convertEmptyStringToNull, bool $rightTrimString, ?int $case): Converter
503504
{
504505
return new Converter($convertEmptyStringToNull, $rightTrimString, $case);

0 commit comments

Comments
 (0)