Merge pull request #337 from rectorphp/laravel-to-symfony

[POC] Laravel Controller to Symfony
This commit is contained in:
Tomáš Votruba 2018-03-06 21:21:40 +01:00 committed by GitHub
commit 84a7c24d02
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 212 additions and 0 deletions

View File

@ -0,0 +1,59 @@
<?php declare(strict_types=1);
namespace Rector\Console\Command;
use Rector\Console\ConsoleStyle;
use Rector\Naming\CommandNaming;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Finder\Finder;
final class LevelsCommand extends Command
{
/**
* @var ConsoleStyle
*/
private $consoleStyle;
public function __construct(ConsoleStyle $consoleStyle)
{
$this->consoleStyle = $consoleStyle;
parent::__construct();
}
protected function configure(): void
{
$this->setName(CommandNaming::classToName(self::class));
$this->setDescription('List available levels.');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$levels = $this->getAvailbleLevels();
$this->consoleStyle->title(sprintf('%d available levels:', count($levels)));
$this->consoleStyle->listing($levels);
return 0;
}
/**
* @return string[]
*/
private function getAvailbleLevels(): array
{
$finder = Finder::create()->files()
->in(__DIR__ . '/../../config/level');
$levels = [];
foreach ($finder->getIterator() as $fileInfo) {
$levels[] = $fileInfo->getBasename('.' . $fileInfo->getExtension());
}
sort($levels);
return array_unique($levels);
}
}

View File

@ -0,0 +1,72 @@
<?php declare(strict_types=1);
namespace Rector\Rector\Dynamic;
use PhpParser\Node;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Name;
use Rector\Node\MethodCallNodeFactory;
use Rector\Rector\AbstractRector;
/**
* Before:
* - view('...', [])
*
* After:
* - $this->render('...')
*/
final class FunctionToMethodCallRector extends AbstractRector
{
/**
* @var string[]
*/
private $functionToMethodCall = [];
/**
* @var MethodCallNodeFactory
*/
private $methodCallNodeFactory;
/**
* @param string[] $functionToMethodCall e.g. ["view" => ["this", "render"]]
*/
public function __construct(array $functionToMethodCall, MethodCallNodeFactory $methodCallNodeFactory)
{
$this->functionToMethodCall = $functionToMethodCall;
$this->methodCallNodeFactory = $methodCallNodeFactory;
}
public function isCandidate(Node $node): bool
{
if (! $node instanceof FuncCall) {
return false;
}
if (! $node->name instanceof Name) {
return false;
}
$functionName = $node->name->toString();
return isset($this->functionToMethodCall[$functionName]);
}
/**
* @param FuncCall $funcCallNode
*/
public function refactor(Node $funcCallNode): ?Node
{
$functionName = $funcCallNode->name->toString();
[$variableName, $methodName] = $this->functionToMethodCall[$functionName];
$methodCallNode = $this->methodCallNodeFactory->createWithVariableNameAndMethodName(
$variableName,
$methodName
);
$methodCallNode->args = $funcCallNode->args;
return $methodCallNode;
}
}

View File

@ -0,0 +1,11 @@
services:
Rector\Rector\Dynamic\ClassReplacerRector:
$oldToNewClasses:
'Illuminate\Http\Response': 'Symfony\Component\HttpFoundation\Response'
'App\Http\Controllers\Controller': 'Symfony\Bundle\FrameworkBundle\Controller\Controller'
# view('...') => $this->render('...')
Rector\Rector\Dynamic\FunctionToMethodCallRector:
$functionToMethodCall:
'view': ['this', 'render']

View File

@ -0,0 +1,14 @@
<?php declare(strict_types=1);
namespace App\Controller;
use \Symfony\Bundle\FrameworkBundle\Controller\Controller;
use \Symfony\Component\HttpFoundation\Response;
class UserController extends \Symfony\Bundle\FrameworkBundle\Controller\Controller
{
public function show(): \Symfony\Component\HttpFoundation\Response
{
return $this->render('user.profile');
}
}

View File

@ -0,0 +1,31 @@
<?php declare(strict_types=1);
namespace Rector\Tests\Rector\FrameworkMigration\LaravelToSymfony;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
final class LaravelToSymfonyTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideWrongToFixedFiles()
*/
public function test(string $wrong, string $fixed): void
{
$this->doTestFileMatchesExpectedContent($wrong, $fixed);
}
/**
* @return string[][]
*/
public function provideWrongToFixedFiles(): array
{
return [
[__DIR__ . '/Wrong/wrong.php.inc', __DIR__ . '/Correct/correct.php.inc'],
];
}
protected function provideConfig(): string
{
return __DIR__ . '/config.yml';
}
}

View File

@ -0,0 +1,14 @@
<?php declare(strict_types=1);
namespace App\Controller;
use App\Http\Controllers\Controller;
use Illuminate\Http\Response;
class UserController extends Controller
{
public function show(): Response
{
return view('user.profile');
}
}

View File

@ -0,0 +1,11 @@
services:
Rector\Rector\Dynamic\ClassReplacerRector:
$oldToNewClasses:
'Illuminate\Http\Response': 'Symfony\Component\HttpFoundation\Response'
'App\Http\Controllers\Controller': 'Symfony\Bundle\FrameworkBundle\Controller\Controller'
# view('...') => $this->render('...')
Rector\Rector\Dynamic\FunctionToMethodCallRector:
$functionToMethodCall:
'view': ['this', 'render']