Skip to content

Commit 23de646

Browse files
committed
Merge branch 'QA_5_2'
Signed-off-by: Maurício Meneghini Fauth <mauricio@fauth.dev>
2 parents a5ccad4 + 7baf4f8 commit 23de646

7 files changed

Lines changed: 355 additions & 220 deletions

File tree

phpstan-baseline.neon

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2652,16 +2652,11 @@ parameters:
26522652

26532653
-
26542654
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
2655-
count: 2
2656-
path: src/Controllers/Import/SimulateDmlController.php
2657-
2658-
-
2659-
message: "#^Parameter \\#1 \\$separator of function explode expects non\\-empty\\-string, string given\\.$#"
26602655
count: 1
26612656
path: src/Controllers/Import/SimulateDmlController.php
26622657

26632658
-
2664-
message: "#^Parameter \\#2 \\$string of function explode expects string, mixed given\\.$#"
2659+
message: "#^Parameter \\#1 \\$query of method PhpMyAdmin\\\\Controllers\\\\Import\\\\SimulateDmlController\\:\\:createParser\\(\\) expects string, mixed given\\.$#"
26652660
count: 1
26662661
path: src/Controllers/Import/SimulateDmlController.php
26672662

psalm-baseline.xml

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1966,12 +1966,6 @@
19661966
</UnusedProperty>
19671967
</file>
19681968
<file src="src/Controllers/Import/SimulateDmlController.php">
1969-
<ArgumentTypeCoercion>
1970-
<code><![CDATA[$sqlDelimiter]]></code>
1971-
</ArgumentTypeCoercion>
1972-
<PossiblyUnusedMethod>
1973-
<code><![CDATA[__construct]]></code>
1974-
</PossiblyUnusedMethod>
19751969
<RiskyTruthyFalsyComparison>
19761970
<code><![CDATA[empty($statement->join)]]></code>
19771971
</RiskyTruthyFalsyComparison>
@@ -12745,6 +12739,11 @@
1274512739
<code><![CDATA[Config::getInstance()]]></code>
1274612740
</DeprecatedMethod>
1274712741
</file>
12742+
<file src="tests/unit/Controllers/Import/SimulateDmlControllerTest.php">
12743+
<PossiblyUnusedMethod>
12744+
<code><![CDATA[providerForTestGetMatchedRows]]></code>
12745+
</PossiblyUnusedMethod>
12746+
</file>
1274812747
<file src="tests/unit/Controllers/Navigation/UpdateNavWidthConfigControllerTest.php">
1274912748
<PossiblyUnusedMethod>
1275012749
<code><![CDATA[invalidParamsProvider]]></code>
@@ -13853,11 +13852,6 @@
1385313852
<code><![CDATA[assertNull]]></code>
1385413853
</TypeDoesNotContainNull>
1385513854
</file>
13856-
<file src="tests/unit/Import/SimulateDmlTest.php">
13857-
<PossiblyUnusedMethod>
13858-
<code><![CDATA[providerForTestGetMatchedRows]]></code>
13859-
</PossiblyUnusedMethod>
13860-
</file>
1386113855
<file src="tests/unit/IndexTest.php">
1386213856
<MixedArgument>
1386313857
<code><![CDATA[$this->params['columns']]]></code>

src/Controllers/Import/SimulateDmlController.php

Lines changed: 51 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -10,78 +10,90 @@
1010
use PhpMyAdmin\Import\SimulateDml;
1111
use PhpMyAdmin\Message;
1212
use PhpMyAdmin\ResponseRenderer;
13+
use PhpMyAdmin\SqlParser\Lexer;
1314
use PhpMyAdmin\SqlParser\Parser;
1415
use PhpMyAdmin\SqlParser\Statements\DeleteStatement;
1516
use PhpMyAdmin\SqlParser\Statements\UpdateStatement;
17+
use PhpMyAdmin\SqlParser\TokensList;
18+
use PhpMyAdmin\SqlParser\TokenType;
1619
use PhpMyAdmin\SqlParser\Utils\Query;
1720

1821
use function __;
22+
use function array_filter;
23+
use function array_values;
1924
use function count;
20-
use function explode;
2125

2226
final class SimulateDmlController implements InvocableController
2327
{
28+
private string $error = '';
29+
30+
/**
31+
* @psalm-var list<array{
32+
* sql_query: string,
33+
* matched_rows: int,
34+
* matched_rows_url: string,
35+
* }>
36+
*/
37+
private array $data = [];
38+
2439
public function __construct(private readonly ResponseRenderer $response, private readonly SimulateDml $simulateDml)
2540
{
2641
}
2742

2843
public function __invoke(ServerRequest $request): Response
2944
{
30-
$error = '';
31-
$errorMsg = __('Only single-table UPDATE and DELETE queries can be simulated.');
3245
/** @var string $sqlDelimiter */
3346
$sqlDelimiter = $request->getParsedBodyParam('sql_delimiter', '');
34-
$sqlData = [];
35-
$queries = explode($sqlDelimiter, $GLOBALS['sql_query']);
36-
foreach ($queries as $sqlQuery) {
37-
if ($sqlQuery === '') {
38-
continue;
39-
}
4047

41-
// Parsing the query.
42-
$parser = new Parser($sqlQuery);
48+
$parser = $this->createParser($GLOBALS['sql_query'], $sqlDelimiter);
49+
$this->process($parser);
4350

44-
if (empty($parser->statements[0])) {
45-
continue;
46-
}
51+
if ($this->error !== '') {
52+
$this->response->addJSON('message', Message::rawError($this->error));
53+
$this->response->addJSON('sql_data', false);
4754

48-
$statement = $parser->statements[0];
55+
return $this->response->response();
56+
}
57+
58+
$this->response->addJSON('sql_data', $this->data);
59+
60+
return $this->response->response();
61+
}
62+
63+
private function createParser(string $query, string $delimiter): Parser
64+
{
65+
$lexer = new Lexer($query, false, $delimiter);
66+
$list = new TokensList(array_values(array_filter(
67+
$lexer->list->tokens,
68+
static function ($token): bool {
69+
return $token->type !== TokenType::Comment;
70+
},
71+
)));
72+
73+
return new Parser($list);
74+
}
4975

76+
private function process(Parser $parser): void
77+
{
78+
foreach ($parser->statements as $statement) {
5079
if (
51-
! ($statement instanceof UpdateStatement || $statement instanceof DeleteStatement)
80+
! $statement instanceof UpdateStatement && ! $statement instanceof DeleteStatement
5281
|| ! empty($statement->join)
82+
|| count(Query::getTables($statement)) > 1
5383
) {
54-
$error = $errorMsg;
55-
break;
56-
}
57-
58-
$tables = Query::getTables($statement);
59-
if (count($tables) > 1) {
60-
$error = $errorMsg;
84+
$this->error = __('Only single-table UPDATE and DELETE queries can be simulated.');
6185
break;
6286
}
6387

6488
// Get the matched rows for the query.
65-
$result = $this->simulateDml->getMatchedRows($sqlQuery, $parser, $statement);
66-
$error = $this->simulateDml->getError();
89+
$result = $this->simulateDml->getMatchedRows($parser, $statement);
90+
$this->error = $this->simulateDml->getError();
6791

68-
if ($error !== '') {
92+
if ($this->error !== '') {
6993
break;
7094
}
7195

72-
$sqlData[] = $result;
96+
$this->data[] = $result;
7397
}
74-
75-
if ($error !== '') {
76-
$message = Message::rawError($error);
77-
$this->response->addJSON('message', $message);
78-
$this->response->addJSON('sql_data', false);
79-
80-
return $this->response->response();
81-
}
82-
83-
$this->response->addJSON('sql_data', $sqlData);
84-
85-
return $this->response->response();
8698
}
8799
}

src/Import/SimulateDml.php

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,8 @@ public function getError(): string
4141
* matched_rows_url: string
4242
* }
4343
*/
44-
public function getMatchedRows(
45-
string $query,
46-
Parser $parser,
47-
DeleteStatement|UpdateStatement $statement,
48-
): array {
44+
public function getMatchedRows(Parser $parser, DeleteStatement|UpdateStatement $statement): array
45+
{
4946
if ($statement instanceof DeleteStatement) {
5047
$matchedRowsQuery = $this->getSimulatedDeleteQuery($parser, $statement);
5148
} else {
@@ -61,7 +58,7 @@ public function getMatchedRows(
6158
]);
6259

6360
return [
64-
'sql_query' => Html\Generator::formatSql($query),
61+
'sql_query' => Html\Generator::formatSql($statement->build()),
6562
'matched_rows' => $matchedRows,
6663
'matched_rows_url' => $matchedRowsUrl,
6764
];

tests/unit/AbstractTestCase.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,4 +185,20 @@ protected function setProperty(object|null $object, string $className, string $p
185185

186186
$property->setValue($object, $value);
187187
}
188+
189+
/**
190+
* Get a private or protected property via reflection.
191+
*
192+
* @param object $object The object to inspect, pass null for static objects()
193+
* @param string $className The class name
194+
* @param string $propertyName The method name
195+
* @phpstan-param class-string $className
196+
*/
197+
protected function getProperty(object $object, string $className, string $propertyName): mixed
198+
{
199+
$class = new ReflectionClass($className);
200+
$property = $class->getProperty($propertyName);
201+
202+
return $property->getValue($object);
203+
}
188204
}

0 commit comments

Comments
 (0)