From 80314eb924e9c71e30b43b2dbda2e1c8548df3ed Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Thu, 20 Jul 2017 18:37:43 +0200 Subject: [PATCH] decouple ClassPropertyCollector, [NamedServicesToContstructor] change mechanism to add new properties post traverse --- src/Builder/Class_/ClassPropertyCollector.php | 26 +++ .../AddPropertiesToClassNodeVisitor.php | 67 ++++++ .../GetterToPropertyNodeVisitor.php | 71 ++++-- .../NamedServicesToConstructorNodeVisitor.php | 203 ------------------ src/config/services.yml | 4 + .../Test.php | 6 - .../correct/correct.php.inc | 2 +- .../correct/correct2.php.inc | 2 +- .../correct/correct3.php.inc | 2 +- .../wrong/wrong.php.inc | 2 +- .../wrong/wrong2.php.inc | 2 +- .../wrong/wrong3.php.inc | 2 +- 12 files changed, 152 insertions(+), 237 deletions(-) create mode 100644 src/Builder/Class_/ClassPropertyCollector.php create mode 100644 src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/AddPropertiesToClassNodeVisitor.php delete mode 100644 src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/NamedServicesToConstructorNodeVisitor.php diff --git a/src/Builder/Class_/ClassPropertyCollector.php b/src/Builder/Class_/ClassPropertyCollector.php new file mode 100644 index 00000000000..4b0255ac111 --- /dev/null +++ b/src/Builder/Class_/ClassPropertyCollector.php @@ -0,0 +1,26 @@ +classProperties[$class] = [ + $propertyType => $propertyName + ]; + } + + /** + * @return string[] + */ + public function getPropertiesforClass(string $class): array + { + return $this->classProperties[$class] ?: []; + } +} diff --git a/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/AddPropertiesToClassNodeVisitor.php b/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/AddPropertiesToClassNodeVisitor.php new file mode 100644 index 00000000000..db33ea6ab06 --- /dev/null +++ b/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/AddPropertiesToClassNodeVisitor.php @@ -0,0 +1,67 @@ +constructorMethodBuilder = $constructorMethodBuilder; + $this->propertyBuilder = $propertyBuilder; + $this->newClassPropertyCollector = $newClassPropertyCollector; + } + + public function afterTraverse(array $nodes): array + { + foreach ($nodes as $node) { + if ($node instanceof Class_) { + $this->className = (string) $node->name; + $this->reconstruct($node); + } + } + + return $nodes; + } + + private function reconstruct(Class_ $classNode): void + { + $propertiesForClass = $this->newClassPropertyCollector->getPropertiesforClass($this->className); + + foreach ($propertiesForClass as $propertyType => $propertyName) { + $this->constructorMethodBuilder->addPropertyAssignToClass($classNode, $propertyType, $propertyName); + $this->propertyBuilder->addPropertyToClass($classNode, $propertyType, $propertyName); + } + } +} diff --git a/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/GetterToPropertyNodeVisitor.php b/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/GetterToPropertyNodeVisitor.php index 01119128e14..bd0dfeb30ff 100644 --- a/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/GetterToPropertyNodeVisitor.php +++ b/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/GetterToPropertyNodeVisitor.php @@ -11,17 +11,23 @@ use PhpParser\Node\Scalar\String_; use PhpParser\NodeVisitorAbstract; use Rector\Builder\Kernel\ServiceFromKernelResolver; use Rector\Builder\Naming\NameResolver; +use Rector\Buillder\Class_\ClassPropertyCollector; use Rector\Tests\NodeVisitor\DependencyInjection\NamedServicesToConstructorReconstructor\Source\LocalKernel; /** * Converts all: - * $this->get('some_service') + * $this->get('some_service') # where "some_service" is name of the service in container * * into: - * $this->someService + * $this->someService # where "someService" is type of the service */ final class GetterToPropertyNodeVisitor extends NodeVisitorAbstract { + /** + * @var string + */ + private $className; + /** * @var NameResolver */ @@ -32,10 +38,34 @@ final class GetterToPropertyNodeVisitor extends NodeVisitorAbstract */ private $serviceFromKernelResolver; - public function __construct(NameResolver $nameResolver, ServiceFromKernelResolver $serviceFromKernelResolver) - { + /** + * @var ClassPropertyCollector + */ + private $classPropertyCollector; + + public function __construct( + NameResolver $nameResolver, + ServiceFromKernelResolver $serviceFromKernelResolver, + ClassPropertyCollector $classPropertyCollector + ) { $this->nameResolver = $nameResolver; $this->serviceFromKernelResolver = $serviceFromKernelResolver; + $this->classPropertyCollector = $classPropertyCollector; + } + + /** + * @param Node[] $nodes + * @return array|null + */ + public function beforeTraverse(array $nodes): ?array + { + foreach ($nodes as $node) { + if ($node instanceof Node\Stmt\Class_) { + $this->className = (string) $node->name; + } + } + + return null; } /** @@ -88,27 +118,17 @@ final class GetterToPropertyNodeVisitor extends NodeVisitorAbstract private function reconstruct(Node $assignOrMethodCallNode): void { if ($assignOrMethodCallNode instanceof Assign) { - $this->processAssignment($assignOrMethodCallNode); + $refactoredMethodCall = $this->processMethodCallNode($assignOrMethodCallNode->expr); + if ($refactoredMethodCall) { + $assignOrMethodCallNode->expr = $refactoredMethodCall; + } } if ($assignOrMethodCallNode instanceof MethodCall) { - $this->processMethodCall($assignOrMethodCallNode); - } - } - - private function processAssignment(Assign $assignNode): void - { - $refactoredMethodCall = $this->processMethodCallNode($assignNode->expr); - if ($refactoredMethodCall) { - $assignNode->expr = $refactoredMethodCall; - } - } - - private function processMethodCall(MethodCall $methodCallNode): void - { - $refactoredMethodCall = $this->processMethodCallNode($methodCallNode->var); - if ($refactoredMethodCall) { - $methodCallNode->var = $refactoredMethodCall; + $refactoredMethodCall = $this->processMethodCallNode($assignOrMethodCallNode->var); + if ($refactoredMethodCall) { + $assignOrMethodCallNode->var = $refactoredMethodCall; + } } } @@ -142,8 +162,15 @@ final class GetterToPropertyNodeVisitor extends NodeVisitorAbstract $serviceName, LocalKernel::class ); + if ($serviceType === null) { + return null; + } + + $propertyName = $this->nameResolver->resolvePropertyNameFromType($serviceType); + $this->classPropertyCollector->addPropertyForClass($this->className, $serviceType, $propertyName); + return $this->createPropertyFetch($propertyName); } diff --git a/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/NamedServicesToConstructorNodeVisitor.php b/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/NamedServicesToConstructorNodeVisitor.php deleted file mode 100644 index a74b29664a5..00000000000 --- a/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/NamedServicesToConstructorNodeVisitor.php +++ /dev/null @@ -1,203 +0,0 @@ -constructorMethodBuilder = $constructorMethodBuilder; - $this->propertyBuilder = $propertyBuilder; - $this->nameResolver = $nameResolver; - $this->serviceFromKernelResolver = $serviceFromKernelResolver; - } - - private function isCandidate(Node $node): bool - { - return $node instanceof Class_; - } - - /** - * @param Class_ $classNode - */ - public function reconstruct(Node $classNode): void - { - foreach ($classNode->stmts as $insideClassNode) { - // 1. Detect method - if (! $insideClassNode instanceof ClassMethod) { - continue; - } - - $methodNode = $insideClassNode; - foreach ($methodNode->stmts as $insideMethodNode) { - $insideMethodNode = $insideMethodNode->expr; - - if ($insideMethodNode instanceof MethodCall && $insideMethodNode->var instanceof MethodCall) { - $this->processOnServiceMethodCall($classNode, $insideMethodNode); - - // B. Find $var = $this->get('...'); - } elseif ($insideMethodNode instanceof Assign) { - $this->processAssignment($classNode, $insideMethodNode); - } - } - } - } - - private function processOnServiceMethodCall(Class_ $classNode, MethodCall $methodCallNode): void - { - if (! $this->isContainerGetCall($methodCallNode)) { - return; - } - - $refactoredMethodCall = $this->processMethodCallNode($classNode, $methodCallNode->var); - if ($refactoredMethodCall) { - $methodCallNode->var = $refactoredMethodCall; - } - } - - private function processAssignment(Class_ $classNode, Assign $assignNode): void - { - if (!$this->isContainerGetCall($assignNode)) { - return; - } - - $this->processMethodCallNode($classNode, $assignNode->expr); - - /*$refactoredMethodCall = */ -// if ($refactoredMethodCall) { -// $assignNode->expr = $refactoredMethodCall; -// } - } - - /** - * Accept only "$this->get('string')" statements. - */ - private function isContainerGetCall(Node $node): bool - { - if ($node instanceof Assign && ($node->expr instanceof MethodCall || $node->var instanceof MethodCall)) { - $methodCall = $node->expr; - } elseif ($node instanceof MethodCall && $node->var instanceof MethodCall) { - $methodCall = $node->var; - } else { - return false; - } - - if ($methodCall->var->name !== 'this') { - return false; - } - - if ((string) $methodCall->name !== 'get') { - return false; - } - - if (! $methodCall->args[0]->value instanceof String_) { - return false; - } - - return true; - } - - private function processMethodCallNode(Class_ $classNode, MethodCall $methodCall): ?PropertyFetch - { - /** @var String_ $argument */ - $argument = $methodCall->args[0]->value; - $serviceName = $argument->value; - - $serviceType = $this->serviceFromKernelResolver->resolveServiceClassByNameFromKernel( - $serviceName, LocalKernel::class - ); - - if ($serviceType === null) { - return null; - } - - // Get property name - $propertyName = $this->nameResolver->resolvePropertyNameFromType($serviceType); - - // Add property assignment to constructor - $this->constructorMethodBuilder->addPropertyAssignToClass($classNode, $serviceType, $propertyName); - - // 5. Add property to class - $this->propertyBuilder->addPropertyToClass($classNode, $serviceType, $propertyName); - - // creates "$this->propertyName" -// return new PropertyFetch( -// new Variable('this', [ -// 'name' => $propertyName -// ]), $propertyName -// ); - - return null; - - } - - /** - * Called when entering a node. - * - * Return value semantics: - * * null - * => $node stays as-is - * * NodeTraverser::DONT_TRAVERSE_CHILDREN - * => Children of $node are not traversed. $node stays as-is - * * NodeTraverser::STOP_TRAVERSAL - * => Traversal is aborted. $node stays as-is - * * otherwise - * => $node is set to the return value - * - * @param Node $node Node - * - * @return null|int|Node Replacement node (or special return value) - */ - public function enterNode(Node $node) - { - if ($this->isCandidate($node)) { - $this->reconstruct($node); - } - - return null; - } -} diff --git a/src/config/services.yml b/src/config/services.yml index af4446ad185..526168dd2ed 100644 --- a/src/config/services.yml +++ b/src/config/services.yml @@ -1,3 +1,7 @@ +parameters: + # todo + kernel_class: # for name based service refactoring + services: _defaults: autowire: true diff --git a/tests/NodeVisitor/DependencyInjection/NamedServicesToConstructorReconstructor/Test.php b/tests/NodeVisitor/DependencyInjection/NamedServicesToConstructorReconstructor/Test.php index 5d2586030dd..361c063516e 100644 --- a/tests/NodeVisitor/DependencyInjection/NamedServicesToConstructorReconstructor/Test.php +++ b/tests/NodeVisitor/DependencyInjection/NamedServicesToConstructorReconstructor/Test.php @@ -2,7 +2,6 @@ namespace Rector\Tests\NodeVisitor\DependencyInjection\NamedServicesToConstructorReconstructor; -use Rector\NodeVisitor\DependencyInjection\NamedServicesToConstructor\NamedServicesToConstructorNodeVisitor; use Rector\Testing\PHPUnit\AbstractReconstructorTestCase; final class Test extends AbstractReconstructorTestCase @@ -13,9 +12,4 @@ final class Test extends AbstractReconstructorTestCase $this->doTestFileMatchesExpectedContent(__DIR__ . '/wrong/wrong2.php.inc', __DIR__ . '/correct/correct2.php.inc'); // $this->doTestFileMatchesExpectedContent(__DIR__ . '/wrong/wrong3.php.inc', __DIR__ . '/correct/correct3.php.inc'); } - - protected function getNodeVisitorClass(): string - { - return NamedServicesToConstructorNodeVisitor::class; - } } diff --git a/tests/NodeVisitor/DependencyInjection/NamedServicesToConstructorReconstructor/correct/correct.php.inc b/tests/NodeVisitor/DependencyInjection/NamedServicesToConstructorReconstructor/correct/correct.php.inc index 21c523e32ef..31dadc890f4 100644 --- a/tests/NodeVisitor/DependencyInjection/NamedServicesToConstructorReconstructor/correct/correct.php.inc +++ b/tests/NodeVisitor/DependencyInjection/NamedServicesToConstructorReconstructor/correct/correct.php.inc @@ -1,6 +1,6 @@