From 3700808e3523557a72188fe61ae8f1262aad528f Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 10 Oct 2026 08:22:06 +0200 Subject: [PATCH 1/4] Tracking dependencies on values --- composer.json | 2 +- config/extensions.neon | 2 +- .../DbSchemaResultCacheMetaExtension.php | 31 +++++++++++++++---- ...unMysqlQueryDynamicReturnTypeExtension.php | 2 ++ ...nectionFetchDynamicReturnTypeExtension.php | 2 ++ ...ExecuteQueryDynamicReturnTypeExtension.php | 2 ++ ...nectionFetchDynamicReturnTypeExtension.php | 2 ++ ...ctionPrepareDynamicReturnTypeExtension.php | 2 ++ ...nectionQueryDynamicReturnTypeExtension.php | 2 ++ ...ctrineResultDynamicReturnTypeExtension.php | 2 ++ ...ementExecuteDynamicReturnTypeExtension.php | 2 ++ ...EscapeStringDynamicReturnTypeExtension.php | 4 +++ .../MysqliQueryDynamicReturnTypeExtension.php | 4 +++ .../PdoPrepareDynamicReturnTypeExtension.php | 2 ++ .../PdoQueryDynamicReturnTypeExtension.php | 2 ++ .../PdoQuoteDynamicReturnTypeExtension.php | 2 ++ ...tColumnCountDynamicReturnTypeExtension.php | 2 ++ ...tatementExecuteTypeSpecifyingExtension.php | 2 ++ ...atementFetchDynamicReturnTypeExtension.php | 2 ++ ...tFetchObjectDynamicReturnTypeExtension.php | 2 ++ ...entSetFetchModeTypeSpecifyingExtension.php | 2 ++ src/Rules/DoctrineKeyValueStyleRule.php | 3 ++ src/Rules/PdoStatementExecuteMethodRule.php | 3 ++ src/Rules/QueryPlanAnalyzerRule.php | 3 ++ ...ErrorInDibiPreparedStatementMethodRule.php | 3 ++ ...ntaxErrorInPreparedStatementMethodRule.php | 3 ++ src/Rules/SyntaxErrorInQueryFunctionRule.php | 3 ++ src/Rules/SyntaxErrorInQueryMethodRule.php | 3 ++ 28 files changed, 88 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 77155e4c1..2e4090fb1 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,7 @@ "php": "^7.4 || ^8.0", "composer-runtime-api": "^2.0", "composer/semver": "^3.2", - "phpstan/phpstan": "^2.1.2" + "phpstan/phpstan": "^2.3.0" }, "require-dev": { "ext-mysqli": "*", diff --git a/config/extensions.neon b/config/extensions.neon index a01171797..437374315 100644 --- a/config/extensions.neon +++ b/config/extensions.neon @@ -102,4 +102,4 @@ services: - class: staabm\PHPStanDba\Extensions\DbSchemaResultCacheMetaExtension tags: - - phpstan.resultCacheMetaExtension + - phpstan.resultCacheValueExtension diff --git a/src/Extensions/DbSchemaResultCacheMetaExtension.php b/src/Extensions/DbSchemaResultCacheMetaExtension.php index 91420b338..f2953dfcc 100644 --- a/src/Extensions/DbSchemaResultCacheMetaExtension.php +++ b/src/Extensions/DbSchemaResultCacheMetaExtension.php @@ -4,23 +4,32 @@ namespace staabm\PHPStanDba\Extensions; -use PHPStan\Analyser\ResultCache\ResultCacheMetaExtension; +use PHPStan\Analyser\DependencyTracker; +use PHPStan\Analyser\ResultCache\ResultCacheValueExtension; +use PHPStan\Analyser\Scope; use staabm\PHPStanDba\DbaException; use staabm\PHPStanDba\QueryReflection\QueryReflection; -// @phpstan-ignore class.implementsDeprecatedInterface -final class DbSchemaResultCacheMetaExtension implements ResultCacheMetaExtension +final class DbSchemaResultCacheMetaExtension implements ResultCacheValueExtension { - public function getKey(): string + public const SCHEMA_KEY = 'schema'; + + /** + * Marks the currently analysed file as dependent on the database schema. + */ + public static function trackSchemaDependency(Scope $scope): void { - return 'phpstan-dba-schema-hash'; + if ($scope instanceof DependencyTracker) { + $scope->trackValueDependency(self::class, self::SCHEMA_KEY); + } } - public function getHash(): string + public function getValue(string $key): string { try { $queryReflection = new QueryReflection(); $schemaHasher = $queryReflection->getSchemaHasher(); + return $schemaHasher->hashDb(); } catch (DbaException $e) { // don't break the whole process when reflector is not @@ -29,4 +38,14 @@ public function getHash(): string return 'reflector-not-initialized'; } } + + public function keyToResultCache(string $key): string + { + return $key; + } + + public function keyFromResultCache(string $storedKey): string + { + return $storedKey; + } } diff --git a/src/Extensions/DeployerRunMysqlQueryDynamicReturnTypeExtension.php b/src/Extensions/DeployerRunMysqlQueryDynamicReturnTypeExtension.php index 1834365c2..123885789 100644 --- a/src/Extensions/DeployerRunMysqlQueryDynamicReturnTypeExtension.php +++ b/src/Extensions/DeployerRunMysqlQueryDynamicReturnTypeExtension.php @@ -27,6 +27,8 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): ?Type { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $args = $functionCall->getArgs(); if (\count($args) < 2) { diff --git a/src/Extensions/DibiConnectionFetchDynamicReturnTypeExtension.php b/src/Extensions/DibiConnectionFetchDynamicReturnTypeExtension.php index 97f873a4d..2dec1a35c 100644 --- a/src/Extensions/DibiConnectionFetchDynamicReturnTypeExtension.php +++ b/src/Extensions/DibiConnectionFetchDynamicReturnTypeExtension.php @@ -41,6 +41,8 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): ?Type { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $args = $methodCall->getArgs(); if (\count($args) < 1) { diff --git a/src/Extensions/DoctrineConnectionExecuteQueryDynamicReturnTypeExtension.php b/src/Extensions/DoctrineConnectionExecuteQueryDynamicReturnTypeExtension.php index bbc43815a..0a6547bda 100644 --- a/src/Extensions/DoctrineConnectionExecuteQueryDynamicReturnTypeExtension.php +++ b/src/Extensions/DoctrineConnectionExecuteQueryDynamicReturnTypeExtension.php @@ -33,6 +33,8 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): ?Type { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $args = $methodCall->getArgs(); if (\count($args) < 1) { diff --git a/src/Extensions/DoctrineConnectionFetchDynamicReturnTypeExtension.php b/src/Extensions/DoctrineConnectionFetchDynamicReturnTypeExtension.php index 57d866ac3..66be76042 100644 --- a/src/Extensions/DoctrineConnectionFetchDynamicReturnTypeExtension.php +++ b/src/Extensions/DoctrineConnectionFetchDynamicReturnTypeExtension.php @@ -46,6 +46,8 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): ?Type { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $args = $methodCall->getArgs(); if (\count($args) < 1) { diff --git a/src/Extensions/DoctrineConnectionPrepareDynamicReturnTypeExtension.php b/src/Extensions/DoctrineConnectionPrepareDynamicReturnTypeExtension.php index 2f6987a80..9657fa9ce 100644 --- a/src/Extensions/DoctrineConnectionPrepareDynamicReturnTypeExtension.php +++ b/src/Extensions/DoctrineConnectionPrepareDynamicReturnTypeExtension.php @@ -33,6 +33,8 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): ?Type { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $args = $methodCall->getArgs(); if (\count($args) < 1) { diff --git a/src/Extensions/DoctrineConnectionQueryDynamicReturnTypeExtension.php b/src/Extensions/DoctrineConnectionQueryDynamicReturnTypeExtension.php index 8ff4436c5..ca9508c28 100644 --- a/src/Extensions/DoctrineConnectionQueryDynamicReturnTypeExtension.php +++ b/src/Extensions/DoctrineConnectionQueryDynamicReturnTypeExtension.php @@ -33,6 +33,8 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): ?Type { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $args = $methodCall->getArgs(); if (\count($args) < 1) { diff --git a/src/Extensions/DoctrineResultDynamicReturnTypeExtension.php b/src/Extensions/DoctrineResultDynamicReturnTypeExtension.php index fb6a6aa4e..0c36444e9 100644 --- a/src/Extensions/DoctrineResultDynamicReturnTypeExtension.php +++ b/src/Extensions/DoctrineResultDynamicReturnTypeExtension.php @@ -47,6 +47,8 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): ?Type { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + // make sure we don't report wrong types in doctrine 2.x if (! InstalledVersions::satisfies(new VersionParser(), 'doctrine/dbal', '3.*|4.*')) { return null; diff --git a/src/Extensions/DoctrineStatementExecuteDynamicReturnTypeExtension.php b/src/Extensions/DoctrineStatementExecuteDynamicReturnTypeExtension.php index 9642d4534..b64d11712 100644 --- a/src/Extensions/DoctrineStatementExecuteDynamicReturnTypeExtension.php +++ b/src/Extensions/DoctrineStatementExecuteDynamicReturnTypeExtension.php @@ -33,6 +33,8 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): ?Type { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $args = $methodCall->getArgs(); if (\count($args) < 1) { diff --git a/src/Extensions/MysqliEscapeStringDynamicReturnTypeExtension.php b/src/Extensions/MysqliEscapeStringDynamicReturnTypeExtension.php index 422489b32..2db5e15ec 100644 --- a/src/Extensions/MysqliEscapeStringDynamicReturnTypeExtension.php +++ b/src/Extensions/MysqliEscapeStringDynamicReturnTypeExtension.php @@ -49,6 +49,8 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): Type { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $args = $functionCall->getArgs(); $defaultReturn = ParametersAcceptorSelector::selectFromArgs( $scope, @@ -71,6 +73,8 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $args = $methodCall->getArgs(); $defaultReturn = ParametersAcceptorSelector::selectFromArgs( $scope, diff --git a/src/Extensions/MysqliQueryDynamicReturnTypeExtension.php b/src/Extensions/MysqliQueryDynamicReturnTypeExtension.php index 7bf71249e..441397db0 100644 --- a/src/Extensions/MysqliQueryDynamicReturnTypeExtension.php +++ b/src/Extensions/MysqliQueryDynamicReturnTypeExtension.php @@ -50,6 +50,8 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): Type { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $args = $functionCall->getArgs(); $defaultReturn = ParametersAcceptorSelector::selectFromArgs( $scope, @@ -79,6 +81,8 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $args = $methodCall->getArgs(); $defaultReturn = ParametersAcceptorSelector::selectFromArgs( $scope, diff --git a/src/Extensions/PdoPrepareDynamicReturnTypeExtension.php b/src/Extensions/PdoPrepareDynamicReturnTypeExtension.php index e57e9164d..0e7eff9c6 100644 --- a/src/Extensions/PdoPrepareDynamicReturnTypeExtension.php +++ b/src/Extensions/PdoPrepareDynamicReturnTypeExtension.php @@ -41,6 +41,8 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $args = $methodCall->getArgs(); $defaultReturn = ParametersAcceptorSelector::selectFromArgs( $scope, diff --git a/src/Extensions/PdoQueryDynamicReturnTypeExtension.php b/src/Extensions/PdoQueryDynamicReturnTypeExtension.php index bb6a487ab..3aba0b1f7 100644 --- a/src/Extensions/PdoQueryDynamicReturnTypeExtension.php +++ b/src/Extensions/PdoQueryDynamicReturnTypeExtension.php @@ -43,6 +43,8 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $args = $methodCall->getArgs(); $defaultReturn = ParametersAcceptorSelector::selectFromArgs( $scope, diff --git a/src/Extensions/PdoQuoteDynamicReturnTypeExtension.php b/src/Extensions/PdoQuoteDynamicReturnTypeExtension.php index 1a4cf50f5..92ab6c459 100644 --- a/src/Extensions/PdoQuoteDynamicReturnTypeExtension.php +++ b/src/Extensions/PdoQuoteDynamicReturnTypeExtension.php @@ -43,6 +43,8 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $args = $methodCall->getArgs(); $defaultReturn = ParametersAcceptorSelector::selectFromArgs( $scope, diff --git a/src/Extensions/PdoStatementColumnCountDynamicReturnTypeExtension.php b/src/Extensions/PdoStatementColumnCountDynamicReturnTypeExtension.php index 6af01635d..476fa9cd4 100644 --- a/src/Extensions/PdoStatementColumnCountDynamicReturnTypeExtension.php +++ b/src/Extensions/PdoStatementColumnCountDynamicReturnTypeExtension.php @@ -28,6 +28,8 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): ?Type { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $statementType = $scope->getType($methodCall->var); if ($statementType instanceof PdoStatementObjectType) { diff --git a/src/Extensions/PdoStatementExecuteTypeSpecifyingExtension.php b/src/Extensions/PdoStatementExecuteTypeSpecifyingExtension.php index 310b275b8..e94d0b945 100644 --- a/src/Extensions/PdoStatementExecuteTypeSpecifyingExtension.php +++ b/src/Extensions/PdoStatementExecuteTypeSpecifyingExtension.php @@ -42,6 +42,8 @@ public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void public function specifyTypes(MethodReflection $methodReflection, MethodCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + // keep original param name because named-parameters $methodCall = $node; diff --git a/src/Extensions/PdoStatementFetchDynamicReturnTypeExtension.php b/src/Extensions/PdoStatementFetchDynamicReturnTypeExtension.php index 64178009a..bcf89210c 100644 --- a/src/Extensions/PdoStatementFetchDynamicReturnTypeExtension.php +++ b/src/Extensions/PdoStatementFetchDynamicReturnTypeExtension.php @@ -48,6 +48,8 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $returnType = ParametersAcceptorSelector::selectFromArgs( $scope, $methodCall->getArgs(), diff --git a/src/Extensions/PdoStatementFetchObjectDynamicReturnTypeExtension.php b/src/Extensions/PdoStatementFetchObjectDynamicReturnTypeExtension.php index c95fbdb88..63f8a8742 100644 --- a/src/Extensions/PdoStatementFetchObjectDynamicReturnTypeExtension.php +++ b/src/Extensions/PdoStatementFetchObjectDynamicReturnTypeExtension.php @@ -37,6 +37,8 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): ?Type { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + try { return $this->inferType($methodReflection, $methodCall, $scope); } catch (UnresolvableQueryException $exception) { diff --git a/src/Extensions/PdoStatementSetFetchModeTypeSpecifyingExtension.php b/src/Extensions/PdoStatementSetFetchModeTypeSpecifyingExtension.php index 1b5de86c3..73abf80a3 100644 --- a/src/Extensions/PdoStatementSetFetchModeTypeSpecifyingExtension.php +++ b/src/Extensions/PdoStatementSetFetchModeTypeSpecifyingExtension.php @@ -37,6 +37,8 @@ public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void public function specifyTypes(MethodReflection $methodReflection, MethodCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + // keep original param name because named-parameters $methodCall = $node; $statementType = $scope->getType($methodCall->var); diff --git a/src/Rules/DoctrineKeyValueStyleRule.php b/src/Rules/DoctrineKeyValueStyleRule.php index a8e408c6c..cbd341306 100644 --- a/src/Rules/DoctrineKeyValueStyleRule.php +++ b/src/Rules/DoctrineKeyValueStyleRule.php @@ -23,6 +23,7 @@ use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; use PHPStan\Type\VerbosityLevel; +use staabm\PHPStanDba\Extensions\DbSchemaResultCacheMetaExtension; use staabm\PHPStanDba\QueryReflection\QueryReflection; /** @@ -73,6 +74,8 @@ public function getNodeType(): string */ public function processNode(Node $callLike, Scope $scope): array { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + if ($callLike instanceof MethodCall) { if (! $callLike->name instanceof Node\Identifier) { return []; diff --git a/src/Rules/PdoStatementExecuteMethodRule.php b/src/Rules/PdoStatementExecuteMethodRule.php index ea564b8dc..d1b38c04f 100644 --- a/src/Rules/PdoStatementExecuteMethodRule.php +++ b/src/Rules/PdoStatementExecuteMethodRule.php @@ -16,6 +16,7 @@ use PHPStan\Type\Constant\ConstantIntegerType; use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\ObjectType; +use staabm\PHPStanDba\Extensions\DbSchemaResultCacheMetaExtension; use staabm\PHPStanDba\PdoReflection\PdoStatementReflection; use staabm\PHPStanDba\QueryReflection\PlaceholderValidation; use staabm\PHPStanDba\QueryReflection\QueryReflection; @@ -35,6 +36,8 @@ public function getNodeType(): string public function processNode(Node $methodCall, Scope $scope): array { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + if (! $methodCall->name instanceof Node\Identifier) { return []; } diff --git a/src/Rules/QueryPlanAnalyzerRule.php b/src/Rules/QueryPlanAnalyzerRule.php index 43b6eba3b..fe45524ec 100644 --- a/src/Rules/QueryPlanAnalyzerRule.php +++ b/src/Rules/QueryPlanAnalyzerRule.php @@ -19,6 +19,7 @@ use PHPStan\Rules\RuleErrorBuilder; use PHPStan\ShouldNotHappenException; use PHPStan\Type\ObjectType; +use staabm\PHPStanDba\Extensions\DbSchemaResultCacheMetaExtension; use staabm\PHPStanDba\QueryReflection\QueryReflection; use staabm\PHPStanDba\Tests\QueryPlanAnalyzerRuleTest; use staabm\PHPStanDba\UnresolvableQueryException; @@ -53,6 +54,8 @@ public function getNodeType(): string public function processNode(Node $callLike, Scope $scope): array { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + if ($callLike instanceof MethodCall) { if (! $callLike->name instanceof Node\Identifier) { return []; diff --git a/src/Rules/SyntaxErrorInDibiPreparedStatementMethodRule.php b/src/Rules/SyntaxErrorInDibiPreparedStatementMethodRule.php index f94d2442e..763799a2c 100644 --- a/src/Rules/SyntaxErrorInDibiPreparedStatementMethodRule.php +++ b/src/Rules/SyntaxErrorInDibiPreparedStatementMethodRule.php @@ -18,6 +18,7 @@ use PHPStan\ShouldNotHappenException; use PHPStan\Type\Constant\ConstantArrayType; use PHPStan\Type\ObjectType; +use staabm\PHPStanDba\Extensions\DbSchemaResultCacheMetaExtension; use staabm\PHPStanDba\DibiReflection\DibiReflection; use staabm\PHPStanDba\QueryReflection\DbaApi; use staabm\PHPStanDba\QueryReflection\QueryReflection; @@ -53,6 +54,8 @@ public function getNodeType(): string public function processNode(Node $callLike, Scope $scope): array { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + if ($callLike instanceof MethodCall) { if (! $callLike->name instanceof Node\Identifier) { return []; diff --git a/src/Rules/SyntaxErrorInPreparedStatementMethodRule.php b/src/Rules/SyntaxErrorInPreparedStatementMethodRule.php index 68774e6ed..cb79b2c01 100644 --- a/src/Rules/SyntaxErrorInPreparedStatementMethodRule.php +++ b/src/Rules/SyntaxErrorInPreparedStatementMethodRule.php @@ -20,6 +20,7 @@ use PHPStan\ShouldNotHappenException; use PHPStan\Type\MixedType; use PHPStan\Type\ObjectType; +use staabm\PHPStanDba\Extensions\DbSchemaResultCacheMetaExtension; use staabm\PHPStanDba\QueryReflection\PlaceholderValidation; use staabm\PHPStanDba\QueryReflection\QueryReflection; use staabm\PHPStanDba\UnresolvableQueryException; @@ -54,6 +55,8 @@ public function getNodeType(): string public function processNode(Node $callLike, Scope $scope): array { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + if ($callLike instanceof MethodCall) { if (! $callLike->name instanceof Node\Identifier) { return []; diff --git a/src/Rules/SyntaxErrorInQueryFunctionRule.php b/src/Rules/SyntaxErrorInQueryFunctionRule.php index c20c56c13..a11b59396 100644 --- a/src/Rules/SyntaxErrorInQueryFunctionRule.php +++ b/src/Rules/SyntaxErrorInQueryFunctionRule.php @@ -11,6 +11,7 @@ use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; use PHPStan\ShouldNotHappenException; +use staabm\PHPStanDba\Extensions\DbSchemaResultCacheMetaExtension; use staabm\PHPStanDba\QueryReflection\QueryReflection; use staabm\PHPStanDba\Tests\SyntaxErrorInQueryFunctionRuleTest; use staabm\PHPStanDba\UnresolvableQueryException; @@ -45,6 +46,8 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + if (! $node->name instanceof Node\Name) { return []; } diff --git a/src/Rules/SyntaxErrorInQueryMethodRule.php b/src/Rules/SyntaxErrorInQueryMethodRule.php index 457515f42..745a06d93 100644 --- a/src/Rules/SyntaxErrorInQueryMethodRule.php +++ b/src/Rules/SyntaxErrorInQueryMethodRule.php @@ -15,6 +15,7 @@ use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; use PHPStan\ShouldNotHappenException; +use staabm\PHPStanDba\Extensions\DbSchemaResultCacheMetaExtension; use staabm\PHPStanDba\QueryReflection\QueryReflection; use staabm\PHPStanDba\UnresolvableQueryException; @@ -48,6 +49,8 @@ public function getNodeType(): string public function processNode(Node $callLike, Scope $scope): array { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + if ($callLike instanceof MethodCall) { if (! $callLike->name instanceof Identifier) { return []; From 4edd5d0689ad51d662827773ea5f4d16e6076022 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 10 Oct 2026 08:22:57 +0200 Subject: [PATCH 2/4] Update DbSchemaResultCacheMetaExtension.php --- src/Extensions/DbSchemaResultCacheMetaExtension.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Extensions/DbSchemaResultCacheMetaExtension.php b/src/Extensions/DbSchemaResultCacheMetaExtension.php index f2953dfcc..90b07b30c 100644 --- a/src/Extensions/DbSchemaResultCacheMetaExtension.php +++ b/src/Extensions/DbSchemaResultCacheMetaExtension.php @@ -12,7 +12,7 @@ final class DbSchemaResultCacheMetaExtension implements ResultCacheValueExtension { - public const SCHEMA_KEY = 'schema'; + private const SCHEMA_KEY = 'schema'; /** * Marks the currently analysed file as dependent on the database schema. From f406b5b6415384c30b90c42043960ca7bb82852f Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 10 Oct 2026 08:23:02 +0200 Subject: [PATCH 3/4] Update SyntaxErrorInDibiPreparedStatementMethodRule.php --- src/Rules/SyntaxErrorInDibiPreparedStatementMethodRule.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rules/SyntaxErrorInDibiPreparedStatementMethodRule.php b/src/Rules/SyntaxErrorInDibiPreparedStatementMethodRule.php index 763799a2c..4986c5027 100644 --- a/src/Rules/SyntaxErrorInDibiPreparedStatementMethodRule.php +++ b/src/Rules/SyntaxErrorInDibiPreparedStatementMethodRule.php @@ -18,8 +18,8 @@ use PHPStan\ShouldNotHappenException; use PHPStan\Type\Constant\ConstantArrayType; use PHPStan\Type\ObjectType; -use staabm\PHPStanDba\Extensions\DbSchemaResultCacheMetaExtension; use staabm\PHPStanDba\DibiReflection\DibiReflection; +use staabm\PHPStanDba\Extensions\DbSchemaResultCacheMetaExtension; use staabm\PHPStanDba\QueryReflection\DbaApi; use staabm\PHPStanDba\QueryReflection\QueryReflection; use staabm\PHPStanDba\QueryReflection\QueryReflector; From dc7ec42d80737c4b5f6eda89da7f923f5660ea23 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 10 Oct 2026 08:49:23 +0200 Subject: [PATCH 4/4] track a scope dependency only after all fast-fail initial checks --- .../DeployerRunMysqlQueryDynamicReturnTypeExtension.php | 4 ++-- .../DibiConnectionFetchDynamicReturnTypeExtension.php | 4 ++-- ...neConnectionExecuteQueryDynamicReturnTypeExtension.php | 4 ++-- .../DoctrineConnectionFetchDynamicReturnTypeExtension.php | 4 ++-- ...octrineConnectionPrepareDynamicReturnTypeExtension.php | 4 ++-- .../DoctrineConnectionQueryDynamicReturnTypeExtension.php | 4 ++-- .../DoctrineResultDynamicReturnTypeExtension.php | 4 ++-- ...DoctrineStatementExecuteDynamicReturnTypeExtension.php | 4 ++-- .../MysqliEscapeStringDynamicReturnTypeExtension.php | 8 ++++---- src/Extensions/MysqliQueryDynamicReturnTypeExtension.php | 8 ++++---- src/Extensions/PdoPrepareDynamicReturnTypeExtension.php | 4 ++-- src/Extensions/PdoQueryDynamicReturnTypeExtension.php | 4 ++-- src/Extensions/PdoQuoteDynamicReturnTypeExtension.php | 4 ++-- .../PdoStatementColumnCountDynamicReturnTypeExtension.php | 4 ++-- .../PdoStatementExecuteTypeSpecifyingExtension.php | 4 ++-- .../PdoStatementFetchDynamicReturnTypeExtension.php | 4 ++-- .../PdoStatementSetFetchModeTypeSpecifyingExtension.php | 4 ++-- src/Rules/DoctrineKeyValueStyleRule.php | 4 ++-- src/Rules/PdoStatementExecuteMethodRule.php | 4 ++-- src/Rules/QueryPlanAnalyzerRule.php | 4 ++-- .../SyntaxErrorInDibiPreparedStatementMethodRule.php | 4 ++-- src/Rules/SyntaxErrorInPreparedStatementMethodRule.php | 4 ++-- src/Rules/SyntaxErrorInQueryFunctionRule.php | 4 ++-- src/Rules/SyntaxErrorInQueryMethodRule.php | 4 ++-- 24 files changed, 52 insertions(+), 52 deletions(-) diff --git a/src/Extensions/DeployerRunMysqlQueryDynamicReturnTypeExtension.php b/src/Extensions/DeployerRunMysqlQueryDynamicReturnTypeExtension.php index 123885789..6b81811a8 100644 --- a/src/Extensions/DeployerRunMysqlQueryDynamicReturnTypeExtension.php +++ b/src/Extensions/DeployerRunMysqlQueryDynamicReturnTypeExtension.php @@ -27,8 +27,6 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): ?Type { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - $args = $functionCall->getArgs(); if (\count($args) < 2) { @@ -39,6 +37,8 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return null; } + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $queryReflection = new QueryReflection(); $queryString = $queryReflection->resolveQueryString($args[0]->value, $scope); if (null === $queryString) { diff --git a/src/Extensions/DibiConnectionFetchDynamicReturnTypeExtension.php b/src/Extensions/DibiConnectionFetchDynamicReturnTypeExtension.php index 2dec1a35c..67aa57510 100644 --- a/src/Extensions/DibiConnectionFetchDynamicReturnTypeExtension.php +++ b/src/Extensions/DibiConnectionFetchDynamicReturnTypeExtension.php @@ -41,8 +41,6 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): ?Type { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - $args = $methodCall->getArgs(); if (\count($args) < 1) { @@ -53,6 +51,8 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method return null; } + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + try { return $this->inferType($methodReflection, $args[0]->value, $scope); } catch (UnresolvableQueryException $exception) { diff --git a/src/Extensions/DoctrineConnectionExecuteQueryDynamicReturnTypeExtension.php b/src/Extensions/DoctrineConnectionExecuteQueryDynamicReturnTypeExtension.php index 0a6547bda..12f9105ce 100644 --- a/src/Extensions/DoctrineConnectionExecuteQueryDynamicReturnTypeExtension.php +++ b/src/Extensions/DoctrineConnectionExecuteQueryDynamicReturnTypeExtension.php @@ -33,8 +33,6 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): ?Type { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - $args = $methodCall->getArgs(); if (\count($args) < 1) { @@ -50,6 +48,8 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method return null; } + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $params = null; if (\count($args) > 1) { $params = $args[1]->value; diff --git a/src/Extensions/DoctrineConnectionFetchDynamicReturnTypeExtension.php b/src/Extensions/DoctrineConnectionFetchDynamicReturnTypeExtension.php index 66be76042..771a08f75 100644 --- a/src/Extensions/DoctrineConnectionFetchDynamicReturnTypeExtension.php +++ b/src/Extensions/DoctrineConnectionFetchDynamicReturnTypeExtension.php @@ -46,8 +46,6 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): ?Type { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - $args = $methodCall->getArgs(); if (\count($args) < 1) { @@ -63,6 +61,8 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method return null; } + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $params = null; if (\count($args) > 1) { $params = $args[1]->value; diff --git a/src/Extensions/DoctrineConnectionPrepareDynamicReturnTypeExtension.php b/src/Extensions/DoctrineConnectionPrepareDynamicReturnTypeExtension.php index 9657fa9ce..f865190c1 100644 --- a/src/Extensions/DoctrineConnectionPrepareDynamicReturnTypeExtension.php +++ b/src/Extensions/DoctrineConnectionPrepareDynamicReturnTypeExtension.php @@ -33,8 +33,6 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): ?Type { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - $args = $methodCall->getArgs(); if (\count($args) < 1) { @@ -50,6 +48,8 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method return null; } + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + try { return $this->inferType($args[0]->value, $scope); } catch (UnresolvableQueryException $exception) { diff --git a/src/Extensions/DoctrineConnectionQueryDynamicReturnTypeExtension.php b/src/Extensions/DoctrineConnectionQueryDynamicReturnTypeExtension.php index ca9508c28..c8be5b100 100644 --- a/src/Extensions/DoctrineConnectionQueryDynamicReturnTypeExtension.php +++ b/src/Extensions/DoctrineConnectionQueryDynamicReturnTypeExtension.php @@ -33,8 +33,6 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): ?Type { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - $args = $methodCall->getArgs(); if (\count($args) < 1) { @@ -50,6 +48,8 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method return null; } + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + try { return $this->inferType($args[0]->value, $scope); } catch (UnresolvableQueryException $exception) { diff --git a/src/Extensions/DoctrineResultDynamicReturnTypeExtension.php b/src/Extensions/DoctrineResultDynamicReturnTypeExtension.php index 0c36444e9..1570e9ea9 100644 --- a/src/Extensions/DoctrineResultDynamicReturnTypeExtension.php +++ b/src/Extensions/DoctrineResultDynamicReturnTypeExtension.php @@ -47,13 +47,13 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): ?Type { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - // make sure we don't report wrong types in doctrine 2.x if (! InstalledVersions::satisfies(new VersionParser(), 'doctrine/dbal', '3.*|4.*')) { return null; } + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + try { return $this->inferType($methodReflection, $methodCall, $scope); } catch (UnresolvableQueryException $exception) { diff --git a/src/Extensions/DoctrineStatementExecuteDynamicReturnTypeExtension.php b/src/Extensions/DoctrineStatementExecuteDynamicReturnTypeExtension.php index b64d11712..7b02cfd69 100644 --- a/src/Extensions/DoctrineStatementExecuteDynamicReturnTypeExtension.php +++ b/src/Extensions/DoctrineStatementExecuteDynamicReturnTypeExtension.php @@ -33,8 +33,6 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): ?Type { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - $args = $methodCall->getArgs(); if (\count($args) < 1) { @@ -46,6 +44,8 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method return null; } + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + try { return $this->inferType($methodReflection, $methodCall, $args[0]->value, $scope); } catch (UnresolvableQueryException $exception) { diff --git a/src/Extensions/MysqliEscapeStringDynamicReturnTypeExtension.php b/src/Extensions/MysqliEscapeStringDynamicReturnTypeExtension.php index 2db5e15ec..9055b2406 100644 --- a/src/Extensions/MysqliEscapeStringDynamicReturnTypeExtension.php +++ b/src/Extensions/MysqliEscapeStringDynamicReturnTypeExtension.php @@ -49,8 +49,6 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): Type { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - $args = $functionCall->getArgs(); $defaultReturn = ParametersAcceptorSelector::selectFromArgs( $scope, @@ -66,6 +64,8 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return $defaultReturn; } + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $argType = $scope->getType($args[1]->value); return $this->inferType($argType); @@ -73,8 +73,6 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - $args = $methodCall->getArgs(); $defaultReturn = ParametersAcceptorSelector::selectFromArgs( $scope, @@ -90,6 +88,8 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method return $defaultReturn; } + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $argType = $scope->getType($args[0]->value); return $this->inferType($argType); diff --git a/src/Extensions/MysqliQueryDynamicReturnTypeExtension.php b/src/Extensions/MysqliQueryDynamicReturnTypeExtension.php index 441397db0..21b315316 100644 --- a/src/Extensions/MysqliQueryDynamicReturnTypeExtension.php +++ b/src/Extensions/MysqliQueryDynamicReturnTypeExtension.php @@ -50,8 +50,6 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): Type { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - $args = $functionCall->getArgs(); $defaultReturn = ParametersAcceptorSelector::selectFromArgs( $scope, @@ -67,6 +65,8 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return $defaultReturn; } + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + try { $resultType = $this->inferResultType($args[1]->value, $scope); if (null !== $resultType) { @@ -81,8 +81,6 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - $args = $methodCall->getArgs(); $defaultReturn = ParametersAcceptorSelector::selectFromArgs( $scope, @@ -102,6 +100,8 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method return $defaultReturn; } + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + try { $resultType = $this->inferResultType($args[0]->value, $scope); if (null !== $resultType) { diff --git a/src/Extensions/PdoPrepareDynamicReturnTypeExtension.php b/src/Extensions/PdoPrepareDynamicReturnTypeExtension.php index 0e7eff9c6..75527f678 100644 --- a/src/Extensions/PdoPrepareDynamicReturnTypeExtension.php +++ b/src/Extensions/PdoPrepareDynamicReturnTypeExtension.php @@ -41,8 +41,6 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - $args = $methodCall->getArgs(); $defaultReturn = ParametersAcceptorSelector::selectFromArgs( $scope, @@ -62,6 +60,8 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method return $defaultReturn; } + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + try { $resultType = $this->inferType($args[0]->value, $scope); if (null !== $resultType) { diff --git a/src/Extensions/PdoQueryDynamicReturnTypeExtension.php b/src/Extensions/PdoQueryDynamicReturnTypeExtension.php index 3aba0b1f7..a2a167418 100644 --- a/src/Extensions/PdoQueryDynamicReturnTypeExtension.php +++ b/src/Extensions/PdoQueryDynamicReturnTypeExtension.php @@ -43,8 +43,6 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - $args = $methodCall->getArgs(); $defaultReturn = ParametersAcceptorSelector::selectFromArgs( $scope, @@ -64,6 +62,8 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method return $defaultReturn; } + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + try { $resultType = $this->inferType($methodCall, $args[0]->value, $scope); if (null !== $resultType) { diff --git a/src/Extensions/PdoQuoteDynamicReturnTypeExtension.php b/src/Extensions/PdoQuoteDynamicReturnTypeExtension.php index 92ab6c459..0e0f75db2 100644 --- a/src/Extensions/PdoQuoteDynamicReturnTypeExtension.php +++ b/src/Extensions/PdoQuoteDynamicReturnTypeExtension.php @@ -43,8 +43,6 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - $args = $methodCall->getArgs(); $defaultReturn = ParametersAcceptorSelector::selectFromArgs( $scope, @@ -60,6 +58,8 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method return $defaultReturn; } + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + try { $stringType = $this->inferType($methodCall, $scope); if (null !== $stringType) { diff --git a/src/Extensions/PdoStatementColumnCountDynamicReturnTypeExtension.php b/src/Extensions/PdoStatementColumnCountDynamicReturnTypeExtension.php index 476fa9cd4..53df161bb 100644 --- a/src/Extensions/PdoStatementColumnCountDynamicReturnTypeExtension.php +++ b/src/Extensions/PdoStatementColumnCountDynamicReturnTypeExtension.php @@ -28,11 +28,11 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): ?Type { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - $statementType = $scope->getType($methodCall->var); if ($statementType instanceof PdoStatementObjectType) { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $arrays = $statementType->newWithFetchType(QueryReflector::FETCH_TYPE_NUMERIC)->getRowType()->getConstantArrays(); if (count($arrays) === 1) { $rowType = $arrays[0]; diff --git a/src/Extensions/PdoStatementExecuteTypeSpecifyingExtension.php b/src/Extensions/PdoStatementExecuteTypeSpecifyingExtension.php index e94d0b945..528cf5500 100644 --- a/src/Extensions/PdoStatementExecuteTypeSpecifyingExtension.php +++ b/src/Extensions/PdoStatementExecuteTypeSpecifyingExtension.php @@ -42,11 +42,11 @@ public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void public function specifyTypes(MethodReflection $methodReflection, MethodCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - // keep original param name because named-parameters $methodCall = $node; + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + try { $inferredType = $this->inferStatementType($methodReflection, $methodCall, $scope); } catch (UnresolvableQueryException $e) { diff --git a/src/Extensions/PdoStatementFetchDynamicReturnTypeExtension.php b/src/Extensions/PdoStatementFetchDynamicReturnTypeExtension.php index bcf89210c..d9fcd2c0f 100644 --- a/src/Extensions/PdoStatementFetchDynamicReturnTypeExtension.php +++ b/src/Extensions/PdoStatementFetchDynamicReturnTypeExtension.php @@ -48,14 +48,14 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - $returnType = ParametersAcceptorSelector::selectFromArgs( $scope, $methodCall->getArgs(), $methodReflection->getVariants() )->getReturnType(); + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + try { $resultType = $this->inferType($methodReflection, $methodCall, $scope); if (null !== $resultType) { diff --git a/src/Extensions/PdoStatementSetFetchModeTypeSpecifyingExtension.php b/src/Extensions/PdoStatementSetFetchModeTypeSpecifyingExtension.php index 73abf80a3..507656110 100644 --- a/src/Extensions/PdoStatementSetFetchModeTypeSpecifyingExtension.php +++ b/src/Extensions/PdoStatementSetFetchModeTypeSpecifyingExtension.php @@ -37,13 +37,13 @@ public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void public function specifyTypes(MethodReflection $methodReflection, MethodCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - // keep original param name because named-parameters $methodCall = $node; $statementType = $scope->getType($methodCall->var); if ($statementType instanceof PdoStatementObjectType) { + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $reducedType = $this->reduceType($methodCall, $statementType, $scope); if (null !== $reducedType) { diff --git a/src/Rules/DoctrineKeyValueStyleRule.php b/src/Rules/DoctrineKeyValueStyleRule.php index cbd341306..2a370f02d 100644 --- a/src/Rules/DoctrineKeyValueStyleRule.php +++ b/src/Rules/DoctrineKeyValueStyleRule.php @@ -74,8 +74,6 @@ public function getNodeType(): string */ public function processNode(Node $callLike, Scope $scope): array { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - if ($callLike instanceof MethodCall) { if (! $callLike->name instanceof Node\Identifier) { return []; @@ -114,6 +112,8 @@ public function processNode(Node $callLike, Scope $scope): array return []; } + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + // Reorder arguments to account for named parameters $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs( $scope, diff --git a/src/Rules/PdoStatementExecuteMethodRule.php b/src/Rules/PdoStatementExecuteMethodRule.php index d1b38c04f..a991fee38 100644 --- a/src/Rules/PdoStatementExecuteMethodRule.php +++ b/src/Rules/PdoStatementExecuteMethodRule.php @@ -36,8 +36,6 @@ public function getNodeType(): string public function processNode(Node $methodCall, Scope $scope): array { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - if (! $methodCall->name instanceof Node\Identifier) { return []; } @@ -75,6 +73,8 @@ private function checkErrors(MethodReflection $methodReflection, MethodCall $met return []; } + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $args = $methodCall->getArgs(); if (\count($args) < 1) { $parameterKeys = []; diff --git a/src/Rules/QueryPlanAnalyzerRule.php b/src/Rules/QueryPlanAnalyzerRule.php index fe45524ec..2668a61b1 100644 --- a/src/Rules/QueryPlanAnalyzerRule.php +++ b/src/Rules/QueryPlanAnalyzerRule.php @@ -54,8 +54,6 @@ public function getNodeType(): string public function processNode(Node $callLike, Scope $scope): array { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - if ($callLike instanceof MethodCall) { if (! $callLike->name instanceof Node\Identifier) { return []; @@ -110,6 +108,8 @@ public function processNode(Node $callLike, Scope $scope): array return []; } + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + try { return $this->analyze($callLike, $scope); } catch (UnresolvableQueryException $exception) { diff --git a/src/Rules/SyntaxErrorInDibiPreparedStatementMethodRule.php b/src/Rules/SyntaxErrorInDibiPreparedStatementMethodRule.php index 4986c5027..39216006c 100644 --- a/src/Rules/SyntaxErrorInDibiPreparedStatementMethodRule.php +++ b/src/Rules/SyntaxErrorInDibiPreparedStatementMethodRule.php @@ -54,8 +54,6 @@ public function getNodeType(): string public function processNode(Node $callLike, Scope $scope): array { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - if ($callLike instanceof MethodCall) { if (! $callLike->name instanceof Node\Identifier) { return []; @@ -113,6 +111,8 @@ private function checkErrors(CallLike $callLike, Scope $scope, MethodReflection return []; } + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $queryReflection = new QueryReflection(new DbaApi(DbaApi::API_DIBI)); $queryParameters = []; $errors = []; diff --git a/src/Rules/SyntaxErrorInPreparedStatementMethodRule.php b/src/Rules/SyntaxErrorInPreparedStatementMethodRule.php index cb79b2c01..d0bdd74e4 100644 --- a/src/Rules/SyntaxErrorInPreparedStatementMethodRule.php +++ b/src/Rules/SyntaxErrorInPreparedStatementMethodRule.php @@ -55,8 +55,6 @@ public function getNodeType(): string public function processNode(Node $callLike, Scope $scope): array { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - if ($callLike instanceof MethodCall) { if (! $callLike->name instanceof Node\Identifier) { return []; @@ -123,6 +121,8 @@ private function checkErrors(CallLike $callLike, Scope $scope): array return []; } + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $queryExpr = $args[0]->value; $queryReflection = new QueryReflection(); diff --git a/src/Rules/SyntaxErrorInQueryFunctionRule.php b/src/Rules/SyntaxErrorInQueryFunctionRule.php index a11b59396..9d6e141ef 100644 --- a/src/Rules/SyntaxErrorInQueryFunctionRule.php +++ b/src/Rules/SyntaxErrorInQueryFunctionRule.php @@ -46,8 +46,6 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - if (! $node->name instanceof Node\Name) { return []; } @@ -84,6 +82,8 @@ public function processNode(Node $node, Scope $scope): array return []; } + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $queryExpr = $args[$queryArgPosition]->value; $queryReflection = new QueryReflection(); diff --git a/src/Rules/SyntaxErrorInQueryMethodRule.php b/src/Rules/SyntaxErrorInQueryMethodRule.php index 745a06d93..7e9735653 100644 --- a/src/Rules/SyntaxErrorInQueryMethodRule.php +++ b/src/Rules/SyntaxErrorInQueryMethodRule.php @@ -49,8 +49,6 @@ public function getNodeType(): string public function processNode(Node $callLike, Scope $scope): array { - DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); - if ($callLike instanceof MethodCall) { if (! $callLike->name instanceof Identifier) { return []; @@ -105,6 +103,8 @@ public function processNode(Node $callLike, Scope $scope): array return []; } + DbSchemaResultCacheMetaExtension::trackSchemaDependency($scope); + $queryExpr = $args[$queryArgPosition]->value; $queryReflection = new QueryReflection();