Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions src/QueryReflection/Parameter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

namespace staabm\PHPStanDba\QueryReflection;

use PHPStan\Type\Type;

final class Parameter
{
/**
* @var non-empty-string|null
*/
public $name;
/**
* @var Type
*/
public $type;
/**
* @var ?string
*/
public $simulatedValue;
/**
* @var bool
*/
public $isOptional;

/**
* @param non-empty-string|null $name
*/
public function __construct(?string $name, Type $type, ?string $simulatedValue, bool $isOptional)
{
$this->type = $type;
$this->simulatedValue = $simulatedValue;
$this->isOptional = $isOptional;

if (null === $name) {
return;
}

if (!str_starts_with($name, ':')) {
$name = ':'.$name;
}

$this->name = $name;
}
}
4 changes: 2 additions & 2 deletions src/QueryReflection/PlaceholderValidation.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
final class PlaceholderValidation
{
/**
* @param array<string|int, scalar|null> $parameters
* @param array<string|int, Parameter> $parameters
*
* @return iterable<string>
*/
Expand Down Expand Up @@ -39,7 +39,7 @@ public function checkErrors(string $queryString, array $parameters): iterable
}

/**
* @param array<string|int, scalar|null> $parameters
* @param array<string|int, Parameter> $parameters
*
* @return iterable<string>
*/
Expand Down
40 changes: 30 additions & 10 deletions src/QueryReflection/QueryReflection.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\BinaryOp\Concat;
use PHPStan\Analyser\Scope;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Constant\ConstantIntegerType;
use PHPStan\Type\Constant\ConstantStringType;
Expand Down Expand Up @@ -204,7 +205,7 @@ public static function getQueryType(string $query): ?string
*
* @throws UnresolvableQueryException
*
* @return array<string|int, scalar|null>|null
* @return array<string|int, Parameter>|null
*/
public function resolveParameters(Type $parameterTypes): ?array
{
Expand All @@ -213,18 +214,35 @@ public function resolveParameters(Type $parameterTypes): ?array
if ($parameterTypes instanceof ConstantArrayType) {
$keyTypes = $parameterTypes->getKeyTypes();
$valueTypes = $parameterTypes->getValueTypes();
$optionalKeys = $parameterTypes->getOptionalKeys();

foreach ($keyTypes as $i => $keyType) {
$isOptional = \in_array($i, $optionalKeys, true);

if ($keyType instanceof ConstantStringType) {
$placeholderName = $keyType->getValue();

if (!str_starts_with($placeholderName, ':')) {
$placeholderName = ':'.$placeholderName;
if ('' === $placeholderName) {
throw new ShouldNotHappenException('Empty placeholder name');
}

$parameters[$placeholderName] = QuerySimulation::simulateParamValueType($valueTypes[$i], true);
$param = new Parameter(
$placeholderName,
$valueTypes[$i],
QuerySimulation::simulateParamValueType($valueTypes[$i], true),
$isOptional
);

$parameters[$param->name] = $param;
} elseif ($keyType instanceof ConstantIntegerType) {
$parameters[$keyType->getValue()] = QuerySimulation::simulateParamValueType($valueTypes[$i], true);
$param = new Parameter(
null,
$valueTypes[$i],
QuerySimulation::simulateParamValueType($valueTypes[$i], true),
$isOptional
);

$parameters[$keyType->getValue()] = $param;
}
}

Expand All @@ -235,7 +253,7 @@ public function resolveParameters(Type $parameterTypes): ?array
}

/**
* @param array<string|int, scalar|null> $parameters
* @param array<string|int, Parameter> $parameters
*/
private function replaceParameters(string $queryString, array $parameters): string
{
Expand All @@ -248,7 +266,9 @@ private function replaceParameters(string $queryString, array $parameters): stri
return $haystack;
};

foreach ($parameters as $placeholderKey => $value) {
foreach ($parameters as $placeholderKey => $parameter) {
$value = $parameter->simulatedValue;

if (\is_string($value)) {
// XXX escaping
$value = "'".$value."'";
Expand All @@ -258,10 +278,10 @@ private function replaceParameters(string $queryString, array $parameters): stri
$value = (string) $value;
}

if (\is_int($placeholderKey)) {
$queryString = $replaceFirst($queryString, '?', $value);
} else {
if (\is_string($placeholderKey)) {
$queryString = str_replace($placeholderKey, $value, $queryString);
} else {
$queryString = $replaceFirst($queryString, '?', $value);
}
}

Expand Down