Skip to content

Commit 6bc277e

Browse files
staabmclxmstaab
andauthored
support prepared statement analysis of construct()-methods in SyntaxErrorInPreparedStatementMethodRule (#88)
Co-authored-by: Markus Staab <[email protected]>
1 parent 912177f commit 6bc277e

File tree

6 files changed

+49
-10
lines changed

6 files changed

+49
-10
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ services:
112112
arguments:
113113
classMethods:
114114
- 'My\Connection::preparedQuery'
115+
- 'My\PreparedStatement::__construct'
115116
```
116117

117118
__the callable format is `class::method`. phpstan-dba assumes the method takes a query-string as a 1st and the parameter-values as a 2nd argument.__

src/Rules/SyntaxErrorInPreparedStatementMethodRule.php

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,21 @@
55
namespace staabm\PHPStanDba\Rules;
66

77
use PhpParser\Node;
8+
use PhpParser\Node\Expr\CallLike;
89
use PhpParser\Node\Expr\MethodCall;
10+
use PhpParser\Node\Expr\New_;
11+
use PhpParser\Node\Name;
12+
use PhpParser\Node\Name\FullyQualified;
913
use PHPStan\Analyser\Scope;
1014
use PHPStan\Rules\Rule;
1115
use PHPStan\Rules\RuleError;
1216
use PHPStan\Rules\RuleErrorBuilder;
17+
use PHPStan\Type\ObjectType;
18+
use Prophecy\Call\Call;
1319
use staabm\PHPStanDba\QueryReflection\QueryReflection;
1420

1521
/**
16-
* @implements Rule<MethodCall>
22+
* @implements Rule<CallLike>
1723
*
1824
* @see SyntaxErrorInPreparedStatementMethodRuleTest
1925
*/
@@ -34,16 +40,26 @@ public function __construct(array $classMethods)
3440

3541
public function getNodeType(): string
3642
{
37-
return MethodCall::class;
43+
return CallLike::class;
3844
}
3945

40-
public function processNode(Node $methodCall, Scope $scope): array
46+
public function processNode(Node $callLike, Scope $scope): array
4147
{
42-
if (!$methodCall->name instanceof Node\Identifier) {
48+
if ($callLike instanceof MethodCall) {
49+
if (!$callLike->name instanceof Node\Identifier) {
50+
return [];
51+
}
52+
53+
$methodReflection = $scope->getMethodReflection($scope->getType($callLike->var), $callLike->name->toString());
54+
} elseif ($callLike instanceof New_) {
55+
if (!$callLike->class instanceof FullyQualified) {
56+
return [];
57+
}
58+
$methodReflection = $scope->getMethodReflection(new ObjectType($callLike->class->toCodeString()), '__construct');
59+
} else {
4360
return [];
4461
}
4562

46-
$methodReflection = $scope->getMethodReflection($scope->getType($methodCall->var), $methodCall->name->toString());
4763
if (null === $methodReflection) {
4864
return [];
4965
}
@@ -62,15 +78,16 @@ public function processNode(Node $methodCall, Scope $scope): array
6278
return [];
6379
}
6480

65-
return $this->checkErrors($methodCall, $scope);
81+
return $this->checkErrors($callLike, $scope);
6682
}
6783

6884
/**
85+
* @param MethodCall|New_ $callLike
6986
* @return RuleError[]
7087
*/
71-
private function checkErrors(MethodCall $methodCall, Scope $scope): array
88+
private function checkErrors(CallLike $callLike, Scope $scope): array
7289
{
73-
$args = $methodCall->getArgs();
90+
$args = $callLike->getArgs();
7491

7592
if (\count($args) < 2) {
7693
return [];
@@ -88,7 +105,7 @@ private function checkErrors(MethodCall $methodCall, Scope $scope): array
88105
$error = $queryReflection->validateQueryString($queryString);
89106
if (null !== $error) {
90107
return [
91-
RuleErrorBuilder::message('Query error: '.$error->getMessage().' ('.$error->getCode().').')->line($methodCall->getLine())->build(),
108+
RuleErrorBuilder::message('Query error: '.$error->getMessage().' ('.$error->getCode().').')->line($callLike->getLine())->build(),
92109
];
93110
}
94111

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace staabm\PHPStanDba\Tests\Fixture;
4+
5+
class PreparedStatement
6+
{
7+
public function __construct(string $queryString, array $params)
8+
{
9+
}
10+
}

tests/SyntaxErrorInPreparedStatementMethodRuleTest.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ public function testSyntaxErrorInQueryRule(): void
2323
$this->analyse([__DIR__.'/data/syntax-error-in-prepared-statement.php'], [
2424
[
2525
"Query error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL/MariaDB server version for the right syntax to use near 'freigabe1u1 FROM ada LIMIT 0' at line 1 (1064).",
26-
11,
26+
12,
27+
],
28+
[
29+
"Query error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL/MariaDB server version for the right syntax to use near 'freigabe1u1 FROM ada LIMIT 0' at line 1 (1064).",
30+
17,
2731
],
2832
]);
2933
}

tests/config/syntax-error-in-prepared-statement.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ services:
99
arguments:
1010
classMethods:
1111
- 'staabm\PHPStanDba\Tests\Fixture\Connection::preparedQuery'
12+
- 'staabm\PHPStanDba\Tests\Fixture\PreparedStatement::__construct'

tests/data/syntax-error-in-prepared-statement.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace SyntaxErrorInPreparedStatementMethodRuleTest;
44

55
use staabm\PHPStanDba\Tests\Fixture\Connection;
6+
use staabm\PHPStanDba\Tests\Fixture\PreparedStatement;
67

78
class Foo
89
{
@@ -11,6 +12,11 @@ public function syntaxError(Connection $connection)
1112
$connection->preparedQuery('SELECT email adaid WHERE gesperrt freigabe1u1 FROM ada', []);
1213
}
1314

15+
public function syntaxErrorInConstruct()
16+
{
17+
$stmt = new PreparedStatement('SELECT email adaid WHERE gesperrt freigabe1u1 FROM ada', []);
18+
}
19+
1420
public function preparedParams(Connection $connection)
1521
{
1622
$connection->preparedQuery('SELECT email, adaid FROM ada WHERE gesperrt = ?', [1]);

0 commit comments

Comments
 (0)