[CakePHPToSymfony] Add CakePHPModelToDoctrineRepositoryRector

This commit is contained in:
TomasVotruba 2020-01-22 19:00:37 +01:00
parent 4d5b203242
commit a63038b95c
19 changed files with 715 additions and 60 deletions

View File

@ -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

View File

@ -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

View File

@ -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
<br>
### `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;
}
}
```
<br>
### `CakePHPTemplateHToTwigRector`
- class: `Rector\CakePHPToSymfony\Rector\Echo_\CakePHPTemplateHToTwigRector`

View File

@ -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

View File

@ -9,7 +9,6 @@ use PhpParser\Node;
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 @@ PHP
$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 @@ PHP
foreach ($componentNames as $componentName) {
foreach ($componentsClasses as $componentClass) {
$shortComponentClass = $this->classNaming->getShortName($componentClass);
$shortComponentClass = $this->getShortName($componentClass);
if (! Strings::startsWith($shortComponentClass, $componentName)) {
continue;
}

View File

@ -0,0 +1,264 @@
<?php
declare(strict_types=1);
namespace Rector\CakePHPToSymfony\Rector\Class_;
use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Namespace_;
use PhpParser\NodeTraverser;
use Rector\CakePHPToSymfony\Rector\AbstractCakePHPRector;
use Rector\CakePHPToSymfony\Rector\NodeFactory\DoctrineNodeFactory;
use Rector\CakePHPToSymfony\Rector\NodeFactory\DoctrineRepositoryClassMethodFactory;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
use Symplify\SmartFileSystem\SmartFileInfo;
/**
* @see https://book.cakephp.org/2/en/models/retrieving-your-data.html#find
* @see https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/tutorials/getting-started.html#entity-repositories
*
* @see \Rector\CakePHPToSymfony\Tests\Rector\Class_\CakePHPModelToDoctrineRepositoryRector\CakePHPModelToDoctrineRepositoryRectorTest
*/
final class CakePHPModelToDoctrineRepositoryRector extends AbstractCakePHPRector
{
/**
* @var DoctrineRepositoryClassMethodFactory
*/
private $doctrineRepositoryClassMethodFactory;
/**
* @var DoctrineNodeFactory
*/
private $doctrineNodeFactory;
public function __construct(
DoctrineRepositoryClassMethodFactory $doctrineRepositoryClassMethodFactory,
DoctrineNodeFactory $doctrineNodeFactory
) {
$this->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';
}
}

View File

@ -0,0 +1,85 @@
<?php
declare(strict_types=1);
namespace Rector\CakePHPToSymfony\Rector\NodeFactory;
use Doctrine\ORM\EntityManagerInterface;
use PhpParser\BuilderFactory;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Property;
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockManipulator;
use Rector\PHPStan\Type\FullyQualifiedObjectType;
final class DoctrineNodeFactory
{
/**
* @var BuilderFactory
*/
private $builderFactory;
/**
* @var DocBlockManipulator
*/
private $docBlockManipulator;
public function __construct(BuilderFactory $builderFactory, DocBlockManipulator $docBlockManipulator)
{
$this->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();
}
}

View File

@ -0,0 +1,161 @@
<?php
declare(strict_types=1);
namespace Rector\CakePHPToSymfony\Rector\NodeFactory;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Exception\NotImplementedException;
use Rector\PhpParser\Node\Resolver\NameResolver;
use Rector\PhpParser\Node\Value\ValueResolver;
use Rector\PhpParser\NodeTraverser\CallableNodeTraverser;
final class DoctrineRepositoryClassMethodFactory
{
/**
* @var CallableNodeTraverser
*/
private $callableNodeTraverser;
/**
* @var NameResolver
*/
private $nameResolver;
/**
* @var ValueResolver
*/
private $valueResolver;
public function __construct(
CallableNodeTraverser $callableNodeTraverser,
NameResolver $nameResolver,
ValueResolver $valueResolver
) {
$this->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);
}
}
}

View File

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace Rector\CakePHPToSymfony\Tests\Rector\Class_\CakePHPModelToDoctrineRepositoryRector;
use Iterator;
use Rector\CakePHPToSymfony\Rector\Class_\CakePHPModelToDoctrineRepositoryRector;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
final class CakePHPModelToDoctrineRepositoryRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideDataForTest()
*/
public function test(string $file): void
{
$this->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;
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace Rector\CakePHPToSymfony\Tests\Rector\Class_\CakePHPModelToDoctrineRepositoryRector\Fixture;
class Activity extends \AppModel
{
public function getAll()
{
$result = $this->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;
}
}
?>
-----
<?php
namespace Rector\CakePHPToSymfony\Tests\Rector\Class_\CakePHPModelToDoctrineRepositoryRector\Fixture;
class Activity
{
}
?>

View File

@ -0,0 +1,25 @@
<?php
namespace Rector\CakePHPToSymfony\Tests\Rector\Class_\CakePHPModelToDoctrineRepositoryRector\Fixture;
class ActivityRepository
{
/**
* @var \Doctrine\ORM\EntityRepository
*/
private $repository;
public function __construct(\Doctrine\ORM\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;
}
}

View File

@ -7,7 +7,6 @@ namespace Rector\CodingStyle\Rector\Catch_;
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 @@ use Rector\RectorDefinition\RectorDefinition;
*/
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 @@ PHP
}
$type = $node->types[0];
$typeShortName = $this->classNaming->getShortName($type);
$typeShortName = $this->getShortName($type);
$oldVariableName = $this->getName($node->var);
if (! $oldVariableName) {

View File

@ -22,7 +22,6 @@ use PHPStan\Type\Type;
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 @@ PHP
$shortNames = $this->shortNameResolver->resolveForNode($use);
foreach ($shortNames as $alias => $useImport) {
$shortName = $this->classNaming->getShortName($useImport);
$shortName = $this->getShortName($useImport);
if ($shortName === $alias) {
continue;
}

View File

@ -23,7 +23,6 @@ use PhpParser\Node\Stmt\Return_;
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 @@ final class NonVariableToVariableOnFunctionCallRector extends AbstractRector
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);
}

View File

@ -241,7 +241,7 @@ PHP
$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);

View File

@ -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#'

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
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 @@ trait BetterStandardPrinterTrait
return $this->betterStandardPrinter->print($node);
}
/**
* @param Node|Node[]|null $node
*/
public function printToFile($node, string $filePath): void
{
$content = $this->print($node);
$content = '<?php' . PHP_EOL . PHP_EOL . $content . PHP_EOL;
FileSystem::write($filePath, $content);
}
/**
* @param Node|Node[]|null $firstNode
* @param Node|Node[]|null $secondNode

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Rector\Rector\AbstractRector;
use PhpParser\Node;
use Rector\CodingStyle\Naming\ClassNaming;
use Rector\PhpParser\Node\Resolver\NameResolver;
/**
@ -18,12 +19,18 @@ trait NameResolverTrait
*/
private $nameResolver;
/**
* @var ClassNaming
*/
private $classNaming;
/**
* @required
*/
public function autowireNameResolverTrait(NameResolver $nameResolver): void
public function autowireNameResolverTrait(NameResolver $nameResolver, ClassNaming $classNaming): void
{
$this->nameResolver = $nameResolver;
$this->classNaming = $classNaming;
}
public function isName(Node $node, string $name): bool
@ -48,4 +55,12 @@ trait NameResolverTrait
{
return $this->nameResolver->getName($node);
}
/**
* @param string|Node\Name|Node\Identifier $name
*/
protected function getShortName($name): string
{
return $this->classNaming->getShortName($name);
}
}

View File

@ -10,7 +10,6 @@ use PhpParser\Node\Stmt\Class_;
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 @@ use Symplify\SmartFileSystem\SmartFileInfo;
*/
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 @@ PHP
continue;
}
$classShortName = $this->classNaming->getShortName($className);
$classShortName = $this->getShortName($className);
if ($smartFileInfo->getBasenameWithoutSuffix() === $classShortName) {
return false;
}