mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-18 05:48:21 +01:00
[Symfony] move getter to ctor Rector to SymfonyExtra
This commit is contained in:
parent
d756d0ccaa
commit
84bcd3bbb4
190
src/Rector/Contrib/SymfonyExtra/GetterToPropertyRector.php
Normal file
190
src/Rector/Contrib/SymfonyExtra/GetterToPropertyRector.php
Normal file
@ -0,0 +1,190 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Rector\Contrib\SymfonyExtra;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Scalar\String_;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use Rector\Builder\Class_\ClassPropertyCollector;
|
||||
use Rector\Builder\Kernel\ServiceFromKernelResolver;
|
||||
use Rector\Builder\Naming\NameResolver;
|
||||
use Rector\Deprecation\SetNames;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\Tests\Rector\Contrib\SymfonyExtra\GetterToPropertyRector\Source\LocalKernel;
|
||||
|
||||
/**
|
||||
* Converts all:
|
||||
* $this->get('some_service') # where "some_service" is name of the service in container.
|
||||
*
|
||||
* into:
|
||||
* $this->someService # where "someService" is type of the service
|
||||
*/
|
||||
final class GetterToPropertyRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var NameResolver
|
||||
*/
|
||||
private $nameResolver;
|
||||
|
||||
/**
|
||||
* @var ServiceFromKernelResolver
|
||||
*/
|
||||
private $serviceFromKernelResolver;
|
||||
|
||||
/**
|
||||
* @var ClassPropertyCollector
|
||||
*/
|
||||
private $classPropertyCollector;
|
||||
|
||||
/**
|
||||
* @var Class_
|
||||
*/
|
||||
private $classNode;
|
||||
|
||||
public function __construct(
|
||||
NameResolver $nameResolver,
|
||||
ServiceFromKernelResolver $serviceFromKernelResolver,
|
||||
ClassPropertyCollector $classPropertyCollector
|
||||
) {
|
||||
$this->nameResolver = $nameResolver;
|
||||
$this->serviceFromKernelResolver = $serviceFromKernelResolver;
|
||||
$this->classPropertyCollector = $classPropertyCollector;
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo add node traverser for this or to AbstractRector
|
||||
* @param Node[] $nodes
|
||||
* @return null|Node[]
|
||||
*/
|
||||
public function beforeTraverse(array $nodes): ?array
|
||||
{
|
||||
$this->classNode = null;
|
||||
|
||||
foreach ($nodes as $node) {
|
||||
if ($node instanceof Class_) {
|
||||
$this->classNode = $node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Node $node
|
||||
* Possibly simlify to just "$this->get('some_service')"
|
||||
*/
|
||||
public function isCandidate(Node $node): bool
|
||||
{
|
||||
// $var = $this->get('some_service');
|
||||
// $var = $this->get('some_service')->getData();
|
||||
if ($node instanceof Assign && ($node->expr instanceof MethodCall || $node->var instanceof MethodCall)) {
|
||||
if ($this->isContainerGetCall($node->expr)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// ['var => $this->get('some_service')->getData()]
|
||||
if ($node instanceof MethodCall && $node->var instanceof MethodCall) {
|
||||
if ($this->isContainerGetCall($node->var)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function refactor(Node $assignOrMethodCallNode): ?Node
|
||||
{
|
||||
if ($assignOrMethodCallNode instanceof Assign) {
|
||||
$refactoredMethodCall = $this->processMethodCallNode($assignOrMethodCallNode->expr);
|
||||
if ($refactoredMethodCall) {
|
||||
$assignOrMethodCallNode->expr = $refactoredMethodCall;
|
||||
}
|
||||
}
|
||||
|
||||
if ($assignOrMethodCallNode instanceof MethodCall) {
|
||||
$refactoredMethodCall = $this->processMethodCallNode($assignOrMethodCallNode->var);
|
||||
if ($refactoredMethodCall) {
|
||||
$assignOrMethodCallNode->var = $refactoredMethodCall;
|
||||
}
|
||||
}
|
||||
|
||||
return $assignOrMethodCallNode;
|
||||
}
|
||||
|
||||
public function getSetName(): string
|
||||
{
|
||||
return SetNames::SYMFONY_EXTRA;
|
||||
}
|
||||
|
||||
public function sinceVersion(): float
|
||||
{
|
||||
return 3.3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is "$this->get('string')" statements?
|
||||
*/
|
||||
private function isContainerGetCall(MethodCall $methodCall): bool
|
||||
{
|
||||
if ($methodCall->var->name !== 'this') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((string) $methodCall->name !== 'get') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $methodCall->args[0]->value instanceof String_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function processMethodCallNode(MethodCall $methodCall): ?PropertyFetch
|
||||
{
|
||||
/** @var String_ $argument */
|
||||
$argument = $methodCall->args[0]->value;
|
||||
$serviceName = $argument->value;
|
||||
|
||||
$serviceType = $this->serviceFromKernelResolver->resolveServiceClassByNameFromKernel(
|
||||
$serviceName,
|
||||
LocalKernel::class
|
||||
);
|
||||
|
||||
if ($serviceType === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$propertyName = $this->nameResolver->resolvePropertyNameFromType($serviceType);
|
||||
|
||||
$this->classPropertyCollector->addPropertyForClass($this->getClassName(), $serviceType, $propertyName);
|
||||
|
||||
return $this->createPropertyFetch($propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo move to NodeFactory
|
||||
* Creates "$this->propertyName".
|
||||
*/
|
||||
private function createPropertyFetch(string $propertyName): PropertyFetch
|
||||
{
|
||||
return new PropertyFetch(
|
||||
new Variable('this', [
|
||||
'name' => $propertyName,
|
||||
]),
|
||||
$propertyName
|
||||
);
|
||||
}
|
||||
|
||||
private function getClassName(): string
|
||||
{
|
||||
return $this->classNode->namespacedName->toString();
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
services:
|
||||
some.class:
|
||||
class: stdClass
|
@ -1,6 +1,6 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Rector\Contrib\Symfony\GetterToPropertyRector\Source;
|
||||
namespace Rector\Tests\Rector\Contrib\SymfonyExtra\GetterToPropertyRector\Source;
|
||||
|
||||
use Symfony\Component\Config\Loader\LoaderInterface;
|
||||
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
@ -0,0 +1,3 @@
|
||||
services:
|
||||
some_service:
|
||||
class: stdClass
|
@ -1,8 +1,8 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Rector\Contrib\Symfony\GetterToPropertyRector;
|
||||
namespace Rector\Tests\Rector\Contrib\SymfonyExtra\GetterToPropertyRector;
|
||||
|
||||
use Rector\Rector\Contrib\Symfony\GetterToPropertyRector;
|
||||
use Rector\Rector\Contrib\SymfonyExtra\GetterToPropertyRector;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
|
||||
final class Test extends AbstractRectorTestCase
|
@ -4,6 +4,6 @@ class ClassWithNamedService extends Controller
|
||||
{
|
||||
public function render()
|
||||
{
|
||||
$this->get('some.class')->render();
|
||||
$this->get('some_service')->render();
|
||||
}
|
||||
}
|
@ -4,6 +4,6 @@ class ClassWithNamedService implements ContainerAwareInterface
|
||||
{
|
||||
public function render()
|
||||
{
|
||||
$someService = $this->get('some.class');
|
||||
$someService = $this->get('some_service');
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ class ClassWithNamedService implements ContainerAwareInterface
|
||||
{
|
||||
public function render()
|
||||
{
|
||||
$someService = $this->get('some.class');
|
||||
$someResult = $this->get('some.class')->callMe();
|
||||
$someService = $this->get('some_service');
|
||||
$someResult = $this->get('some_service')->callMe();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user