[Doctrine] Add ChangeIdenticalUuidToEqualsMethodCallRector

This commit is contained in:
Tomas Votruba 2019-09-21 19:23:55 +02:00
parent 8993b6bc14
commit d727b0181e
7 changed files with 205 additions and 2 deletions

View File

@ -2,3 +2,4 @@ services:
Rector\Doctrine\Rector\MethodCall\ChangeSetIdToUuidValueRector: ~
Rector\Doctrine\Rector\MethodCall\ChangeGetUuidMethodCallToGetIdRector: ~
Rector\Doctrine\Rector\ClassMethod\ChangeReturnTypeOfClassMethodWithGetIdRector: ~
Rector\Doctrine\Rector\Identical\ChangeIdenticalUuidToEqualsMethodCallRector: ~

View File

@ -4,6 +4,7 @@ namespace Rector\DeadCode\Doctrine;
use Doctrine\ORM\Mapping\Entity;
use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Property;
use PHPStan\Type\ObjectType;
@ -155,7 +156,7 @@ final class DoctrineEntityManipulator
public function isMethodCallOnDoctrineEntity(Node $node, string $methodName): bool
{
if (! $node instanceof Node\Expr\MethodCall) {
if (! $node instanceof MethodCall) {
return false;
}

View File

@ -0,0 +1,119 @@
<?php declare(strict_types=1);
namespace Rector\Doctrine\Rector\Identical;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\BinaryOp\Identical;
use PHPStan\Type\ObjectType;
use Rector\DeadCode\Doctrine\DoctrineEntityManipulator;
use Rector\Doctrine\ValueObject\DoctrineClass;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
/**
* @see \Rector\Doctrine\Tests\Rector\Identical\ChangeIdenticalUuidToEqualsMethodCallRector\ChangeIdenticalUuidToEqualsMethodCallRectorTest
*/
final class ChangeIdenticalUuidToEqualsMethodCallRector extends AbstractRector
{
/**
* @var DoctrineEntityManipulator
*/
private $doctrineEntityManipulator;
public function __construct(DoctrineEntityManipulator $doctrineEntityManipulator)
{
$this->doctrineEntityManipulator = $doctrineEntityManipulator;
}
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Change $uuid === 1 to $uuid->equals(\Ramsey\Uuid\Uuid::fromString(1))', [
new CodeSample(
<<<'PHP'
class SomeClass
{
public function match($checkedId): int
{
$building = new Building();
return $building->getId() === $checkedId;
}
}
PHP
,
<<<'PHP'
class SomeClass
{
public function match($checkedId): int
{
$building = new Building();
return $building->getId()->equals(\Ramsey\Uuid\Uuid::fromString($checkedId));
}
}
PHP
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [Identical::class];
}
/**
* @param Identical $node
*/
public function refactor(Node $node): ?Node
{
$match = $this->matchEntityCallAndComparedVariable($node);
if ($match === null) {
return null;
}
[$entityMethodCall, $comparedVariable] = $match;
$fromStringValue = $this->createStaticCall(DoctrineClass::RAMSEY_UUID, 'fromString', [$comparedVariable]);
return $this->createMethodCall($entityMethodCall, 'equals', [$fromStringValue]);
}
private function isAlreadyUuidType(Expr $expr): bool
{
$comparedValueObjectType = $this->getStaticType($expr);
if (! $comparedValueObjectType instanceof ObjectType) {
return false;
}
return $comparedValueObjectType->getClassName() === DoctrineClass::RAMSEY_UUID_INTERFACE;
}
/**
* @return Expr[]|null
*/
private function matchEntityCallAndComparedVariable(Node $node): ?array
{
if ($this->doctrineEntityManipulator->isMethodCallOnDoctrineEntity($node->left, 'getId')) {
if ($this->isAlreadyUuidType($node->right)) {
return null;
}
return [$node->left, $node->right];
}
if ($this->doctrineEntityManipulator->isMethodCallOnDoctrineEntity($node->right, 'getId')) {
if ($this->isAlreadyUuidType($node->left)) {
return null;
}
return [$node->right, $node->left];
}
return null;
}
}

View File

@ -0,0 +1,30 @@
<?php declare(strict_types=1);
namespace Rector\Doctrine\Tests\Rector\Identical\ChangeIdenticalUuidToEqualsMethodCallRector;
use Rector\Doctrine\Rector\Identical\ChangeIdenticalUuidToEqualsMethodCallRector;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
final class ChangeIdenticalUuidToEqualsMethodCallRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideDataForTest()
*/
public function test(string $file): void
{
$this->doTestFile($file);
}
/**
* @return string[]
*/
public function provideDataForTest(): iterable
{
yield [__DIR__ . '/Fixture/fixture.php.inc'];
}
protected function getRectorClass(): string
{
return ChangeIdenticalUuidToEqualsMethodCallRector::class;
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace Rector\Doctrine\Tests\Rector\Identical\ChangeIdenticalUuidToEqualsMethodCallRector\Fixture;
use Rector\Doctrine\Tests\Rector\Identical\ChangeIdenticalUuidToEqualsMethodCallRector\Source\Building;
class SomeClass
{
public function match($checkedId): int
{
$building = new Building();
$isLeft = $building->getId() === $checkedId;
$isRight = $checkedId === $building->getId();
}
}
?>
-----
<?php
namespace Rector\Doctrine\Tests\Rector\Identical\ChangeIdenticalUuidToEqualsMethodCallRector\Fixture;
use Rector\Doctrine\Tests\Rector\Identical\ChangeIdenticalUuidToEqualsMethodCallRector\Source\Building;
class SomeClass
{
public function match($checkedId): int
{
$building = new Building();
$isLeft = $building->getId()->equals(\Ramsey\Uuid\Uuid::fromString($checkedId));
$isRight = $building->getId()->equals(\Ramsey\Uuid\Uuid::fromString($checkedId));
}
}
?>

View File

@ -0,0 +1,13 @@
<?php declare(strict_types=1);
namespace Rector\Doctrine\Tests\Rector\Identical\ChangeIdenticalUuidToEqualsMethodCallRector\Source;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
final class Building
{
}

View File

@ -1,4 +1,6 @@
<?php declare(strict_types=1);
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';