From a63038b95c8d7722ae722665ad76d03c72920bc0 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Wed, 22 Jan 2020 19:00:37 +0100 Subject: [PATCH] [CakePHPToSymfony] Add CakePHPModelToDoctrineRepositoryRector --- .github/workflows/test_with_doctrine.yaml | 8 +- ...-50.yaml => cakephp-24-to-symfony-51.yaml} | 5 +- docs/AllRectorsOverview.md | 59 +++- ecs.yaml | 1 + ...ePHPControllerComponentToSymfonyRector.php | 13 +- ...CakePHPModelToDoctrineRepositoryRector.php | 264 ++++++++++++++++++ .../NodeFactory/DoctrineNodeFactory.php | 85 ++++++ .../DoctrineRepositoryClassMethodFactory.php | 161 +++++++++++ ...PHPModelToDoctrineRepositoryRectorTest.php | 34 +++ .../Fixture/fixture.php.inc | 40 +++ .../Source/ExpectedActivityRepository.php | 25 ++ .../CatchExceptionNameMatchingTypeRector.php | 13 +- .../Rector/Use_/RemoveUnusedAliasRector.php | 11 +- ...VariableToVariableOnFunctionCallRector.php | 11 +- .../src/Rector/Class_/RenameClassRector.php | 2 +- phpstan.neon | 2 + .../BetterStandardPrinterTrait.php | 11 + .../AbstractRector/NameResolverTrait.php | 17 +- .../MultipleClassFileToPsr4ClassesRector.php | 13 +- 19 files changed, 715 insertions(+), 60 deletions(-) rename config/set/cakephp-to-symfony/{cakephp-24-to-symfony-50.yaml => cakephp-24-to-symfony-51.yaml} (84%) create mode 100644 packages/CakePHPToSymfony/src/Rector/Class_/CakePHPModelToDoctrineRepositoryRector.php create mode 100644 packages/CakePHPToSymfony/src/Rector/NodeFactory/DoctrineNodeFactory.php create mode 100644 packages/CakePHPToSymfony/src/Rector/NodeFactory/DoctrineRepositoryClassMethodFactory.php create mode 100644 packages/CakePHPToSymfony/tests/Rector/Class_/CakePHPModelToDoctrineRepositoryRector/CakePHPModelToDoctrineRepositoryRectorTest.php create mode 100644 packages/CakePHPToSymfony/tests/Rector/Class_/CakePHPModelToDoctrineRepositoryRector/Fixture/fixture.php.inc create mode 100644 packages/CakePHPToSymfony/tests/Rector/Class_/CakePHPModelToDoctrineRepositoryRector/Source/ExpectedActivityRepository.php diff --git a/.github/workflows/test_with_doctrine.yaml b/.github/workflows/test_with_doctrine.yaml index e27b28a8683c..c1e5ce9e88f4 100644 --- a/.github/workflows/test_with_doctrine.yaml +++ b/.github/workflows/test_with_doctrine.yaml @@ -1,7 +1,7 @@ -name: Test_With_Doctrine +name: Test With Doctrine on: - pull_request: + pull_request: null push: branches: - master @@ -15,6 +15,7 @@ jobs: with: php-version: 7.3 coverage: none + - name: Clone doctrine/orm and install safe dependencies run: | # cannot install dev deps (--no-dev), because doctrine/orm might inherit from them in different version @@ -30,5 +31,4 @@ jobs: # do not intall doctrine/orm phpstan, it conflicts with Retor's one composer install -d orm --no-dev - - run: | - bin/rector process orm/lib --set dead-code --autoload-file orm/vendor/autoload.php + - run: bin/rector process orm/lib --set dead-code --autoload-file orm/vendor/autoload.php diff --git a/config/set/cakephp-to-symfony/cakephp-24-to-symfony-50.yaml b/config/set/cakephp-to-symfony/cakephp-24-to-symfony-51.yaml similarity index 84% rename from config/set/cakephp-to-symfony/cakephp-24-to-symfony-50.yaml rename to config/set/cakephp-to-symfony/cakephp-24-to-symfony-51.yaml index 57d8189b32ed..82381c5154cc 100644 --- a/config/set/cakephp-to-symfony/cakephp-24-to-symfony-50.yaml +++ b/config/set/cakephp-to-symfony/cakephp-24-to-symfony-51.yaml @@ -1,4 +1,4 @@ -# from CakePHP 2.4.6 to Symfony 5.1 (May 2020) and Twig 3 +# from CakePHP 2.4.6 (April 2014) to Symfony 5.1 (May 2020) and Twig 3 services: # https://github.com/cakephp/cakephp/blob/2.4.6/lib/Cake/Controller/Controller.php Rector\CakePHPToSymfony\Rector\Class_\CakePHPControllerToSymfonyControllerRector: null @@ -12,4 +12,7 @@ services: Rector\CakePHPToSymfony\Rector\Echo_\CakePHPTemplateLinkToTwigRector: null Rector\CakePHPToSymfony\Rector\Echo_\CakePHPTemplateTranslateToTwigRector: null Rector\CakePHPToSymfony\Rector\Echo_\CakePHPTemplateHToTwigRector: null + + # Model to Doctrine Rector\CakePHPToSymfony\Rector\Class_\CakePHPModelToDoctrineEntityRector: null + Rector\CakePHPToSymfony\Rector\Class_\CakePHPModelToDoctrineRepositoryRector: null diff --git a/docs/AllRectorsOverview.md b/docs/AllRectorsOverview.md index 7ac2c4c0cd25..162c037c565b 100644 --- a/docs/AllRectorsOverview.md +++ b/docs/AllRectorsOverview.md @@ -1,4 +1,4 @@ -# All 443 Rectors Overview +# All 444 Rectors Overview - [Projects](#projects) - [General](#general) @@ -454,6 +454,63 @@ Migrate CakePHP Model active record to Doctrine\ORM Entity and EntityRepository
+### `CakePHPModelToDoctrineRepositoryRector` + +- class: `Rector\CakePHPToSymfony\Rector\Class_\CakePHPModelToDoctrineRepositoryRector` + +Migrate CakePHP Model active record to Doctrine\ORM\Repository with repository/DQL method calls + +```diff +-class Activity extends \AppModel ++use Doctrine\ORM\EntityManagerInterface; ++ ++class Activity + { ++} ++ ++class ActivityRepository ++{ ++ /** ++ * @var EntityManagerInterface ++ */ ++ private $repository; ++ ++ public function __construct(EntityManagerInterface $entityManager) ++ { ++ $this->repository = $entityManager->getRepository(Activity::class); ++ } ++ + public function getAll() + { +- $result = $this->find('all'); ++ $result = $this->repository->findAll(); + + return $result; + } + + public function getOne() + { +- $result = $this->find('first', [ +- 'conditions' => [ +- 'DocumentVersionsSave.revision_number' => $versionId, +- 'DocumentVersionsSave.document_id' => $documentId, +- ], +- 'order' => [ +- 'created DESC', +- ], +- ]); ++ $result = $this->findOneBy([ ++ 'revision_number' => $versionId, ++ 'document_id' => $documentId, ++ ], 'created DESC'); + + return $result; + } + } +``` + +
+ ### `CakePHPTemplateHToTwigRector` - class: `Rector\CakePHPToSymfony\Rector\Echo_\CakePHPTemplateHToTwigRector` diff --git a/ecs.yaml b/ecs.yaml index b15e29bc56f1..5cdf7a68093f 100644 --- a/ecs.yaml +++ b/ecs.yaml @@ -132,6 +132,7 @@ parameters: Symplify\CodingStandard\Sniffs\ControlStructure\SprintfOverContactSniff: # respects inherited pattern for better comparing - 'src/PhpParser/Printer/BetterStandardPrinter.php' + - 'src/Rector/AbstractRector/BetterStandardPrinterTrait.php' PHP_CodeSniffer\Standards\Generic\Sniffs\CodeAnalysis\AssignmentInConditionSniff.FoundInWhileCondition: null diff --git a/packages/CakePHPToSymfony/src/Rector/Class_/CakePHPControllerComponentToSymfonyRector.php b/packages/CakePHPToSymfony/src/Rector/Class_/CakePHPControllerComponentToSymfonyRector.php index ab57ac2b531e..a913ee039805 100644 --- a/packages/CakePHPToSymfony/src/Rector/Class_/CakePHPControllerComponentToSymfonyRector.php +++ b/packages/CakePHPToSymfony/src/Rector/Class_/CakePHPControllerComponentToSymfonyRector.php @@ -9,7 +9,6 @@ use PhpParser\Node\Stmt\Class_; use PHPStan\Type\ObjectType; use Rector\CakePHPToSymfony\Rector\AbstractCakePHPRector; -use Rector\CodingStyle\Naming\ClassNaming; use Rector\Exception\ShouldNotHappenException; use Rector\PhpParser\Node\Manipulator\ClassManipulator; use Rector\RectorDefinition\CodeSample; @@ -27,20 +26,14 @@ final class CakePHPControllerComponentToSymfonyRector extends AbstractCakePHPRec */ private $classManipulator; - /** - * @var ClassNaming - */ - private $classNaming; - /** * @var string[] */ private $componentsClasses = []; - public function __construct(ClassManipulator $classManipulator, ClassNaming $classNaming) + public function __construct(ClassManipulator $classManipulator) { $this->classManipulator = $classManipulator; - $this->classNaming = $classNaming; } public function getDefinition(): RectorDefinition @@ -131,7 +124,7 @@ public function refactor(Node $node): ?Node $oldProperyNameToNewPropertyName = []; foreach ($componentClasses as $componentName => $componentClass) { - $componentClassShortName = $this->classNaming->getShortName($componentClass); + $componentClassShortName = $this->getShortName($componentClass); $propertyShortName = lcfirst($componentClassShortName); $this->addPropertyToClass($node, new ObjectType($componentClass), $propertyShortName); @@ -179,7 +172,7 @@ private function matchComponentClass(array $componentNames): array foreach ($componentNames as $componentName) { foreach ($componentsClasses as $componentClass) { - $shortComponentClass = $this->classNaming->getShortName($componentClass); + $shortComponentClass = $this->getShortName($componentClass); if (! Strings::startsWith($shortComponentClass, $componentName)) { continue; } diff --git a/packages/CakePHPToSymfony/src/Rector/Class_/CakePHPModelToDoctrineRepositoryRector.php b/packages/CakePHPToSymfony/src/Rector/Class_/CakePHPModelToDoctrineRepositoryRector.php new file mode 100644 index 000000000000..f98fa08146e1 --- /dev/null +++ b/packages/CakePHPToSymfony/src/Rector/Class_/CakePHPModelToDoctrineRepositoryRector.php @@ -0,0 +1,264 @@ +doctrineRepositoryClassMethodFactory = $doctrineRepositoryClassMethodFactory; + $this->doctrineNodeFactory = $doctrineNodeFactory; + } + + public function getDefinition(): RectorDefinition + { + return new RectorDefinition( + 'Migrate CakePHP Model active record to Doctrine\ORM\Repository with repository/DQL method calls', + [ + new CodeSample( + <<<'PHP' +class Activity extends \AppModel +{ + public function getAll() + { + $result = $this->find('all'); + + return $result; + } + + public function getOne() + { + $result = $this->find('first', [ + 'conditions' => [ + 'DocumentVersionsSave.revision_number' => $versionId, + 'DocumentVersionsSave.document_id' => $documentId, + ], + 'order' => [ + 'created DESC', + ], + ]); + + return $result; + } +} +PHP +, + <<<'PHP' +use Doctrine\ORM\EntityManagerInterface; + +class Activity +{ +} + +class ActivityRepository +{ + /** + * @var EntityManagerInterface + */ + private $repository; + + public function __construct(EntityManagerInterface $entityManager) + { + $this->repository = $entityManager->getRepository(Activity::class); + } + + public function getAll() + { + $result = $this->repository->findAll(); + + return $result; + } + + public function getOne() + { + $result = $this->findOneBy([ + 'revision_number' => $versionId, + 'document_id' => $documentId, + ], 'created DESC'); + + return $result; + } +} +PHP + + ), + ] + ); + } + + /** + * @return string[] + */ + public function getNodeTypes(): array + { + return [Class_::class]; + } + + /** + * @param Class_ $node + */ + public function refactor(Node $node): ?Node + { + if (! $this->isInCakePHPController($node)) { + return null; + } + + $repositoryMethods = $this->getRepositoryMethods($node); + if ($repositoryMethods === []) { + return null; + } + + // 1. create repository class + $repositoryClass = $this->createRepositoryClass($node, $repositoryMethods); + + // 2. save repository class + $nodeToPrint = $this->createNodeToPrint($node, $repositoryClass); + + $repositoryFilePath = $this->createRepositoryFilePath($node); + $this->printToFile($nodeToPrint, $repositoryFilePath); + + // 3.remove repository class methods + foreach ($repositoryMethods as $repositoryMethod) { + $this->removeNode($repositoryMethod); + } + + $node->extends = null; + + return $node; + } + + /** + * Looks for "$this->find()" call + */ + private function inRepositoryMethod(ClassMethod $classMethod): bool + { + $isRepositoryMethod = false; + + $this->traverseNodesWithCallable((array) $classMethod->getStmts(), function (Node $node) use ( + &$isRepositoryMethod + ) { + if (! $node instanceof MethodCall) { + return null; + } + + if (! $this->isObjectType($node->var, 'AppModel')) { + return null; + } + + if (! $this->isName($node->name, 'find')) { + return null; + } + + $isRepositoryMethod = true; + + return NodeTraverser::STOP_TRAVERSAL; + }); + + return $isRepositoryMethod; + } + + /** + * @return ClassMethod[] + */ + private function getRepositoryMethods(Class_ $class): array + { + $repositoryMethods = []; + + foreach ($class->getMethods() as $classMethod) { + if (! $this->inRepositoryMethod($classMethod)) { + continue; + } + + $repositoryMethods[] = $classMethod; + } + + return $repositoryMethods; + } + + private function createNodeToPrint(Class_ $class, Class_ $repositoryClass): Node + { + /** @var Namespace_|null $namespaceNode */ + $namespaceNode = $class->getAttribute(AttributeKey::NAMESPACE_NODE); + if ($namespaceNode !== null) { + $namespaceNode->stmts = [$repositoryClass]; + return $namespaceNode; + } + + return $repositoryClass; + } + + private function createRepositoryFilePath(Class_ $class): string + { + $repositoryClassName = $this->getRepositoryShortClassName($class); + + /** @var SmartFileInfo $fileInfo */ + $fileInfo = $class->getAttribute(AttributeKey::FILE_INFO); + + return $fileInfo->getRelativeDirectoryPath() . '/' . $repositoryClassName . '.php'; + } + + /** + * @param ClassMethod[] $repositoryMethods + */ + private function createRepositoryClass(Class_ $class, array $repositoryMethods): Class_ + { + $repositoryClassName = $this->getRepositoryShortClassName($class); + $repositoryClass = new Class_($repositoryClassName); + + $repositoryClass->stmts[] = $this->doctrineNodeFactory->createRepositoryProperty(); + + $entityClass = $this->getName($class->name); + assert(is_string($entityClass)); + + $repositoryClass->stmts[] = $this->doctrineNodeFactory->createConstructorWithGetRepositoryAssign($entityClass); + + foreach ($repositoryMethods as $repositoryMethod) { + $doctrineRepositoryClassMethod = $this->doctrineRepositoryClassMethodFactory->createFromCakePHPClassMethod( + $repositoryMethod, + $entityClass + ); + $repositoryClass->stmts[] = $doctrineRepositoryClassMethod; + } + + return $repositoryClass; + } + + private function getRepositoryShortClassName(Class_ $class): string + { + return $this->getShortName($class->name) . 'Repository'; + } +} diff --git a/packages/CakePHPToSymfony/src/Rector/NodeFactory/DoctrineNodeFactory.php b/packages/CakePHPToSymfony/src/Rector/NodeFactory/DoctrineNodeFactory.php new file mode 100644 index 000000000000..4eefc00569b8 --- /dev/null +++ b/packages/CakePHPToSymfony/src/Rector/NodeFactory/DoctrineNodeFactory.php @@ -0,0 +1,85 @@ +builderFactory = $builderFactory; + $this->docBlockManipulator = $docBlockManipulator; + } + + /** + * Creates: + * $this->repository = $entityManager->getRepository(\EntityClass::class); + */ + public function createRepositoryAssign(string $entityClass): Assign + { + $repositoryPropertyFetch = new PropertyFetch(new Variable('this'), new Identifier('repository')); + + $entityClassReference = new ClassConstFetch(new FullyQualified($entityClass), 'class'); + + $getRepositoryMethodCall = new MethodCall(new Variable('entityManager'), 'getRepository', [ + new Arg($entityClassReference), + ]); + + return new Assign($repositoryPropertyFetch, $getRepositoryMethodCall); + } + + public function createRepositoryProperty(): Property + { + $repositoryProperty = $this->builderFactory->property('repository') + ->makePrivate() + ->getNode(); + + $this->docBlockManipulator->changeVarTag( + $repositoryProperty, + new FullyQualifiedObjectType('Doctrine\ORM\EntityRepository') + ); + + return $repositoryProperty; + } + + public function createConstructorWithGetRepositoryAssign(string $entityClass): ClassMethod + { + $param = $this->builderFactory->param('entityManager') + ->setType(new FullyQualified(EntityManagerInterface::class)) + ->getNode(); + + $assign = $this->createRepositoryAssign($entityClass); + + return $this->builderFactory->method('__construct') + ->makePublic() + ->addParam($param) + ->addStmt($assign) + ->getNode(); + } +} diff --git a/packages/CakePHPToSymfony/src/Rector/NodeFactory/DoctrineRepositoryClassMethodFactory.php b/packages/CakePHPToSymfony/src/Rector/NodeFactory/DoctrineRepositoryClassMethodFactory.php new file mode 100644 index 000000000000..8286d5fd4c81 --- /dev/null +++ b/packages/CakePHPToSymfony/src/Rector/NodeFactory/DoctrineRepositoryClassMethodFactory.php @@ -0,0 +1,161 @@ +callableNodeTraverser = $callableNodeTraverser; + $this->nameResolver = $nameResolver; + $this->valueResolver = $valueResolver; + } + + public function createFromCakePHPClassMethod(ClassMethod $classMethod, string $entityClass): ClassMethod + { + $this->callableNodeTraverser->traverseNodesWithCallable( + (array) $classMethod->getStmts(), + function (Node $node) use ($entityClass) { + if (! $node instanceof MethodCall) { + return null; + } + + if (! $this->nameResolver->isName($node->name, 'find')) { + return null; + } + + $this->createMethodByKind($node, $entityClass); + } + ); + + return $classMethod; + } + + private function createMethodByKind(MethodCall $methodCall, string $entityClass): void + { + $findKind = $this->valueResolver->getValue($methodCall->args[0]->value); + if ($findKind === 'all') { + $methodCall->var = new PropertyFetch(new Variable('this'), 'repository'); + $methodCall->name = new Identifier('findAll'); + $methodCall->args = []; + } elseif ($findKind === 'first') { + $methodCall->name = new Identifier('findOneBy'); + unset($methodCall->args[0]); + + if (! isset($methodCall->args[1])) { + return; + } + + $firstArgument = $methodCall->args[1]->value; + assert($firstArgument instanceof Array_); + + $methodCall->args = $this->createFindOneByArgs($entityClass, $firstArgument); + } else { + throw new NotImplementedException(); + } + } + + private function getItemByKey(Array_ $array, string $key): ?ArrayItem + { + foreach ($array->items as $arrayItem) { + if ($arrayItem->key === null) { + continue; + } + + if ($this->valueResolver->getValue($arrayItem->key) !== $key) { + continue; + } + + return $arrayItem; + } + + return null; + } + + private function clearStringFromEntityPrefix(String_ $string, string $entityClass): String_ + { + $string->value = Strings::replace($string->value, '#^' . $entityClass . '\.#'); + + return $string; + } + + /** + * @return Arg[] + */ + private function createFindOneByArgs(string $entityClass, Array_ $firstArgument): array + { + $args = []; + + /** @var Array_ $firstArgument */ + $conditionsArrayItem = $this->getItemByKey($firstArgument, 'conditions'); + if ($conditionsArrayItem !== null && $conditionsArrayItem->value instanceof Array_) { + $conditionArray = $conditionsArrayItem->value; + $this->removeEntityPrefixFromConditionKeys($conditionArray, $entityClass); + $args[] = new Arg($conditionArray); + } + + $orderItem = $this->getItemByKey($firstArgument, 'order'); + if ($orderItem !== null) { + if (count($args) === 0) { + $args[] = new Arg(new ConstFetch(new Name('null'))); + } + + /** @var Array_ $orderArray */ + $orderArray = $orderItem->value; + assert(isset($orderArray->items[0])); + $args[] = new Arg($orderArray->items[0]->value); + } + + return $args; + } + + private function removeEntityPrefixFromConditionKeys(Array_ $conditionArray, string $entityClass): void + { + // clear keys from current class + foreach ($conditionArray->items as $conditionArrayItem) { + if (! $conditionArrayItem->key instanceof String_) { + continue; + } + + $conditionArrayItem->key = $this->clearStringFromEntityPrefix($conditionArrayItem->key, $entityClass); + } + } +} diff --git a/packages/CakePHPToSymfony/tests/Rector/Class_/CakePHPModelToDoctrineRepositoryRector/CakePHPModelToDoctrineRepositoryRectorTest.php b/packages/CakePHPToSymfony/tests/Rector/Class_/CakePHPModelToDoctrineRepositoryRector/CakePHPModelToDoctrineRepositoryRectorTest.php new file mode 100644 index 000000000000..7da29e00b796 --- /dev/null +++ b/packages/CakePHPToSymfony/tests/Rector/Class_/CakePHPModelToDoctrineRepositoryRector/CakePHPModelToDoctrineRepositoryRectorTest.php @@ -0,0 +1,34 @@ +doTestFile($file); + + $repositoryFilePath = $this->getTempPath() . '/ActivityRepository.php'; + $this->assertFileExists($repositoryFilePath); + $this->assertFileEquals(__DIR__ . '/Source/ExpectedActivityRepository.php', $repositoryFilePath); + } + + public function provideDataForTest(): Iterator + { + return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + protected function getRectorClass(): string + { + return CakePHPModelToDoctrineRepositoryRector::class; + } +} diff --git a/packages/CakePHPToSymfony/tests/Rector/Class_/CakePHPModelToDoctrineRepositoryRector/Fixture/fixture.php.inc b/packages/CakePHPToSymfony/tests/Rector/Class_/CakePHPModelToDoctrineRepositoryRector/Fixture/fixture.php.inc new file mode 100644 index 000000000000..971d7099d6d7 --- /dev/null +++ b/packages/CakePHPToSymfony/tests/Rector/Class_/CakePHPModelToDoctrineRepositoryRector/Fixture/fixture.php.inc @@ -0,0 +1,40 @@ +find('all'); + + return $result; + } + + public function getOne() + { + $result = $this->find('first', [ + 'conditions' => [ + 'Activity.revision_number' => $versionId, + 'Activity.document_id' => $documentId, + ], + 'order' => [ + 'created DESC', + ], + ]); + + return $result; + } +} + +?> +----- + diff --git a/packages/CakePHPToSymfony/tests/Rector/Class_/CakePHPModelToDoctrineRepositoryRector/Source/ExpectedActivityRepository.php b/packages/CakePHPToSymfony/tests/Rector/Class_/CakePHPModelToDoctrineRepositoryRector/Source/ExpectedActivityRepository.php new file mode 100644 index 000000000000..830f96616b38 --- /dev/null +++ b/packages/CakePHPToSymfony/tests/Rector/Class_/CakePHPModelToDoctrineRepositoryRector/Source/ExpectedActivityRepository.php @@ -0,0 +1,25 @@ +repository = $entityManager->getRepository(\Activity::class); + } + public function getAll() + { + $result = $this->repository->findAll(); + return $result; + } + public function getOne() + { + $result = $this->findOneBy(['revision_number' => $versionId, 'document_id' => $documentId], 'created DESC'); + return $result; + } +} diff --git a/packages/CodingStyle/src/Rector/Catch_/CatchExceptionNameMatchingTypeRector.php b/packages/CodingStyle/src/Rector/Catch_/CatchExceptionNameMatchingTypeRector.php index caadda2afd95..2084254b7175 100644 --- a/packages/CodingStyle/src/Rector/Catch_/CatchExceptionNameMatchingTypeRector.php +++ b/packages/CodingStyle/src/Rector/Catch_/CatchExceptionNameMatchingTypeRector.php @@ -7,7 +7,6 @@ use PhpParser\Node; use PhpParser\Node\Expr\Variable; use PhpParser\Node\Stmt\Catch_; -use Rector\CodingStyle\Naming\ClassNaming; use Rector\Rector\AbstractRector; use Rector\RectorDefinition\CodeSample; use Rector\RectorDefinition\RectorDefinition; @@ -17,16 +16,6 @@ */ final class CatchExceptionNameMatchingTypeRector extends AbstractRector { - /** - * @var ClassNaming - */ - private $classNaming; - - public function __construct(ClassNaming $classNaming) - { - $this->classNaming = $classNaming; - } - public function getDefinition(): RectorDefinition { return new RectorDefinition('Type and name of catch exception should match', [ @@ -80,7 +69,7 @@ public function refactor(Node $node): ?Node } $type = $node->types[0]; - $typeShortName = $this->classNaming->getShortName($type); + $typeShortName = $this->getShortName($type); $oldVariableName = $this->getName($node->var); if (! $oldVariableName) { diff --git a/packages/CodingStyle/src/Rector/Use_/RemoveUnusedAliasRector.php b/packages/CodingStyle/src/Rector/Use_/RemoveUnusedAliasRector.php index 544b55061efd..70de7fac646b 100644 --- a/packages/CodingStyle/src/Rector/Use_/RemoveUnusedAliasRector.php +++ b/packages/CodingStyle/src/Rector/Use_/RemoveUnusedAliasRector.php @@ -22,7 +22,6 @@ use PHPStan\Type\UnionType; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; use Rector\CodingStyle\Imports\ShortNameResolver; -use Rector\CodingStyle\Naming\ClassNaming; use Rector\Exception\ShouldNotHappenException; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\PHPStan\Type\AliasedObjectType; @@ -45,19 +44,13 @@ final class RemoveUnusedAliasRector extends AbstractRector */ private $resolvedDocPossibleAliases = []; - /** - * @var ClassNaming - */ - private $classNaming; - /** * @var ShortNameResolver */ private $shortNameResolver; - public function __construct(ClassNaming $classNaming, ShortNameResolver $shortNameResolver) + public function __construct(ShortNameResolver $shortNameResolver) { - $this->classNaming = $classNaming; $this->shortNameResolver = $shortNameResolver; } @@ -163,7 +156,7 @@ private function collectUseNamesAliasToName(Use_ $use): array $shortNames = $this->shortNameResolver->resolveForNode($use); foreach ($shortNames as $alias => $useImport) { - $shortName = $this->classNaming->getShortName($useImport); + $shortName = $this->getShortName($useImport); if ($shortName === $alias) { continue; } diff --git a/packages/Php70/src/Rector/FuncCall/NonVariableToVariableOnFunctionCallRector.php b/packages/Php70/src/Rector/FuncCall/NonVariableToVariableOnFunctionCallRector.php index 85bc5ad72be3..c319850422c1 100644 --- a/packages/Php70/src/Rector/FuncCall/NonVariableToVariableOnFunctionCallRector.php +++ b/packages/Php70/src/Rector/FuncCall/NonVariableToVariableOnFunctionCallRector.php @@ -23,7 +23,6 @@ use PHPStan\Analyser\MutatingScope; use PHPStan\Analyser\Scope; use PHPStan\Reflection\ParameterReflection; -use Rector\CodingStyle\Naming\ClassNaming; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\Php70\ValueObject\VariableAssignPair; use Rector\PHPStan\Reflection\CallReflectionResolver; @@ -48,15 +47,9 @@ final class NonVariableToVariableOnFunctionCallRector extends AbstractRector */ private $callReflectionResolver; - /** - * @var ClassNaming - */ - private $classNaming; - - public function __construct(CallReflectionResolver $callReflectionResolver, ClassNaming $classNaming) + public function __construct(CallReflectionResolver $callReflectionResolver) { $this->callReflectionResolver = $callReflectionResolver; - $this->classNaming = $classNaming; } public function getDefinition(): RectorDefinition @@ -176,7 +169,7 @@ private function isVariableLikeNode(Node $node): bool private function getVariableNameFor(Expr $expr, Scope $scope): string { if ($expr instanceof New_ && $expr->class instanceof Name) { - $name = $this->classNaming->getShortName($expr->class); + $name = $this->getShortName($expr->class); } else { $name = $this->getName($expr); } diff --git a/packages/Renaming/src/Rector/Class_/RenameClassRector.php b/packages/Renaming/src/Rector/Class_/RenameClassRector.php index 74221a3128bf..ae74e0997e66 100644 --- a/packages/Renaming/src/Rector/Class_/RenameClassRector.php +++ b/packages/Renaming/src/Rector/Class_/RenameClassRector.php @@ -241,7 +241,7 @@ private function refactorClassLikeNode(ClassLike $classLike): ?Node $this->alreadyProcessedClasses[] = $name; $newName = $this->oldToNewClasses[$name]; - $newClassNamePart = $this->classNaming->getShortName($newName); + $newClassNamePart = $this->getShortName($newName); $newNamespacePart = $this->classNaming->getNamespace($newName); $this->ensureClassWillNotBeDuplicate($newName, $name); diff --git a/phpstan.neon b/phpstan.neon index ed8f76213aee..f3d871bd3a73 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -228,3 +228,5 @@ parameters: # known value - '#Access to undefined constant Rector\\BetterPhpDocParser\\PhpDocNode\\AbstractTagValueNode\:\:SHORT_NAME#' + - '#Parameter \#1 \$name of method Rector\\Rector\\AbstractRector\:\:getShortName\(\) expects PhpParser\\Node\\Identifier\|PhpParser\\Node\\Name\|string, PhpParser\\Node\\Identifier\|null given#' + - '#Parameter \#1 \$entityClass of method Rector\\CakePHPToSymfony\\Rector\\NodeFactory\\DoctrineNodeFactory\:\:createConstructorWithGetRepositoryAssign\(\) expects string, string\|null given#' diff --git a/src/Rector/AbstractRector/BetterStandardPrinterTrait.php b/src/Rector/AbstractRector/BetterStandardPrinterTrait.php index 3b9576a6a8a5..b48369e1ea21 100644 --- a/src/Rector/AbstractRector/BetterStandardPrinterTrait.php +++ b/src/Rector/AbstractRector/BetterStandardPrinterTrait.php @@ -4,6 +4,7 @@ namespace Rector\Rector\AbstractRector; +use Nette\Utils\FileSystem; use PhpParser\Node; use Rector\PhpParser\Node\BetterNodeFinder; use Rector\PhpParser\Printer\BetterStandardPrinter; @@ -43,6 +44,16 @@ public function print($node): string return $this->betterStandardPrinter->print($node); } + /** + * @param Node|Node[]|null $node + */ + public function printToFile($node, string $filePath): void + { + $content = $this->print($node); + $content = 'nameResolver = $nameResolver; + $this->classNaming = $classNaming; } public function isName(Node $node, string $name): bool @@ -48,4 +55,12 @@ public function getName(Node $node): ?string { return $this->nameResolver->getName($node); } + + /** + * @param string|Node\Name|Node\Identifier $name + */ + protected function getShortName($name): string + { + return $this->classNaming->getShortName($name); + } } diff --git a/src/Rector/Psr4/MultipleClassFileToPsr4ClassesRector.php b/src/Rector/Psr4/MultipleClassFileToPsr4ClassesRector.php index 2c1094d77e17..535df22e892d 100644 --- a/src/Rector/Psr4/MultipleClassFileToPsr4ClassesRector.php +++ b/src/Rector/Psr4/MultipleClassFileToPsr4ClassesRector.php @@ -10,7 +10,6 @@ use PhpParser\Node\Stmt\ClassLike; use PhpParser\Node\Stmt\Declare_; use PhpParser\Node\Stmt\Namespace_; -use Rector\CodingStyle\Naming\ClassNaming; use Rector\FileSystemRector\Rector\AbstractFileSystemRector; use Rector\RectorDefinition\CodeSample; use Rector\RectorDefinition\RectorDefinition; @@ -21,16 +20,6 @@ */ final class MultipleClassFileToPsr4ClassesRector extends AbstractFileSystemRector { - /** - * @var ClassNaming - */ - private $classNaming; - - public function __construct(ClassNaming $classNaming) - { - $this->classNaming = $classNaming; - } - public function getDefinition(): RectorDefinition { return new RectorDefinition( @@ -110,7 +99,7 @@ private function shouldDeleteFileInfo(SmartFileInfo $smartFileInfo, array $nodes continue; } - $classShortName = $this->classNaming->getShortName($className); + $classShortName = $this->getShortName($className); if ($smartFileInfo->getBasenameWithoutSuffix() === $classShortName) { return false; }