From 056833adffbba8db94b8736600a8742b02f93c6d Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Sun, 3 Nov 2019 19:10:23 +0100 Subject: [PATCH] add template nested --- .../TemplateAnnotationRector.php | 114 ++++++++++++------ .../resolve_another_method_call.php.inc | 50 ++++++++ .../TemplateAnnotationVersion3RectorTest.php | 1 + 3 files changed, 129 insertions(+), 36 deletions(-) create mode 100755 packages/Sensio/tests/Rector/FrameworkExtraBundle/TemplateAnnotationRector/Fixture/Version3/resolve_another_method_call.php.inc diff --git a/packages/Sensio/src/Rector/FrameworkExtraBundle/TemplateAnnotationRector.php b/packages/Sensio/src/Rector/FrameworkExtraBundle/TemplateAnnotationRector.php index 17d5e7c0b78b..cfe111776883 100644 --- a/packages/Sensio/src/Rector/FrameworkExtraBundle/TemplateAnnotationRector.php +++ b/packages/Sensio/src/Rector/FrameworkExtraBundle/TemplateAnnotationRector.php @@ -13,6 +13,7 @@ use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Return_; use Rector\BetterPhpDocParser\PhpDocNode\Sensio\SensioTemplateTagValueNode; +use Rector\NodeContainer\ParsedNodesByType; use Rector\Rector\AbstractRector; use Rector\RectorDefinition\CodeSample; use Rector\RectorDefinition\RectorDefinition; @@ -31,9 +32,18 @@ final class TemplateAnnotationRector extends AbstractRector */ private $templateGuesser; - public function __construct(TemplateGuesser $templateGuesser, int $version = 3) - { + /** + * @var ParsedNodesByType + */ + private $parsedNodesByType; + + public function __construct( + TemplateGuesser $templateGuesser, + ParsedNodesByType $parsedNodesByType, + int $version = 3 + ) { $this->templateGuesser = $templateGuesser; + $this->parsedNodesByType = $parsedNodesByType; $this->version = $version; } @@ -74,7 +84,7 @@ public function getNodeTypes(): array public function refactor(Node $node): ?Node { if ($node instanceof Class_) { - return $this->addBaseClassIfMissing($node); + return $this->addAbstractControllerParentClassIfMissing($node); } if ($node instanceof ClassMethod) { @@ -84,7 +94,7 @@ public function refactor(Node $node): ?Node return null; } - private function addBaseClassIfMissing(Class_ $node): ?Node + private function addAbstractControllerParentClassIfMissing(Class_ $node): ?Class_ { if ($node->extends !== null) { return null; @@ -101,14 +111,13 @@ private function addBaseClassIfMissing(Class_ $node): ?Node private function classHasTemplateAnnotations(Class_ $node): bool { - foreach ($node->stmts as $stmtNode) { - $phpDocInfo = $this->getPhpDocInfo($stmtNode); + foreach ($node->getMethods() as $classMethod) { + $phpDocInfo = $this->getPhpDocInfo($classMethod); if ($phpDocInfo === null) { continue; } - $templateTagValueNode = $phpDocInfo->getByType(SensioTemplateTagValueNode::class); - if ($templateTagValueNode !== null) { + if ((bool) $phpDocInfo->getByType(SensioTemplateTagValueNode::class)) { return true; } } @@ -118,32 +127,13 @@ private function classHasTemplateAnnotations(Class_ $node): bool private function replaceTemplateAnnotation(ClassMethod $classMethod): ?Node { - $phpDocInfo = $this->getPhpDocInfo($classMethod); - if ($phpDocInfo === null) { + /** @var SensioTemplateTagValueNode|null $sensioTemplateTagValueNode */ + $sensioTemplateTagValueNode = $this->getSensioTemplateTagValueNode($classMethod); + if ($sensioTemplateTagValueNode === null) { return null; } - $templateTagValueNode = $phpDocInfo->getByType(SensioTemplateTagValueNode::class); - if ($templateTagValueNode === null) { - return null; - } - - /** @var Return_|null $returnNode */ - $returnNode = $this->betterNodeFinder->findLastInstanceOf((array) $classMethod->stmts, Return_::class); - - // create "$this->render('template.file.twig.html', ['key' => 'value']);" method call - $renderArguments = $this->resolveRenderArguments($classMethod, $returnNode, $templateTagValueNode); - $thisRenderMethodCall = $this->createMethodCall('this', 'render', $renderArguments); - - if ($returnNode === null) { - // or add as last statement in the method - $classMethod->stmts[] = new Return_($thisRenderMethodCall); - } - - // replace Return_ node value if exists and is not already in correct format - if ($returnNode && ! $returnNode->expr instanceof MethodCall) { - $returnNode->expr = $thisRenderMethodCall; - } + $this->refactorClassMethod($classMethod, $sensioTemplateTagValueNode); // remove annotation $this->docBlockManipulator->removeTagFromNode($classMethod, SensioTemplateTagValueNode::class); @@ -156,20 +146,20 @@ private function replaceTemplateAnnotation(ClassMethod $classMethod): ?Node */ private function resolveRenderArguments( ClassMethod $classMethod, - ?Return_ $returnNode, + ?Return_ $return, SensioTemplateTagValueNode $sensioTemplateTagValueNode ): array { $arguments = [$this->resolveTemplateName($classMethod, $sensioTemplateTagValueNode)]; - if ($returnNode === null) { + if ($return === null) { return $this->createArgs($arguments); } - if ($returnNode->expr instanceof Array_ && count($returnNode->expr->items)) { - $arguments[] = $returnNode->expr; + if ($return->expr instanceof Array_ && count($return->expr->items)) { + $arguments[] = $return->expr; } - $arguments = array_merge($arguments, $this->resolveArrayArgumentsFromMethodCall($returnNode)); + $arguments = array_merge($arguments, $this->resolveArrayArgumentsFromMethodCall($return)); return $this->createArgs($arguments); } @@ -207,4 +197,56 @@ private function resolveArrayArgumentsFromMethodCall(Return_ $returnNode): array return $arguments; } + + private function createThisRender( + ClassMethod $classMethod, + ?Return_ $return, + SensioTemplateTagValueNode $sensioTemplateTagValueNode + ): MethodCall { + $renderArguments = $this->resolveRenderArguments($classMethod, $return, $sensioTemplateTagValueNode); + + return $this->createMethodCall('this', 'render', $renderArguments); + } + + private function refactorClassMethod( + ClassMethod $classMethod, + SensioTemplateTagValueNode $sensioTemplateTagValueNode + ): void { + /** @var Return_|null $returnNode */ + $returnNode = $this->betterNodeFinder->findLastInstanceOf((array) $classMethod->stmts, Return_::class); + + if ($returnNode !== null) { + if ($returnNode->expr instanceof MethodCall) { + // go inside called method + $innerClassMethod = $this->parsedNodesByType->findClassMethodByMethodCall($returnNode->expr); + if ($innerClassMethod !== null) { + $this->refactorClassMethod($innerClassMethod, $sensioTemplateTagValueNode); + return; + } + } + } + + // create "$this->render('template.file.twig.html', ['key' => 'value']);" method call + $thisRenderMethodCall = $this->createThisRender($classMethod, $returnNode, $sensioTemplateTagValueNode); + + if ($returnNode === null) { + // or add as last statement in the method + $classMethod->stmts[] = new Return_($thisRenderMethodCall); + } + + // replace Return_ node value if exists and is not already in correct format + if ($returnNode && ! $returnNode->expr instanceof MethodCall) { + $returnNode->expr = $thisRenderMethodCall; + } + } + + private function getSensioTemplateTagValueNode(ClassMethod $classMethod): ?SensioTemplateTagValueNode + { + $phpDocInfo = $this->getPhpDocInfo($classMethod); + if ($phpDocInfo === null) { + return null; + } + + return $phpDocInfo->getByType(SensioTemplateTagValueNode::class); + } } diff --git a/packages/Sensio/tests/Rector/FrameworkExtraBundle/TemplateAnnotationRector/Fixture/Version3/resolve_another_method_call.php.inc b/packages/Sensio/tests/Rector/FrameworkExtraBundle/TemplateAnnotationRector/Fixture/Version3/resolve_another_method_call.php.inc new file mode 100755 index 000000000000..9cac7c7e1f2d --- /dev/null +++ b/packages/Sensio/tests/Rector/FrameworkExtraBundle/TemplateAnnotationRector/Fixture/Version3/resolve_another_method_call.php.inc @@ -0,0 +1,50 @@ +processForm($request); + } + + private function processForm(Request $request): array + { + return [ + 'form' => $request, + ]; + } +} + +?> +----- +processForm($request); + } + + private function processForm(Request $request): array + { + return $this->render('PAPPSurveyBundle:Survey:create.html.twig', [ + 'form' => $request, + ]); + } +} + +?> diff --git a/packages/Sensio/tests/Rector/FrameworkExtraBundle/TemplateAnnotationRector/TemplateAnnotationVersion3RectorTest.php b/packages/Sensio/tests/Rector/FrameworkExtraBundle/TemplateAnnotationRector/TemplateAnnotationVersion3RectorTest.php index 67fcb3a2f5b5..2def0110261f 100644 --- a/packages/Sensio/tests/Rector/FrameworkExtraBundle/TemplateAnnotationRector/TemplateAnnotationVersion3RectorTest.php +++ b/packages/Sensio/tests/Rector/FrameworkExtraBundle/TemplateAnnotationRector/TemplateAnnotationVersion3RectorTest.php @@ -25,6 +25,7 @@ public function provideDataForTest(): Iterator yield [__DIR__ . '/Fixture/Version3/fixture3.php.inc']; yield [__DIR__ . '/Fixture/Version3/fixture4.php.inc']; yield [__DIR__ . '/Fixture/Version3/skip_just_template.php.inc']; + yield [__DIR__ . '/Fixture/Version3/resolve_another_method_call.php.inc']; } /**