Skip to content

Commit

Permalink
Merge 56b2cc2 into e945600
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed Jan 18, 2020
2 parents e945600 + 56b2cc2 commit 3c64137
Show file tree
Hide file tree
Showing 33 changed files with 1,554 additions and 126 deletions.
9 changes: 6 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@
"Rector\\Phalcon\\": "packages/Phalcon/src",
"Rector\\DoctrineGedmoToKnplabs\\": "packages/DoctrineGedmoToKnplabs/src",
"Rector\\MinimalScope\\": "packages/MinimalScope/src",
"Rector\\Polyfill\\": "packages/Polyfill/src"
"Rector\\Polyfill\\": "packages/Polyfill/src",
"Rector\\CakePHPToSymfony\\": "packages/CakePHPToSymfony/src"
}
},
"autoload-dev": {
Expand Down Expand Up @@ -174,7 +175,8 @@
"Rector\\DoctrineGedmoToKnplabs\\Tests\\": "packages/DoctrineGedmoToKnplabs/tests",
"Rector\\MinimalScope\\Tests\\": "packages/MinimalScope/tests",
"Rector\\Utils\\PHPStanStaticTypeMapperChecker\\": "utils/PHPStanStaticTypeMapperChecker/src",
"Rector\\Polyfill\\Tests\\": "packages/Polyfill/tests"
"Rector\\Polyfill\\Tests\\": "packages/Polyfill/tests",
"Rector\\CakePHPToSymfony\\Tests\\": "packages/CakePHPToSymfony/tests"
},
"classmap": [
"packages/CakePHP/tests/Rector/Name/ImplicitShortClassNameUseStatementRector/Source",
Expand All @@ -188,7 +190,8 @@
"tests/Issues/Issue1243/Source",
"packages/Autodiscovery/tests/Rector/FileSystem/MoveInterfacesToContractNamespaceDirectoryRector/Expected",
"packages/Autodiscovery/tests/Rector/FileSystem/MoveServicesBySuffixToDirectoryRector/Expected",
"packages/CakePHP/tests/Rector/StaticCall/AppUsesStaticCallToUseStatementRector/Source"
"packages/CakePHP/tests/Rector/StaticCall/AppUsesStaticCallToUseStatementRector/Source",
"packages/CakePHPToSymfony/tests/Rector/Class_/CakePHPControllerComponentToSymfonyRector/Source"
],
"files": [
"packages/DeadCode/tests/Rector/MethodCall/RemoveDefaultArgumentValueRector/Source/UserDefined.php",
Expand Down
7 changes: 7 additions & 0 deletions config/set/cakephp-to-symfony/cakephp-24-to-symfony-50.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
services:
Rector\CakePHPToSymfony\Rector\Class_\CakePHPControllerToSymfonyControllerRector: null
Rector\CakePHPToSymfony\Rector\ClassMethod\CakePHPControllerActionToSymfonyControllerActionRector: null
Rector\CakePHPToSymfony\Rector\Class_\CakePHPControllerHelperToSymfonyRector: null
Rector\CakePHPToSymfony\Rector\Class_\CakePHPControllerComponentToSymfonyRector: null
Rector\CakePHPToSymfony\Rector\Class_\CakePHPControllerRedirectToSymfonyRector: null
Rector\CakePHPToSymfony\Rector\ClassMethod\CakePHPControllerRedirectToSymfonyRector: null
109 changes: 107 additions & 2 deletions docs/AllRectorsOverview.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# All 432 Rectors Overview
# All 436 Rectors Overview

- [Projects](#projects)
- [General](#general)
Expand All @@ -8,6 +8,7 @@
- [Architecture](#architecture)
- [Autodiscovery](#autodiscovery)
- [CakePHP](#cakephp)
- [CakePHPToSymfony](#cakephptosymfony)
- [Celebrity](#celebrity)
- [CodeQuality](#codequality)
- [CodingStyle](#codingstyle)
Expand Down Expand Up @@ -283,6 +284,110 @@ services:

<br>

## CakePHPToSymfony

### `CakePHPControllerActionToSymfonyControllerActionRector`

- class: `Rector\CakePHPToSymfony\Rector\ClassMethod\CakePHPControllerActionToSymfonyControllerActionRector`

Migrate CakePHP 2.4 Controller action to Symfony 5

```diff
+use Symfony\Component\HttpFoundation\Response;
+
class HomepageController extends \AppController
{
- public function index()
+ public function index(): Response
{
$value = 5;
- $this->set('name', $value);
+ return $this->renderResponse('homepage/index.twig', [
+ 'name' => $value
+ ]);
}
}
```

<br>

### `CakePHPControllerComponentToSymfonyRector`

- class: `Rector\CakePHPToSymfony\Rector\Class_\CakePHPControllerComponentToSymfonyRector`

Migrate CakePHP 2.4 Controller $components property to Symfony 5

```diff
class MessagesController extends \AppController
{
- public $components = ['Overview'];
+ private function __construct(OverviewComponent $overviewComponent)
+ {
+ $this->overviewComponent->filter();
+ }

public function someAction()
{
- $this->Overview->filter();
+ $this->overviewComponent->filter();
}
}

class OverviewComponent extends \Component
{
public function filter()
{
}
}
```

<br>

### `CakePHPControllerHelperToSymfonyRector`

- class: `Rector\CakePHPToSymfony\Rector\Class_\CakePHPControllerHelperToSymfonyRector`

Migrate CakePHP 2.4 Controller $helpers and $components property to Symfony 5

```diff
class HomepageController extends AppController
{
- public $helpers = ['Flash'];
-
public function index()
{
- $this->Flash->success(__('Your post has been saved.'));
- $this->Flash->error(__('Unable to add your post.'));
+ $this->addFlash('success', __('Your post has been saved.'));
+ $this->addFlash('error', __('Unable to add your post.'));
}
}
```

<br>

### `CakePHPControllerToSymfonyControllerRector`

- class: `Rector\CakePHPToSymfony\Rector\Class_\CakePHPControllerToSymfonyControllerRector`

Migrate CakePHP 2.4 Controller to Symfony 5

```diff
-class HomepageController extends AppController
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
+
+class HomepageController extends AbstractController
{
- public function index()
+ public function index(): Response
{
}
}
```

<br>

## Celebrity

### `CommonNotEqualRector`
Expand Down Expand Up @@ -8724,7 +8829,7 @@ services:
Rector\Rector\Visibility\ChangeMethodVisibilityRector:
$methodToVisibilityByClass:
FrameworkClass:
someMethod: protected
someMethod: protected
```

Expand Down
9 changes: 9 additions & 0 deletions packages/CakePHPToSymfony/config/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
services:
_defaults:
autowire: true
public: true

Rector\CakePHPToSymfony\:
resource: '../src'
exclude:
- '../src/Rector/**/*Rector.php'
26 changes: 26 additions & 0 deletions packages/CakePHPToSymfony/src/Rector/AbstractCakePHPRector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace Rector\CakePHPToSymfony\Rector;

use PhpParser\Node;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Rector\AbstractRector;

abstract class AbstractCakePHPRector extends AbstractRector
{
protected function isInCakePHPController(Node $node): bool
{
if ($this->isObjectType($node, 'AppController')) {
return true;
}

$class = $node->getAttribute(AttributeKey::CLASS_NODE);
if ($class !== null) {
return true;
}

return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
<?php

declare(strict_types=1);

namespace Rector\CakePHPToSymfony\Rector\ClassMethod;

use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Return_;
use Rector\CakePHPToSymfony\Rector\AbstractCakePHPRector;
use Rector\CakePHPToSymfony\Rector\TemplatePathResolver;
use Rector\CodeQuality\CompactConverter;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;

/**
* @see https://book.cakephp.org/2/en/tutorials-and-examples/blog/part-two.html
* @see https://symfony.com/doc/5.0/controller.html
* @see https://symfony.com/doc/5.0/controller.html#rendering-templates
*
* @see https://stackoverflow.com/a/21647715/1348344 for $this->view
*
* @see \Rector\CakePHPToSymfony\Tests\Rector\ClassMethod\CakePHPControllerActionToSymfonyControllerActionRector\CakePHPControllerActionToSymfonyControllerActionRectorTest
*/
final class CakePHPControllerActionToSymfonyControllerActionRector extends AbstractCakePHPRector
{
/**
* @var CompactConverter
*/
private $compactConverter;

/**
* @var TemplatePathResolver
*/
private $templatePathResolver;

public function __construct(CompactConverter $compactConverter, TemplatePathResolver $templatePathResolver)
{
$this->compactConverter = $compactConverter;
$this->templatePathResolver = $templatePathResolver;
}

public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Migrate CakePHP 2.4 Controller action to Symfony 5', [
new CodeSample(
<<<'PHP'
class HomepageController extends \AppController
{
public function index()
{
$value = 5;
$this->set('name', $value);
}
}
PHP
,
<<<'PHP'
use Symfony\Component\HttpFoundation\Response;
class HomepageController extends \AppController
{
public function index(): Response
{
$value = 5;
return $this->renderResponse('homepage/index.twig', [
'name' => $value
]);
}
}
PHP

),
]);
}

/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [ClassMethod::class];
}

/**
* @param ClassMethod $node
*/
public function refactor(Node $node): ?Node
{
if (! $this->isInCakePHPController($node)) {
return null;
}

if (! $node->isPublic()) {
return null;
}

$methodCall = $this->createThisRenderMethodCall($node);
$return = new Return_($methodCall);
$node->stmts[] = $return;

$node->returnType = new FullyQualified('Symfony\Component\HttpFoundation\Response');

return $node;
}

/**
* @return Arg[][]
*/
private function collectAndRemoveSetMethodCallArgs(array $stmts): array
{
$setMethodCallArgs = [];

$this->traverseNodesWithCallable($stmts, function (Node $node) use (&$setMethodCallArgs) {
if (! $node instanceof MethodCall) {
return null;
}

if (! $this->isName($node->name, 'set')) {
return null;
}

$setMethodCallArgs[] = $node->args;
$this->removeNode($node);

return null;
});

return $setMethodCallArgs;
}

/**
* @param Arg[][] $setValues
*/
private function createArrayFromSetValues(array $setValues): Array_
{
$arrayItems = [];

foreach ($setValues as $setValue) {
if (count($setValue) > 1) {
$arrayItems[] = new ArrayItem($setValue[1]->value, $setValue[0]->value);
} elseif ($this->isCompactFuncCall($setValue[0]->value)) {
/** @var FuncCall $compactFuncCall */
$compactFuncCall = $setValue[0]->value;

return $this->compactConverter->convertToArray($compactFuncCall);
}
}

return new Array_($arrayItems);
}

private function isCompactFuncCall(Node $node): bool
{
if (! $node instanceof FuncCall) {
return false;
}

return $this->isName($node, 'compact');
}

/**
* Creates "$this->render('...', [...])";
*/
private function createThisRenderMethodCall(ClassMethod $classMethod): MethodCall
{
$thisVariable = new Variable('this');
$thisRenderMethodCall = new MethodCall($thisVariable, 'render');

$templateName = $this->templatePathResolver->resolveForClassMethod($classMethod);
$thisRenderMethodCall->args[] = new Arg(new String_($templateName));

$setValues = $this->collectAndRemoveSetMethodCallArgs((array) $classMethod->stmts);

if ($setValues !== []) {
$parametersArray = $this->createArrayFromSetValues($setValues);
$thisRenderMethodCall->args[] = new Arg($parametersArray);
}

return $thisRenderMethodCall;
}
}

0 comments on commit 3c64137

Please sign in to comment.