Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ services:
# Model to Doctrine
Rector\CakePHPToSymfony\Rector\Class_\CakePHPModelToDoctrineEntityRector: null
Rector\CakePHPToSymfony\Rector\Class_\CakePHPModelToDoctrineRepositoryRector: null
Rector\CakePHPToSymfony\Rector\Class_\CakePHPImplicitRouteToExplicitRouteAnnotationRector: null
25 changes: 24 additions & 1 deletion docs/AllRectorsOverview.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# All 444 Rectors Overview
# All 445 Rectors Overview

- [Projects](#projects)
- [General](#general)
Expand Down Expand Up @@ -422,6 +422,29 @@ Migrate CakePHP 2.4 Controller to Symfony 5

<br>

### `CakePHPImplicitRouteToExplicitRouteAnnotationRector`

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

Migrate CakePHP implicit routes to Symfony @route annotations

```diff
-class PaymentsController extends AppController
+use Symfony\Component\Routing\Annotation\Route;
+
+class AdminPaymentsController extends AppController
{
+ /**
+ * @Route(path="/payments/index", name="payments_index")
+ */
public function index()
{
}
}
```

<br>

### `CakePHPModelToDoctrineEntityRector`

- class: `Rector\CakePHPToSymfony\Rector\Class_\CakePHPModelToDoctrineEntityRector`
Expand Down
6 changes: 5 additions & 1 deletion ecs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ parameters:
PHP_CodeSniffer\Standards\PSR2\Sniffs\Methods\MethodDeclarationSniff.Underscore: null
Symplify\CodingStandard\Sniffs\Architecture\DuplicatedClassShortNameSniff: null
# skip temporary due to missing "import" feature in PhpStorm
SlevomatCodingStandard\Sniffs\Namespaces\ReferenceUsedNamesOnlySniff.PartialUse: null
# SlevomatCodingStandard\Sniffs\Namespaces\ReferenceUsedNamesOnlySniff.PartialUse: null

# run manually from time to time - performance demanding + not to bother user with it
Symplify\CodingStandard\Fixer\Order\PropertyOrderByComplexityFixer: null
Expand Down Expand Up @@ -173,4 +173,8 @@ parameters:
# part of the comparison logic
- 'packages/Polyfill/src/ConditionEvaluator.php'

SlevomatCodingStandard\Sniffs\Namespaces\ReferenceUsedNamesOnlySniff.PartialUse:
- "packages/DeadCode/src/Rector/Plus/RemoveDeadZeroAndOneOperationRector.php"
- "packages/Php56/src/Rector/FunctionLike/AddDefaultValueForUndefinedVariableRector.php"

line_ending: "\n"
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public function printFormatPreserving(PhpDocInfo $phpDocInfo, bool $shouldSkipEm
return $this->printPhpDocNode($this->attributeAwarePhpDocNode, $shouldSkipEmptyLinesAbove);
}

public function printPhpDocNode(
private function printPhpDocNode(
AttributeAwarePhpDocNode $attributeAwarePhpDocNode,
bool $shouldSkipEmptyLinesAbove = false
): string {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?php

declare(strict_types=1);

namespace Rector\CakePHPToSymfony\Rector\Class_;

use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\BetterPhpDocParser\PhpDocNode\Symfony\SymfonyRouteTagValueNode;
use Rector\CakePHPToSymfony\Rector\AbstractCakePHPRector;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PHPStan\Type\FullyQualifiedObjectType;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
use Rector\Util\RectorStrings;

/**
* @inspiration
* @see \Rector\NetteToSymfony\Rector\ClassMethod\RouterListToControllerAnnotationsRector
*
* @see \Rector\CakePHPToSymfony\Tests\Rector\Class_\CakePHPImplicitRouteToExplicitRouteAnnotationRector\CakePHPImplicitRouteToExplicitRouteAnnotationRectorTest
*/
final class CakePHPImplicitRouteToExplicitRouteAnnotationRector extends AbstractCakePHPRector
{
/**
* @var string
*/
private const HAS_FRESH_ROUTE_ANNOTATION_ATTRIBUTE = 'has_fresh_route_annotation';

public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Migrate CakePHP implicit routes to Symfony @route annotations', [
new CodeSample(
<<<'PHP'
class PaymentsController extends AppController
{
public function index()
{
}
}
PHP
,
<<<'PHP'
use Symfony\Component\Routing\Annotation\Route;

class AdminPaymentsController extends AppController
{
/**
* @Route(path="/payments/index", name="payments_index")
*/
public function index()
{
}
}
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;
}

foreach ($node->getMethods() as $classMethod) {
if (! $classMethod->isPublic()) {
continue;
}

/** @var string $className */
$className = $node->getAttribute(AttributeKey::CLASS_NAME);
$shortClassName = $this->getShortName($className);

$methodName = $this->getName($classMethod);

$combined = RectorStrings::removeSuffixes($shortClassName, ['Controller']) . '/' . $methodName;
$path = '/' . RectorStrings::camelCaseToSlashes($combined);
$name = RectorStrings::camelCaseToUnderscore($combined);

$symfonyRoutePhpDocTagValueNode = $this->createSymfonyRoutePhpDocTagValueNode($path, $name);
$this->addSymfonyRouteShortTagNodeWithUse($symfonyRoutePhpDocTagValueNode, $classMethod);
}

return $node;
}

private function createSymfonyRoutePhpDocTagValueNode(string $path, string $name): SymfonyRouteTagValueNode
{
return new SymfonyRouteTagValueNode($path, $name);
}

/**
* @todo reuse from RouterListToControllerAnnotationsRector
*/
private function addSymfonyRouteShortTagNodeWithUse(
SymfonyRouteTagValueNode $symfonyRouteTagValueNode,
ClassMethod $classMethod
): void {
// @todo use empty phpdoc info
$this->docBlockManipulator->addTagValueNodeWithShortName($classMethod, $symfonyRouteTagValueNode);

$symfonyRouteUseObjectType = new FullyQualifiedObjectType(SymfonyRouteTagValueNode::CLASS_NAME);
$this->addUseType($symfonyRouteUseObjectType, $classMethod);

$classMethod->setAttribute(self::HAS_FRESH_ROUTE_ANNOTATION_ATTRIBUTE, true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace Rector\CakePHPToSymfony\Tests\Rector\Class_\CakePHPImplicitRouteToExplicitRouteAnnotationRector;

use Iterator;
use Rector\CakePHPToSymfony\Rector\Class_\CakePHPImplicitRouteToExplicitRouteAnnotationRector;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

final class CakePHPImplicitRouteToExplicitRouteAnnotationRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideDataForTest()
*/
public function test(string $file): void
{
$this->doTestFile($file);
}

public function provideDataForTest(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}

protected function getRectorClass(): string
{
return CakePHPImplicitRouteToExplicitRouteAnnotationRector::class;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Rector\CakePHPToSymfony\Tests\Rector\Class_\CakePHPImplicitRouteToExplicitRouteAnnotationRector\Fixture;

class PaymentsController extends \AppController
{
public function index()
{
}
}

?>
-----
<?php

namespace Rector\CakePHPToSymfony\Tests\Rector\Class_\CakePHPImplicitRouteToExplicitRouteAnnotationRector\Fixture;

use Symfony\Component\Routing\Annotation\Route;
class PaymentsController extends \AppController
{
/**
* @Route(path="/payments/index", name="payments_index")
*/
public function index()
{
}
}

?>
2 changes: 1 addition & 1 deletion packages/CodeQuality/src/Rector/If_/CombineIfRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public function refactor(Node $node): ?Node
return null;
}

/** @var Node\Stmt\If_ $subIf */
/** @var If_ $subIf */
$subIf = $node->stmts[0];
$node->cond = new BooleanAnd($node->cond, $subIf->cond);
$node->stmts = $subIf->stmts;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\ClassMethod;
Expand Down Expand Up @@ -205,7 +206,7 @@ private function resolvePropertyFetchType(PropertyFetch $propertyFetch): Type
}

/**
* @param Node\Stmt[] $stmts
* @param Stmt[] $stmts
*/
private function resolveAssignedTypeInStmtsByPropertyName(array $stmts, string $propertyName): ?Type
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use PhpParser\Node;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Return_;
use PHPStan\Analyser\Scope;
Expand Down Expand Up @@ -139,7 +140,7 @@ private function isConstructorWithStaticFactory(ClassMethod $classMethod, string
return false;
}

/** @var Node\Stmt\Class_|null $class */
/** @var Class_|null $class */
$class = $classMethod->getAttribute(AttributeKey::CLASS_NODE);
if ($class === null) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@ public function getNodeTypes(): array
Minus::class,
Mul::class,
Div::class,
Node\Expr\AssignOp\Plus::class,
Node\Expr\AssignOp\Minus::class,
Node\Expr\AssignOp\Mul::class,
Node\Expr\AssignOp\Div::class,
AssignOp\Plus::class,
AssignOp\Minus::class,
AssignOp\Mul::class,
AssignOp\Div::class,
];
}

Expand Down Expand Up @@ -106,7 +106,7 @@ public function refactor(Node $node): ?Node
private function processAssignOp(Node $node): ?Expr
{
// +=, -=
if ($node instanceof Node\Expr\AssignOp\Plus || $node instanceof Node\Expr\AssignOp\Minus) {
if ($node instanceof AssignOp\Plus || $node instanceof AssignOp\Minus) {
if (! $this->isValue($node->expr, 0)) {
return null;
}
Expand All @@ -117,7 +117,7 @@ private function processAssignOp(Node $node): ?Expr
}

// *, /
if ($node instanceof Node\Expr\AssignOp\Mul || $node instanceof Node\Expr\AssignOp\Div) {
if ($node instanceof AssignOp\Mul || $node instanceof AssignOp\Div) {
if (! $this->isValue($node->expr, 1)) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ private function transformConcatExpressionToSingleString(Concat $concat): ?strin
} elseif ($expressionPart instanceof Concat) {
$output .= $this->transformConcatExpressionToSingleString($expressionPart);
} elseif ($expressionPart instanceof ClassConstFetch) {
/** @var Node\Name $name */
/** @var Name $name */
$name = $expressionPart->class->getAttribute('originalName');

$output .= implode('\\', $name->parts);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Exception\ShouldNotHappenException;
use Rector\Laravel\FunctionToServiceMap;
use Rector\Laravel\ValueObject\ArrayFunctionToMethodCall;
Expand Down Expand Up @@ -144,7 +145,7 @@ private function shouldSkipFuncCall(FuncCall $funcCall): bool
return true;
}

/** @var Node\Stmt\ClassMethod|null $classMethod */
/** @var ClassMethod|null $classMethod */
$classMethod = $funcCall->getAttribute(AttributeKey::METHOD_NODE);
if ($classMethod === null) {
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ final class FunctionMethodAndClassNodeVisitor extends NodeVisitorAbstract
private $methodNode;

/**
* @var Node\Stmt\Function_|null
* @var Function_|null
*/
private $functionNode;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public function getNodeClasses(): array
}

/**
* @param Node\Expr\Cast $node
* @param Cast $node
*/
public function resolve(Node $node): Type
{
Expand Down
Loading