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
2 changes: 2 additions & 0 deletions .phpstorm.meta.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
\Rector\NodeTypeResolver\Node\AttributeKey::IS_UNREACHABLE,
\Rector\NodeTypeResolver\Node\AttributeKey::PHP_DOC_INFO,
\Rector\NodeTypeResolver\Node\AttributeKey::KIND,
\Rector\NodeTypeResolver\Node\AttributeKey::CLASS_SHORT_NAME,
);

expectedArguments(
Expand All @@ -65,4 +66,5 @@
\Rector\NodeTypeResolver\Node\AttributeKey::IS_UNREACHABLE,
\Rector\NodeTypeResolver\Node\AttributeKey::PHP_DOC_INFO,
\Rector\NodeTypeResolver\Node\AttributeKey::KIND,
\Rector\NodeTypeResolver\Node\AttributeKey::CLASS_SHORT_NAME,
);
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ services:
Rector\CakePHPToSymfony\Rector\Class_\CakePHPModelToDoctrineEntityRector: null
Rector\CakePHPToSymfony\Rector\Class_\CakePHPModelToDoctrineRepositoryRector: null
Rector\CakePHPToSymfony\Rector\Class_\CakePHPImplicitRouteToExplicitRouteAnnotationRector: null
Rector\CakePHPToSymfony\Rector\Class_\CakePHPBeforeFilterToRequestEventSubscriberRector: null
39 changes: 24 additions & 15 deletions docs/AllRectorsOverview.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# All 445 Rectors Overview
# All 446 Rectors Overview

- [Projects](#projects)
- [General](#general)
Expand Down Expand Up @@ -286,6 +286,24 @@ services:

## CakePHPToSymfony

### `CakePHPBeforeFilterToRequestEventSubscriberRector`

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

Migrate CakePHP beforeFilter() method from controller to Event Subscriber before request

```diff
class SuperadminController extends \AppController
{
- public function beforeFilter()
- {
- // something
- }
}
```

<br>

### `CakePHPControllerActionToSymfonyControllerActionRector`

- class: `Rector\CakePHPToSymfony\Rector\ClassMethod\CakePHPControllerActionToSymfonyControllerActionRector`
Expand Down Expand Up @@ -4178,24 +4196,15 @@ Change Form that extends Control to Controller and decoupled FormType
+ $form->handleRequest($request);

- $form->onSuccess[] = [$this, 'processForm'];
- }
-
- public function processForm(Form $form)
- {
- // process me
+ if ($form->isSuccess() && $form->isValid()) {
+ // process me
+ }
}
+}

- public function processForm(Form $form)
- {
- // process me
- }
+class SomeFormType extends \Symfony\Component\Form\AbstractType
+{
+ public function buildForm(\Symfony\Component\Form\FormBuilderInterface $formBuilder, array $options)
+ {
+ $formBuilder->add('name', \Symfony\Component\Form\Extension\Core\Type\TextType::class, [
+ 'label' => 'Your name'
+ ]);
+ }
}
```

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php

declare(strict_types=1);

namespace Rector\CakePHPToSymfony\NodeFactory;

use PhpParser\BuilderFactory;
use PhpParser\Node;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Namespace_;
use PhpParser\Node\Stmt\Return_;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Symplify\SmartFileSystem\SmartFileInfo;

final class EventSubscriberClassFactory
{
/**
* @var BuilderFactory
*/
private $builderFactory;

public function __construct(BuilderFactory $builderFactory)
{
$this->builderFactory = $builderFactory;
}

/**
* @return Namespace_|Class_
*/
public function createEventSubscriberClass(Class_ $class, ClassMethod $onBeforeFilterClassMethod): Node
{
$eventSubscriberClassName = $this->createEventSubscriberClassName($class);

$classBuilder = $this->builderFactory->class($eventSubscriberClassName);
$classBuilder->implement(new FullyQualified('Symfony\Component\EventDispatcher\EventSubscriberInterface'));
$classBuilder->makeFinal();

$classBuilder->addStmt($this->createGetSubscribedEventsClassMethod());
$classBuilder->addStmt($this->createOnKernelRequestClassMethod($onBeforeFilterClassMethod));

$eventSubscriberClass = $classBuilder->getNode();

/** @var string|null $namespaceName */
$namespaceName = $class->getAttribute(AttributeKey::NAMESPACE_NAME);
if ($namespaceName === null) {
return $eventSubscriberClass;
}

$namespace = new Namespace_(new Name($namespaceName));
$namespace->stmts[] = $eventSubscriberClass;

return $namespace;
}

public function resolveEventSubscriberFilePath(Class_ $class): string
{
/** @var SmartFileInfo $fileInfo */
$fileInfo = $class->getAttribute(AttributeKey::FILE_INFO);
$eventSubscriberClassName = $this->createEventSubscriberClassName($class);
return dirname($fileInfo->getRealPath()) . DIRECTORY_SEPARATOR . $eventSubscriberClassName . '.php';
}

public function createEventSubscriberClassName(Class_ $class): string
{
$className = $class->getAttribute(AttributeKey::CLASS_SHORT_NAME);

return $className . 'EventSubscriber';
}

private function createGetSubscribedEventsClassMethod(): ClassMethod
{
$classMethodBuilder = $this->builderFactory->method('getSubscribedEvents');
$classMethodBuilder->makePublic();
$classMethodBuilder->makeStatic();

$eventConstant = new ClassConstFetch(new FullyQualified(
'Symfony\Component\HttpKernel\KernelEvents'
), 'REQUEST');
$arrayItem = new ArrayItem(new String_('onKernelRequest'), $eventConstant);
$eventsToMethodsArray = new Array_([$arrayItem]);

$return = new Return_($eventsToMethodsArray);
$classMethodBuilder->addStmt($return);
$classMethodBuilder->setReturnType('array');

return $classMethodBuilder->getNode();
}

private function createOnKernelRequestClassMethod(ClassMethod $onBeforeFilterClassMethod): ClassMethod
{
$classMethodBuilder = $this->builderFactory->method('onKernelRequest');
$classMethodBuilder->addStmts((array) $onBeforeFilterClassMethod->stmts);
$classMethodBuilder->makePublic();

return $classMethodBuilder->getNode();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php

declare(strict_types=1);

namespace Rector\CakePHPToSymfony\Rector\Class_;

use Nette\Utils\FileSystem;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use Rector\CakePHPToSymfony\NodeFactory\EventSubscriberClassFactory;
use Rector\CakePHPToSymfony\Rector\AbstractCakePHPRector;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;

/**
* @inspired by
* @see \Rector\NetteToSymfony\Rector\Assign\FormControlToControllerAndFormTypeRector::refactor()
*
* @see \Rector\CakePHPToSymfony\Tests\Rector\Class_\CakePHPBeforeFilterToRequestEventSubscriberRector\CakePHPBeforeFilterToRequestEventSubscriberRectorExtraTest
*/
final class CakePHPBeforeFilterToRequestEventSubscriberRector extends AbstractCakePHPRector
{
/**
* @var EventSubscriberClassFactory
*/
private $eventSubscriberClassFactory;

public function __construct(EventSubscriberClassFactory $eventSubscriberClassFactory)
{
$this->eventSubscriberClassFactory = $eventSubscriberClassFactory;
}

public function getDefinition(): RectorDefinition
{
return new RectorDefinition(
'Migrate CakePHP beforeFilter() method from controller to Event Subscriber before request',
[
new CodeSample(
<<<'PHP'
class SuperadminController extends \AppController
{
public function beforeFilter()
{
// something
}
}
PHP
,
<<<'PHP'
class SuperadminController extends \AppController
{
}
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;
}

$beforeFilterClassMethod = $node->getMethod('beforeFilter');
if ($beforeFilterClassMethod === null) {
return null;
}

$this->removeNode($beforeFilterClassMethod);

// create event subscriber with name...
$eventSubscriberClass = $this->eventSubscriberClassFactory->createEventSubscriberClass(
$node,
$beforeFilterClassMethod
);
$eventSubscriberFilePath = $this->eventSubscriberClassFactory->resolveEventSubscriberFilePath($node);

// @todo make temporary
$content = '<?php' . PHP_EOL . $this->print($eventSubscriberClass) . PHP_EOL;
FileSystem::write($eventSubscriberFilePath, $content);

return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,8 @@ public function refactor(Node $node): ?Node
continue;
}

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

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,9 @@ private function inRepositoryMethod(ClassMethod $classMethod): bool

private function getRepositoryShortClassName(Class_ $class): string
{
return $this->getShortName($class->name) . 'Repository';
/** @var string $classShortName */
$classShortName = $class->getAttribute(AttributeKey::CLASS_SHORT_NAME);

return $classShortName . 'Repository';
}
}
14 changes: 2 additions & 12 deletions packages/CakePHPToSymfony/src/TemplatePathResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use PhpParser\Node;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\CodingStyle\Naming\ClassNaming;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PhpParser\Node\Commander\NodeRemovingCommander;
use Rector\PhpParser\Node\Manipulator\PropertyFetchManipulator;
Expand All @@ -32,11 +31,6 @@ final class TemplatePathResolver
*/
private $valueResolver;

/**
* @var ClassNaming
*/
private $classNaming;

/**
* @var NodeRemovingCommander
*/
Expand All @@ -46,13 +40,11 @@ public function __construct(
CallableNodeTraverser $callableNodeTraverser,
PropertyFetchManipulator $propertyFetchManipulator,
ValueResolver $valueResolver,
ClassNaming $classNaming,
NodeRemovingCommander $nodeRemovingCommander
) {
$this->callableNodeTraverser = $callableNodeTraverser;
$this->propertyFetchManipulator = $propertyFetchManipulator;
$this->valueResolver = $valueResolver;
$this->classNaming = $classNaming;
$this->nodeRemovingCommander = $nodeRemovingCommander;
}

Expand All @@ -71,10 +63,8 @@ public function resolveForClassMethod(ClassMethod $classMethod): string

public function resolveClassNameTemplatePart(ClassMethod $classMethod): string
{
/** @var string $className */
$className = $classMethod->getAttribute(AttributeKey::CLASS_NAME);
$shortClassName = $this->classNaming->getShortName($className);

/** @var string $shortClassName */
$shortClassName = $classMethod->getAttribute(AttributeKey::CLASS_SHORT_NAME);
$shortClassName = Strings::replace($shortClassName, '#Controller$#i');

return Strings::lower($shortClassName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,24 @@
use Rector\CakePHPToSymfony\Rector\Class_\CakePHPBeforeFilterToRequestEventSubscriberRector;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

final class CakePHPBeforeFilterToRequestEventSubscriberRectorTest extends AbstractRectorTestCase
final class CakePHPBeforeFilterToRequestEventSubscriberRectorExtraTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(string $file): void
public function test(string $inputFile, string $expectedExtraFileName, string $expectedExtraContentFilePath): void
{
$this->doTestFile($file);
$this->doTestFile($inputFile);
$this->doTestExtraFile($expectedExtraFileName, $expectedExtraContentFilePath);
}

public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
yield [
__DIR__ . '/Fixture/fixture.php.inc',
'SuperadminControllerEventSubscriber.php',
__DIR__ . '/Source/extra_file.php',
];
}

protected function getRectorClass(): string
Expand Down
Loading