From 7392f57556a829ca539c6d6f860913da6f17471b Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Mon, 17 Nov 2025 11:40:17 +0100 Subject: [PATCH 1/3] feat: Replace fetch with fetchAssociative Signed-off-by: Carl Schwan --- .../nextcloud-33-deprecations.php | 12 ++ .../ReplaceFetchAllMethodCallRector.php | 166 ++++++++++++++++++ src/Set/NextcloudSets.php | 3 + 3 files changed, 181 insertions(+) create mode 100644 config/nextcloud-33/nextcloud-33-deprecations.php create mode 100644 src/Rector/ReplaceFetchAllMethodCallRector.php diff --git a/config/nextcloud-33/nextcloud-33-deprecations.php b/config/nextcloud-33/nextcloud-33-deprecations.php new file mode 100644 index 0000000..2a13d54 --- /dev/null +++ b/config/nextcloud-33/nextcloud-33-deprecations.php @@ -0,0 +1,12 @@ +sets([NextcloudSets::NEXTCLOUD_27]); + $rectorConfig->rule(ReplaceFetchAllMethodCallRector::class); +}; diff --git a/src/Rector/ReplaceFetchAllMethodCallRector.php b/src/Rector/ReplaceFetchAllMethodCallRector.php new file mode 100644 index 0000000..deeba62 --- /dev/null +++ b/src/Rector/ReplaceFetchAllMethodCallRector.php @@ -0,0 +1,166 @@ +fetchAll() to ->fetchAllAssociative() and other replacements', + [ + new CodeSample( + <<<'CODE_SAMPLE' +use OCP\DB\IResult; +use OCP\DB\IConnection; +use OCP\DB\IQueryBuilder; + +class SomeClass +{ + public function run(IConnection $connection) + { + $qb = $connection->getQueryBuilder(); + $result = $qb->exec(); + return $result->fetchAll(); + } +} +CODE_SAMPLE, + <<<'CODE_SAMPLE' +use OCP\DB\IResult; +use OCP\DB\IConnection; +use OCP\DB\IQueryBuilder; + +class SomeClass +{ + public function run(IConnection $connection) + { + $qb = $connection->getQueryBuilder(); + $result = $qb->exec(); + return $result->fetchAllAssociative(); + } +} +CODE_SAMPLE, + ), + ], + ); + } + + /** + * @return array> + */ + public function getNodeTypes(): array + { + return [MethodCall::class]; + } + + public function refactor(Node $node): ?Node + { + if (!($node instanceof MethodCall)) { + return null; + } + if ($this->isObjectType($node->var, new ObjectType('OCP\DB\IResult'))) { + return $this->refactorResultStatement($node); + } + + return null; + } + + private function refactorResultStatement(MethodCall $methodCall): ?MethodCall + { + if ($this->isName($methodCall->name, 'fetchColumn')) { + $methodCall->name = new Identifier('fetchOne'); + + return $methodCall; + } + + if ($this->isName($methodCall->name, 'fetch')) { + $args = $methodCall->getArgs(); + if ($args === []) { + $methodCall->name = new Identifier('fetchAssociative'); + + return $methodCall; + } + + $firstArg = $args[0]; + + $newMethodName = $this->resolveFirstMethodName($firstArg, false); + if (is_string($newMethodName)) { + $methodCall->args = []; + + $methodCall->name = new Identifier($newMethodName); + + return $methodCall; + } + + return null; + } + + if ($this->isName($methodCall->name, 'fetchAll')) { + $args = $methodCall->getArgs(); + if ($args === []) { + $methodCall->name = new Identifier('fetchAllAssociative'); + + return $methodCall; + } + + $firstArg = $args[0]; + + $newMethodName = $this->resolveFirstMethodName($firstArg, true); + if (is_string($newMethodName)) { + $methodCall->args = []; + + $methodCall->name = new Identifier($newMethodName); + + return $methodCall; + } + } + + return null; + } + + private function resolveFirstMethodName(Arg $firstArg, bool $all = false): ?string + { + if (!$firstArg->value instanceof ClassConstFetch) { + return null; + } + + $classConstFetch = $firstArg->value; + if (!$this->isName($classConstFetch->class, 'PDO')) { + return null; + } + + if ($this->isName($classConstFetch->name, 'FETCH_COLUMN')) { + return $all ? 'fetchFirstColumn' : 'fetchOne'; + } + + if ($this->isName($classConstFetch->name, 'FETCH_ASSOC')) { + return $all ? 'fetchAllAssociative' : 'fetchAssociative'; + } + + if ($this->isName($classConstFetch->name, 'FETCH_NUM')) { + return $all ? 'fetchAllNumeric' : 'fetchNumeric'; + } + + return null; + } +} diff --git a/src/Set/NextcloudSets.php b/src/Set/NextcloudSets.php index 38089f2..35468c6 100644 --- a/src/Set/NextcloudSets.php +++ b/src/Set/NextcloudSets.php @@ -12,4 +12,7 @@ final class NextcloudSets public const NEXTCLOUD_28 = self::NEXTCLOUD_27; public const NEXTCLOUD_29 = self::NEXTCLOUD_27; public const NEXTCLOUD_30 = self::NEXTCLOUD_27; + public const NEXTCLOUD_31 = self::NEXTCLOUD_27; + public const NEXTCLOUD_32 = self::NEXTCLOUD_27; + public const NEXTCLOUD_33 = __DIR__ . '/../../config/nextcloud-33/nextcloud-33-deprecations.php'; } From 7923a3457105199b56503642448ff5e5ad94eca6 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Tue, 18 Nov 2025 13:10:02 +0100 Subject: [PATCH 2/3] chore(replace-fetch-all-method-rector): Add unit test Signed-off-by: Carl Schwan --- .../Fixture/test_fixture_fetch.php.inc | 67 +++++++++++++++++++ .../ReplaceFetchAllMethodCallRectorTest.php | 33 +++++++++ .../config/config.php | 16 +++++ 3 files changed, 116 insertions(+) create mode 100644 tests/Rector/ReplaceFetchAllMethodCallRector/Fixture/test_fixture_fetch.php.inc create mode 100644 tests/Rector/ReplaceFetchAllMethodCallRector/ReplaceFetchAllMethodCallRectorTest.php create mode 100644 tests/Rector/ReplaceFetchAllMethodCallRector/config/config.php diff --git a/tests/Rector/ReplaceFetchAllMethodCallRector/Fixture/test_fixture_fetch.php.inc b/tests/Rector/ReplaceFetchAllMethodCallRector/Fixture/test_fixture_fetch.php.inc new file mode 100644 index 0000000..14a7ec4 --- /dev/null +++ b/tests/Rector/ReplaceFetchAllMethodCallRector/Fixture/test_fixture_fetch.php.inc @@ -0,0 +1,67 @@ +getQueryBuilder(); + $result = $qb->select('*') + ->from('pages') + ->executeQuery(); + + $result->fetchAll(); + $result->fetchAll(PDO::FETCH_COLUMN); + $result->fetchAll(PDO::FETCH_ASSOC); + $result->fetchAll(PDO::FETCH_NUM); + + $result->fetch(PDO::FETCH_COLUMN); + $result->fetch(PDO::FETCH_ASSOC); + $result->fetch(); + $result->fetch(PDO::FETCH_NUM); + } +} + +?> +----- +getQueryBuilder(); + $result = $qb->select('*') + ->from('pages') + ->executeQuery(); + + $result->fetchAllAssociative(); + $result->fetchFirstColumn(); + $result->fetchAllAssociative(); + $result->fetchAllNumeric(); + + $result->fetchOne(); + $result->fetchAssociative(); + $result->fetchAssociative(); + $result->fetchNumeric(); + } +} + +?> diff --git a/tests/Rector/ReplaceFetchAllMethodCallRector/ReplaceFetchAllMethodCallRectorTest.php b/tests/Rector/ReplaceFetchAllMethodCallRector/ReplaceFetchAllMethodCallRectorTest.php new file mode 100644 index 0000000..e36c33f --- /dev/null +++ b/tests/Rector/ReplaceFetchAllMethodCallRector/ReplaceFetchAllMethodCallRectorTest.php @@ -0,0 +1,33 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/config.php'; + } +} diff --git a/tests/Rector/ReplaceFetchAllMethodCallRector/config/config.php b/tests/Rector/ReplaceFetchAllMethodCallRector/config/config.php new file mode 100644 index 0000000..43b9378 --- /dev/null +++ b/tests/Rector/ReplaceFetchAllMethodCallRector/config/config.php @@ -0,0 +1,16 @@ +withRules([ + ReplaceFetchAllMethodCallRector::class, + ]); From defb7233ac2b58590042774bcc2943c33fc32886 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Thu, 20 Nov 2025 15:48:52 +0100 Subject: [PATCH 3/3] fix(style): Fix some code style issue Signed-off-by: Carl Schwan --- src/Rector/AnnotationToAttributeRector.php | 2 +- src/Rector/RenameParameterRector.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Rector/AnnotationToAttributeRector.php b/src/Rector/AnnotationToAttributeRector.php index f40573b..63ba407 100644 --- a/src/Rector/AnnotationToAttributeRector.php +++ b/src/Rector/AnnotationToAttributeRector.php @@ -191,7 +191,7 @@ function (DocNode $docNode) use (&$attributeGroups) { } $tag = trim($docNode->name, '@'); // not a basic one - if (strpos($tag, '\\') !== \false) { + if (strpos($tag, '\\') !== false) { return null; } foreach ($this->annotationsToAttributes as $annotationToAttribute) { diff --git a/src/Rector/RenameParameterRector.php b/src/Rector/RenameParameterRector.php index 2dd7091..d3434f8 100644 --- a/src/Rector/RenameParameterRector.php +++ b/src/Rector/RenameParameterRector.php @@ -103,12 +103,12 @@ public function refactor(Node $node): ?Node return null; } - $hasChanged = \false; + $hasChanged = false; foreach ($this->renameParameters as $renameParameter) { foreach ($params as $param) { if ($this->renameVariable($param->var, $renameParameter)) { - $hasChanged = \true; + $hasChanged = true; } } }