mirror of
https://github.com/rectorphp/rector.git
synced 2025-04-14 04:22:17 +02:00
[Doctrine] Add registry to EM
This commit is contained in:
parent
c3f9fb9e44
commit
bd48d5792d
2
config/set/doctrine/doctrine-code-quality.yaml
Normal file
2
config/set/doctrine/doctrine-code-quality.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
services:
|
||||
Rector\Doctrine\Rector\Class_\ManagerRegistryGetManagerToEntityManagerRector: ~
|
8
packages/Doctrine/config/config.yaml
Normal file
8
packages/Doctrine/config/config.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
services:
|
||||
_defaults:
|
||||
autowire: true
|
||||
public: true
|
||||
|
||||
Rector\Doctrine\:
|
||||
resource: '../src'
|
||||
exclude: '../src/{Rector/**/*Rector.php}'
|
@ -0,0 +1,330 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Doctrine\Rector\Class_;
|
||||
|
||||
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\Name\FullyQualified;
|
||||
use PhpParser\Node\Param;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PhpParser\NodeTraverser;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
|
||||
final class ManagerRegistryGetManagerToEntityManagerRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private const MANAGER_REGISTRY_CLASS = 'Doctrine\Common\Persistence\ManagerRegistry';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private const ENTITY_MANAGER_CLASS = 'Doctrine\ORM\EntityManagerInterface';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private const OBJECT_MANAGER_CLASS = 'Doctrine\Common\Persistence\ObjectManager';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $managerRegistryClass;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $objectManagerClass;
|
||||
|
||||
public function __construct(
|
||||
string $managerRegistryClass = self::MANAGER_REGISTRY_CLASS,
|
||||
string $objectManagerClass = self::OBJECT_MANAGER_CLASS
|
||||
) {
|
||||
$this->managerRegistryClass = $managerRegistryClass;
|
||||
$this->objectManagerClass = $objectManagerClass;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition('', [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
use Doctrine\Common\Persistence\ManagerRegistry;
|
||||
|
||||
class CustomRepository
|
||||
{
|
||||
/**
|
||||
* @var ManagerRegistry
|
||||
*/
|
||||
private $managerRegistry;
|
||||
|
||||
public function __construct(ManagerRegistry $managerRegistry)
|
||||
{
|
||||
$this->managerRegistry = $managerRegistry;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$entityManager = $this->managerRegistry->getManager();
|
||||
$someRepository = $entityManager->getRepository('Some');
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
class CustomRepository
|
||||
{
|
||||
/**
|
||||
* @var EntityManagerInterface
|
||||
*/
|
||||
private $entityManager;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$someRepository = $this->entityManager->getRepository('Some');
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [Class_::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Class_ $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
$constructMethodNode = $node->getMethod('__construct');
|
||||
if ($constructMethodNode === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// collect on registry method calls, so we know if the manager registry is needed
|
||||
$registryCalledMethods = $this->resolveManagerRegistryCalledMethodNames($node);
|
||||
|
||||
$shouldRemoveManagerRegistryProperty = $registryCalledMethods === ['getManager'];
|
||||
if (! in_array('getManager', $registryCalledMethods, true)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$registryParam = $this->resolveManagerRegistryParam($constructMethodNode);
|
||||
|
||||
// no registry manager in the constructor
|
||||
if ($registryParam === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// add entity manager via constructor
|
||||
$this->addConstructorDependencyWithProperty(
|
||||
$node,
|
||||
$constructMethodNode,
|
||||
'entityManager',
|
||||
self::ENTITY_MANAGER_CLASS
|
||||
);
|
||||
|
||||
if ($shouldRemoveManagerRegistryProperty === true) {
|
||||
$this->removeManagerRegistryDependency($node, $constructMethodNode, $registryParam);
|
||||
}
|
||||
|
||||
// remove assign method calls
|
||||
$this->removeAssignGetRepositoryCalls($node);
|
||||
|
||||
$this->traverseNodesWithCallable($node->stmts, function (Node $node): ?PropertyFetch {
|
||||
if (! $node instanceof Variable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->isType($node, $this->objectManagerClass)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new PropertyFetch(new Variable('this'), 'entityManager');
|
||||
});
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function isRegistryGetManagerMethodCall(Assign $assign): bool
|
||||
{
|
||||
if (! $assign->expr instanceof MethodCall) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $this->isType($assign->expr->var, $this->managerRegistryClass)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $this->isName($assign->expr->name, 'getManager')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function removeAssignGetRepositoryCalls(Class_ $class): void
|
||||
{
|
||||
$this->traverseNodesWithCallable($class->stmts, function (Node $node) {
|
||||
if (! $node instanceof Assign) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->isRegistryGetManagerMethodCall($node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->removeNode($node);
|
||||
});
|
||||
}
|
||||
|
||||
private function createEntityManagerParam(): Param
|
||||
{
|
||||
return new Param(new Variable('entityManager'), null, new FullyQualified(self::ENTITY_MANAGER_CLASS));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function resolveManagerRegistryCalledMethodNames(Class_ $class): array
|
||||
{
|
||||
$registryCalledMethods = [];
|
||||
$this->traverseNodesWithCallable($class->stmts, function (Node $node) use (&$registryCalledMethods) {
|
||||
if (! $node instanceof MethodCall) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->isType($node->var, $this->managerRegistryClass)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$name = $this->getName($node);
|
||||
if ($name === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$registryCalledMethods[] = $name;
|
||||
});
|
||||
|
||||
return array_unique($registryCalledMethods);
|
||||
}
|
||||
|
||||
private function removeManagerRegistryDependency(
|
||||
Class_ $class,
|
||||
ClassMethod $classMethod,
|
||||
Param $registryParam
|
||||
): void {
|
||||
// remove constructor param: $managerRegistry
|
||||
foreach ($classMethod->params as $key => $param) {
|
||||
if ($param->type === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $this->isName($param->type, $this->managerRegistryClass)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unset($classMethod->params[$key]);
|
||||
}
|
||||
|
||||
$this->removeRegistryDependencyAssign($class, $classMethod, $registryParam);
|
||||
}
|
||||
|
||||
private function addConstructorDependencyWithProperty(
|
||||
Class_ $class,
|
||||
ClassMethod $classMethod,
|
||||
string $name,
|
||||
string $type
|
||||
): void {
|
||||
$propertyFetch = new PropertyFetch(new Variable('this'), $name);
|
||||
$assign = new Assign($propertyFetch, new Variable($name));
|
||||
|
||||
$classMethod->stmts[] = new Expression($assign);
|
||||
|
||||
$this->addPropertyToClass($class, $type, $name);
|
||||
}
|
||||
|
||||
private function resolveManagerRegistryParam(ClassMethod $classMethod): ?Param
|
||||
{
|
||||
foreach ($classMethod->params as $param) {
|
||||
if ($param->type === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $this->isName($param->type, $this->managerRegistryClass)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$classMethod->params[] = $this->createEntityManagerParam();
|
||||
|
||||
return $param;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function removeManagerRegistryProperty(Class_ $class, Assign $assign): void
|
||||
{
|
||||
$managerRegistryPropertyName = $this->getName($assign->var);
|
||||
|
||||
$this->traverseNodesWithCallable($class->stmts, function (Node $node) use (
|
||||
$managerRegistryPropertyName
|
||||
): ?int {
|
||||
if (! $node instanceof Property) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->isName($node, $managerRegistryPropertyName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->removeNode($node);
|
||||
|
||||
return NodeTraverser::STOP_TRAVERSAL;
|
||||
});
|
||||
}
|
||||
|
||||
private function removeRegistryDependencyAssign(Class_ $class, ClassMethod $classMethod, Param $registryParam): void
|
||||
{
|
||||
foreach ((array) $classMethod->stmts as $key => $constructorMethodStmt) {
|
||||
if (! $constructorMethodStmt instanceof Expression && ! $constructorMethodStmt->expr instanceof Assign) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var Assign $assign */
|
||||
$assign = $constructorMethodStmt->expr;
|
||||
if (! $this->areNamesEqual($assign->expr, $registryParam->var)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->removeManagerRegistryProperty($class, $assign);
|
||||
|
||||
// remove assign
|
||||
unset($classMethod->stmts[$key]);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Doctrine\Tests\Rector\Class_\ManagerRegistryGetManagerToEntityManagerRector\Fixture;
|
||||
|
||||
use Rector\Doctrine\Tests\Rector\Class_\ManagerRegistryGetManagerToEntityManagerRector\Source\DummyManagerRegistry;
|
||||
|
||||
class DoNotRemoveRegistryOnNonGetRepoCall
|
||||
{
|
||||
/**
|
||||
* @var DummyManagerRegistry
|
||||
*/
|
||||
private $managerRegistry;
|
||||
|
||||
public function __construct(DummyManagerRegistry $managerRegistry)
|
||||
{
|
||||
$this->managerRegistry = $managerRegistry;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$manager = $this->managerRegistry->getManager();
|
||||
$item = $manager->getItem();
|
||||
|
||||
$this->managerRegistry->kickThat();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Doctrine\Tests\Rector\Class_\ManagerRegistryGetManagerToEntityManagerRector\Fixture;
|
||||
|
||||
use Rector\Doctrine\Tests\Rector\Class_\ManagerRegistryGetManagerToEntityManagerRector\Source\DummyManagerRegistry;
|
||||
|
||||
class DoNotRemoveRegistryOnNonGetRepoCall
|
||||
{
|
||||
/**
|
||||
* @var DummyManagerRegistry
|
||||
*/
|
||||
private $managerRegistry;
|
||||
/**
|
||||
* @var \Doctrine\ORM\EntityManagerInterface
|
||||
*/
|
||||
private $entityManager;
|
||||
|
||||
public function __construct(DummyManagerRegistry $managerRegistry, \Doctrine\ORM\EntityManagerInterface $entityManager)
|
||||
{
|
||||
$this->managerRegistry = $managerRegistry;
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$item = $this->entityManager->getItem();
|
||||
$this->managerRegistry->kickThat();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Doctrine\Tests\Rector\Class_\ManagerRegistryGetManagerToEntityManagerRector\Fixture;
|
||||
|
||||
use Rector\Doctrine\Tests\Rector\Class_\ManagerRegistryGetManagerToEntityManagerRector\Source\DummyManagerRegistry;
|
||||
|
||||
class CustomRepository
|
||||
{
|
||||
/**
|
||||
* @var DummyManagerRegistry
|
||||
*/
|
||||
private $managerRegistry;
|
||||
|
||||
public function __construct(DummyManagerRegistry $managerRegistry)
|
||||
{
|
||||
$this->managerRegistry = $managerRegistry;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$entityManager = $this->managerRegistry->getManager();
|
||||
$someRepository = $entityManager->getRepository('Some');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Doctrine\Tests\Rector\Class_\ManagerRegistryGetManagerToEntityManagerRector\Fixture;
|
||||
|
||||
use Rector\Doctrine\Tests\Rector\Class_\ManagerRegistryGetManagerToEntityManagerRector\Source\DummyManagerRegistry;
|
||||
|
||||
class CustomRepository
|
||||
{
|
||||
/**
|
||||
* @var \Doctrine\ORM\EntityManagerInterface
|
||||
*/
|
||||
private $entityManager;
|
||||
|
||||
public function __construct(\Doctrine\ORM\EntityManagerInterface $entityManager)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$someRepository = $this->entityManager->getRepository('Some');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Doctrine\Tests\Rector\Class_\ManagerRegistryGetManagerToEntityManagerRector\Fixture;
|
||||
|
||||
use Rector\Doctrine\Tests\Rector\Class_\ManagerRegistryGetManagerToEntityManagerRector\Source\DummyManagerRegistry;
|
||||
|
||||
class KeepDifferntMethods
|
||||
{
|
||||
/**
|
||||
* @var DummyManagerRegistry
|
||||
*/
|
||||
private $managerRegistry;
|
||||
|
||||
public function __construct(DummyManagerRegistry $managerRegistry)
|
||||
{
|
||||
$this->managerRegistry = $managerRegistry;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$this->managerRegistry->resetThis();
|
||||
$this->managerRegistry->kickThat();
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Doctrine\Tests\Rector\Class_\ManagerRegistryGetManagerToEntityManagerRector;
|
||||
|
||||
use Rector\Doctrine\Rector\Class_\ManagerRegistryGetManagerToEntityManagerRector;
|
||||
use Rector\Doctrine\Tests\Rector\Class_\ManagerRegistryGetManagerToEntityManagerRector\Source\DummyManagerRegistry;
|
||||
use Rector\Doctrine\Tests\Rector\Class_\ManagerRegistryGetManagerToEntityManagerRector\Source\DummyObjectManager;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
|
||||
final class ManagerRegistryGetManagerToEntityManagerRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$this->doTestFiles([
|
||||
__DIR__ . '/Fixture/fixture.php.inc',
|
||||
__DIR__ . '/Fixture/keep_different_methods.php.inc',
|
||||
__DIR__ . '/Fixture/do_not_remove_registry_on_non_get_repo_call.php.inc',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
protected function getRectorsWithConfiguration(): array
|
||||
{
|
||||
return [
|
||||
ManagerRegistryGetManagerToEntityManagerRector::class => [
|
||||
'$managerRegistryClass' => DummyManagerRegistry::class,
|
||||
'$objectManagerClass' => DummyObjectManager::class,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Doctrine\Tests\Rector\Class_\ManagerRegistryGetManagerToEntityManagerRector\Source;
|
||||
|
||||
final class DummyManagerRegistry
|
||||
{
|
||||
public function getManager(): DummyObjectManager
|
||||
{
|
||||
return new DummyObjectManager();
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Doctrine\Tests\Rector\Class_\ManagerRegistryGetManagerToEntityManagerRector\Source;
|
||||
|
||||
final class DummyObjectManager
|
||||
{
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user