Skip to content

Commit 782a1cb

Browse files
committed
Fix string TypedExpression (not actually typed)
1 parent add494f commit 782a1cb

File tree

3 files changed

+61
-3
lines changed

3 files changed

+61
-3
lines changed

src/Type/Doctrine/Query/QueryResultTypeWalker.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PHPStan\Type\Doctrine\Query;
44

55
use BackedEnum;
6+
use Doctrine\DBAL\Types\StringType as DbalStringType;
67
use Doctrine\DBAL\Types\Type as DbalType;
78
use Doctrine\ORM\EntityManagerInterface;
89
use Doctrine\ORM\Mapping\ClassMetadata;
@@ -1118,11 +1119,16 @@ public function walkSelectExpression($selectExpression): string
11181119
$resultAlias = $selectExpression->fieldIdentificationVariable ?? $this->scalarResultCounter++;
11191120
$type = $this->unmarshalType($expr->dispatch($this));
11201121

1121-
if ($expr instanceof TypedExpression) {
1122+
if (
1123+
$expr instanceof TypedExpression
1124+
&& !$expr->getReturnType() instanceof DbalStringType // StringType is no-op, so using TypedExpression with that does nothing
1125+
) {
1126+
$dbalTypeName = DbalType::getTypeRegistry()->lookupName($expr->getReturnType());
11221127
$type = TypeCombinator::intersect( // e.g. count is typed as int, but we infer int<0, max>
11231128
$type,
1124-
$this->resolveDoctrineType(DbalType::getTypeRegistry()->lookupName($expr->getReturnType()), null, TypeCombinator::containsNull($type))
1129+
$this->resolveDoctrineType($dbalTypeName, null, TypeCombinator::containsNull($type))
11251130
);
1131+
11261132
} else {
11271133
// Expressions default to Doctrine's StringType, whose
11281134
// convertToPHPValue() is a no-op. So the actual type depends on

tests/Platform/QueryResultTypeWalkerFetchTypeMatrixTest.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
use PHPStan\Type\VerbosityLevel;
4747
use PHPUnit\Framework\Constraint\IsEqual;
4848
use PHPUnit\Framework\Constraint\IsIdentical;
49+
use Platform\TypedExpressionStringPiFunction;
4950
use Throwable;
5051
use function floor;
5152
use function getenv;
@@ -3436,6 +3437,24 @@ public static function provideCases(): iterable
34363437
},
34373438
];
34383439

3440+
yield 'STRING_PI()' => [
3441+
'data' => self::dataDefault(),
3442+
'select' => 'SELECT STRING_PI() FROM %s t',
3443+
'mysql' => self::mixed(),
3444+
'sqlite' => self::mixed(),
3445+
'pdo_pgsql' => self::mixed(),
3446+
'pgsql' => self::mixed(),
3447+
'mssql' => self::mixed(),
3448+
'mysqlResult' => '3.14159',
3449+
'sqliteResult' => 3.14159,
3450+
'pdoPgsqlResult' => '3.14159',
3451+
'pgsqlResult' => '3.14159',
3452+
'mssqlResult' => '3.14159',
3453+
'shouldStringify' => static function (Driver $driver, int $php, string $configName): bool {
3454+
return self::defaultStringification($driver, $php, $configName);
3455+
},
3456+
];
3457+
34393458
yield 'COALESCE(t.col_datetime, t.col_datetime)' => [
34403459
'data' => self::dataDefault(),
34413460
'select' => 'SELECT COALESCE(t.col_datetime, t.col_datetime) FROM %s t',
@@ -3454,7 +3473,6 @@ public static function provideCases(): iterable
34543473
},
34553474
];
34563475

3457-
// TODO string TypedExpression does not cast to string
34583476
// TODO would col_numeric_string differ from col_string results ?
34593477
// TODO dbal/orm versions
34603478
// TODO also wrap driver to test alternative driver detection
@@ -3579,6 +3597,7 @@ private function getQuery(
35793597
$config->setMetadataDriverImpl(new AnnotationDriver(new AnnotationReader(), [__DIR__ . '/Entity']));
35803598
$config->addCustomStringFunction('INT_PI', TypedExpressionIntegerPiFunction::class);
35813599
$config->addCustomStringFunction('BOOL_PI', TypedExpressionBooleanPiFunction::class);
3600+
$config->addCustomStringFunction('STRING_PI', TypedExpressionStringPiFunction::class);
35823601
$entityManager = new EntityManager($connection, $config);
35833602

35843603
$schemaTool = new SchemaTool($entityManager);
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Platform;
4+
5+
use Doctrine\DBAL\Types\Type;
6+
use Doctrine\DBAL\Types\Types;
7+
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
8+
use Doctrine\ORM\Query\AST\TypedExpression;
9+
use Doctrine\ORM\Query\Parser;
10+
use Doctrine\ORM\Query\SqlWalker;
11+
use Doctrine\ORM\Query\TokenType;
12+
13+
class TypedExpressionStringPiFunction extends FunctionNode implements TypedExpression
14+
{
15+
16+
public function getSql(SqlWalker $sqlWalker): string
17+
{
18+
return '3.14159';
19+
}
20+
21+
public function parse(Parser $parser): void
22+
{
23+
$parser->match(TokenType::T_IDENTIFIER);
24+
$parser->match(TokenType::T_OPEN_PARENTHESIS);
25+
$parser->match(TokenType::T_CLOSE_PARENTHESIS);
26+
}
27+
28+
public function getReturnType(): Type
29+
{
30+
return Type::getType(Types::STRING);
31+
}
32+
33+
}

0 commit comments

Comments
 (0)