mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-17 21:38:22 +01:00
Move Architecture to Doctrine, improve a bit (#5374)
This commit is contained in:
parent
1fc272e228
commit
2df4732c6c
@ -87,7 +87,6 @@
|
||||
"psr-4": {
|
||||
"Rector\\Testing\\": "packages/testing/src",
|
||||
"Rector\\Comments\\": "packages/comments/src",
|
||||
"Rector\\Architecture\\": "rules/architecture/src",
|
||||
"Rector\\AttributeAwarePhpDoc\\": "packages/attribute-aware-php-doc/src",
|
||||
"Rector\\Autodiscovery\\": "rules/autodiscovery/src",
|
||||
"Rector\\BetterPhpDocParser\\": "packages/better-php-doc-parser/src",
|
||||
@ -218,7 +217,6 @@
|
||||
"tests/debug_functions.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Rector\\Architecture\\Tests\\": "rules/architecture/tests",
|
||||
"Rector\\Autodiscovery\\Tests\\": "rules/autodiscovery/tests",
|
||||
"Rector\\BetterPhpDocParser\\Tests\\": "packages/better-php-doc-parser/tests",
|
||||
"Rector\\Caching\\Tests\\": "packages/caching/tests",
|
||||
|
@ -2,11 +2,10 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\Architecture\Rector\MethodCall\ReplaceParentRepositoryCallsByRepositoryPropertyRector;
|
||||
use Rector\Architecture\Rector\MethodCall\ServiceLocatorToDIRector;
|
||||
use Rector\DeadDocBlock\Rector\ClassLike\RemoveAnnotationRector;
|
||||
use Rector\Doctrine\Rector\Class_\RemoveRepositoryFromEntityAnnotationRector;
|
||||
use Rector\Doctrine\Rector\ClassMethod\ServiceEntityRepositoryParentCallToDIRector;
|
||||
use Rector\Doctrine\Rector\MethodCall\ReplaceParentRepositoryCallsByRepositoryPropertyRector;
|
||||
use Rector\DoctrineCodeQuality\Rector\Class_\MoveRepositoryFromParentToConstructorRector;
|
||||
use Rector\Generic\Rector\Class_\AddPropertyByParentRector;
|
||||
use Rector\Generic\ValueObject\AddPropertyByParent;
|
||||
@ -28,7 +27,6 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
|
||||
// covers "extends EntityRepository"
|
||||
$services->set(MoveRepositoryFromParentToConstructorRector::class);
|
||||
$services->set(ServiceLocatorToDIRector::class);
|
||||
$services->set(ReplaceParentRepositoryCallsByRepositoryPropertyRector::class);
|
||||
$services->set(RemoveRepositoryFromEntityAnnotationRector::class);
|
||||
|
||||
|
@ -156,7 +156,7 @@
|
||||
|
||||
Handles method calls in child of Doctrine EntityRepository and moves them to `$this->repository` property.
|
||||
|
||||
- class: `Rector\Architecture\Rector\MethodCall\ReplaceParentRepositoryCallsByRepositoryPropertyRector`
|
||||
- class: `Rector\Doctrine\Rector\MethodCall\ReplaceParentRepositoryCallsByRepositoryPropertyRector`
|
||||
|
||||
```diff
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
@ -177,7 +177,7 @@ Handles method calls in child of Doctrine EntityRepository and moves them to `$t
|
||||
|
||||
Turns `$this->getRepository()` in Symfony Controller to constructor injection and private property access.
|
||||
|
||||
- class: `Rector\Architecture\Rector\MethodCall\ServiceLocatorToDIRector`
|
||||
- class: `Rector\Doctrine\Rector\MethodCall\ServiceLocatorToDIRector`
|
||||
|
||||
```diff
|
||||
class ProductController extends Controller
|
||||
|
@ -19,6 +19,11 @@ final class EntityTagValueNode extends AbstractDoctrineTagValueNode implements P
|
||||
$this->items[self::REPOSITORY_CLASS] = null;
|
||||
}
|
||||
|
||||
public function hasRepositoryClass(): bool
|
||||
{
|
||||
return $this->items[self::REPOSITORY_CLASS] !== null;
|
||||
}
|
||||
|
||||
public function getShortName(): string
|
||||
{
|
||||
return '@ORM\Entity';
|
||||
|
@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services = $containerConfigurator->services();
|
||||
|
||||
$services->defaults()
|
||||
->autowire()
|
||||
->public()
|
||||
->autoconfigure();
|
||||
|
||||
$services->load('Rector\Architecture\\', __DIR__ . '/../src')
|
||||
->exclude([__DIR__ . '/../src/Rector']);
|
||||
};
|
@ -1,188 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Architecture\Rector\MethodCall;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\ClassConstFetch;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Scalar\String_;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use Rector\Core\Exception\Bridge\RectorProviderException;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Doctrine\Contract\Mapper\DoctrineEntityAndRepositoryMapperInterface;
|
||||
use Rector\Naming\Naming\PropertyNaming;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
|
||||
/**
|
||||
* @see \Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\DoctrineRepositoryAsServiceTest
|
||||
*/
|
||||
final class ServiceLocatorToDIRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var DoctrineEntityAndRepositoryMapperInterface
|
||||
*/
|
||||
private $doctrineEntityAndRepositoryMapper;
|
||||
|
||||
/**
|
||||
* @var PropertyNaming
|
||||
*/
|
||||
private $propertyNaming;
|
||||
|
||||
public function __construct(
|
||||
DoctrineEntityAndRepositoryMapperInterface $doctrineEntityAndRepositoryMapper,
|
||||
PropertyNaming $propertyNaming
|
||||
) {
|
||||
$this->doctrineEntityAndRepositoryMapper = $doctrineEntityAndRepositoryMapper;
|
||||
$this->propertyNaming = $propertyNaming;
|
||||
}
|
||||
|
||||
public function getRuleDefinition(): RuleDefinition
|
||||
{
|
||||
return new RuleDefinition(
|
||||
'Turns $this->getRepository() in Symfony Controller to constructor injection and private property access.',
|
||||
[
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
class ProductController extends Controller
|
||||
{
|
||||
public function someAction()
|
||||
{
|
||||
$entityManager = $this->getDoctrine()->getManager();
|
||||
$entityManager->getRepository('SomethingBundle:Product')->findSomething(...);
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
class ProductController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var ProductRepository
|
||||
*/
|
||||
private $productRepository;
|
||||
|
||||
public function __construct(ProductRepository $productRepository)
|
||||
{
|
||||
$this->productRepository = $productRepository;
|
||||
}
|
||||
|
||||
public function someAction()
|
||||
{
|
||||
$entityManager = $this->getDoctrine()->getManager();
|
||||
$this->productRepository->findSomething(...);
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [MethodCall::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MethodCall $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
if (! $this->isName($node->name, 'getRepository')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$firstArgumentValue = $node->args[0]->value;
|
||||
// possible mocking → skip
|
||||
if ($firstArgumentValue instanceof StaticCall) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var string|null $className */
|
||||
$className = $node->getAttribute(AttributeKey::CLASS_NAME);
|
||||
if ($className === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var MethodCall $methodCallNode */
|
||||
$methodCallNode = $node;
|
||||
if (count($methodCallNode->args) !== 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($methodCallNode->args[0]->value instanceof String_) {
|
||||
/** @var String_ $string */
|
||||
$string = $methodCallNode->args[0]->value;
|
||||
|
||||
// is alias
|
||||
if (Strings::contains($string->value, ':')) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (Strings::endsWith($className, 'Repository')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$repositoryFqn = $this->resolveRepositoryFqnFromGetRepositoryMethodCall($node);
|
||||
$classLike = $node->getAttribute(AttributeKey::CLASS_NODE);
|
||||
if (! $classLike instanceof Class_) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$repositoryObjectType = new ObjectType($repositoryFqn);
|
||||
|
||||
$this->addConstructorDependencyToClass(
|
||||
$classLike,
|
||||
$repositoryObjectType,
|
||||
$this->propertyNaming->fqnToVariableName($repositoryObjectType)
|
||||
);
|
||||
|
||||
return $this->createPropertyFetch('this', $this->propertyNaming->fqnToVariableName($repositoryObjectType));
|
||||
}
|
||||
|
||||
private function resolveRepositoryFqnFromGetRepositoryMethodCall(MethodCall $methodCall): string
|
||||
{
|
||||
$entityFqnOrAlias = $this->entityFqnOrAlias($methodCall);
|
||||
|
||||
if ($entityFqnOrAlias !== null) {
|
||||
$repositoryClassName = $this->doctrineEntityAndRepositoryMapper->mapEntityToRepository($entityFqnOrAlias);
|
||||
if ($repositoryClassName !== null) {
|
||||
return $repositoryClassName;
|
||||
}
|
||||
}
|
||||
|
||||
throw new RectorProviderException(sprintf(
|
||||
'A repository was not provided for "%s" entity by your "%s" class.',
|
||||
$entityFqnOrAlias,
|
||||
get_class($this->doctrineEntityAndRepositoryMapper)
|
||||
));
|
||||
}
|
||||
|
||||
private function entityFqnOrAlias(MethodCall $methodCall): string
|
||||
{
|
||||
$repositoryArgument = $methodCall->args[0]->value;
|
||||
|
||||
if ($repositoryArgument instanceof String_) {
|
||||
return $repositoryArgument->value;
|
||||
}
|
||||
|
||||
if ($repositoryArgument instanceof ClassConstFetch && $repositoryArgument->class instanceof Name) {
|
||||
return $this->getName($repositoryArgument->class);
|
||||
}
|
||||
|
||||
throw new ShouldNotHappenException('Unable to resolve repository argument');
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Core\Tests\Rector\Architecture\DoctrineRepositoryAsService\Source\Entity;
|
||||
|
||||
final class Post
|
||||
{
|
||||
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Core\Tests\Rector\Architecture\DoctrineRepositoryAsService\Source;
|
||||
|
||||
final class EntityManagerClass
|
||||
{
|
||||
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Core\Tests\Rector\Architecture\DoctrineRepositoryAsService\Source\Repository;
|
||||
|
||||
final class PostRepository
|
||||
{
|
||||
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Core\Tests\Rector\Architecture\DoctrineRepositoryAsService\Source;
|
||||
|
||||
class SymfonyController
|
||||
{
|
||||
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DoctrineCodeQuality\NodeAnalyzer;
|
||||
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
|
||||
use Rector\DoctrineCodeQuality\TypeAnalyzer\TypeFinder;
|
||||
|
||||
final class EntityObjectTypeResolver
|
||||
{
|
||||
/**
|
||||
* @var PhpDocInfoFactory
|
||||
*/
|
||||
private $phpDocInfoFactory;
|
||||
|
||||
/**
|
||||
* @var TypeFinder
|
||||
*/
|
||||
private $typeFinder;
|
||||
|
||||
public function __construct(PhpDocInfoFactory $phpDocInfoFactory, TypeFinder $typeFinder)
|
||||
{
|
||||
$this->phpDocInfoFactory = $phpDocInfoFactory;
|
||||
$this->typeFinder = $typeFinder;
|
||||
}
|
||||
|
||||
public function resolveFromRepositoryClass(Class_ $repositoryClass): Type
|
||||
{
|
||||
foreach ($repositoryClass->getMethods() as $classMethod) {
|
||||
if (! $classMethod->isPublic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($classMethod);
|
||||
|
||||
$returnType = $phpDocInfo->getReturnType();
|
||||
$objectType = $this->typeFinder->find($returnType, ObjectType::class);
|
||||
if (! $objectType instanceof ObjectType) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $objectType;
|
||||
}
|
||||
|
||||
return new MixedType();
|
||||
}
|
||||
}
|
@ -12,11 +12,12 @@ use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use PHPStan\Type\TypeWithClassName;
|
||||
use Rector\Core\Exception\Bridge\RectorProviderException;
|
||||
use Rector\Core\PhpParser\Node\Manipulator\ClassDependencyManipulator;
|
||||
use Rector\Core\PhpParser\Node\Manipulator\ClassInsertManipulator;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Doctrine\Contract\Mapper\DoctrineEntityAndRepositoryMapperInterface;
|
||||
use Rector\DoctrineCodeQuality\NodeAnalyzer\EntityObjectTypeResolver;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
@ -26,11 +27,6 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
*/
|
||||
final class MoveRepositoryFromParentToConstructorRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var DoctrineEntityAndRepositoryMapperInterface
|
||||
*/
|
||||
private $doctrineEntityAndRepositoryMapper;
|
||||
|
||||
/**
|
||||
* @var ClassDependencyManipulator
|
||||
*/
|
||||
@ -41,14 +37,19 @@ final class MoveRepositoryFromParentToConstructorRector extends AbstractRector
|
||||
*/
|
||||
private $classInsertManipulator;
|
||||
|
||||
/**
|
||||
* @var EntityObjectTypeResolver
|
||||
*/
|
||||
private $entityObjectTypeResolver;
|
||||
|
||||
public function __construct(
|
||||
ClassDependencyManipulator $classDependencyManipulator,
|
||||
ClassInsertManipulator $classInsertManipulator,
|
||||
DoctrineEntityAndRepositoryMapperInterface $doctrineEntityAndRepositoryMapper
|
||||
EntityObjectTypeResolver $entityObjectTypeResolver
|
||||
) {
|
||||
$this->doctrineEntityAndRepositoryMapper = $doctrineEntityAndRepositoryMapper;
|
||||
$this->classDependencyManipulator = $classDependencyManipulator;
|
||||
$this->classInsertManipulator = $classInsertManipulator;
|
||||
$this->entityObjectTypeResolver = $entityObjectTypeResolver;
|
||||
}
|
||||
|
||||
public function getRuleDefinition(): RuleDefinition
|
||||
@ -141,22 +142,21 @@ CODE_SAMPLE
|
||||
|
||||
/**
|
||||
* Creates:
|
||||
* "$this->repository = $entityManager->getRepository()"
|
||||
* "$this->repository = $entityManager->getRepository(SomeEntityClass::class)"
|
||||
*/
|
||||
private function createRepositoryAssign(Class_ $class): Assign
|
||||
private function createRepositoryAssign(Class_ $repositoryClass): Assign
|
||||
{
|
||||
$repositoryClassName = (string) $class->getAttribute(AttributeKey::CLASS_NAME);
|
||||
$entityClassName = $this->doctrineEntityAndRepositoryMapper->mapRepositoryToEntity($repositoryClassName);
|
||||
$entityObjectType = $this->entityObjectTypeResolver->resolveFromRepositoryClass($repositoryClass);
|
||||
$repositoryClassName = (string) $repositoryClass->getAttribute(AttributeKey::CLASS_NAME);
|
||||
|
||||
if ($entityClassName === null) {
|
||||
if (! $entityObjectType instanceof TypeWithClassName) {
|
||||
throw new RectorProviderException(sprintf(
|
||||
'An entity was not provided for "%s" repository by your "%s" class.',
|
||||
'An entity was not found for "%s" repository.',
|
||||
$repositoryClassName,
|
||||
get_class($this->doctrineEntityAndRepositoryMapper)
|
||||
));
|
||||
}
|
||||
|
||||
$classConstFetch = $this->createClassConstReference($entityClassName);
|
||||
$classConstFetch = $this->createClassConstReference($entityObjectType->getClassName());
|
||||
|
||||
$methodCall = $this->builderFactory->methodCall(
|
||||
new Variable('entityManager'),
|
||||
@ -164,8 +164,7 @@ CODE_SAMPLE
|
||||
[$classConstFetch]
|
||||
);
|
||||
|
||||
$methodCall->setAttribute(AttributeKey::CLASS_NODE, $class);
|
||||
|
||||
$methodCall->setAttribute(AttributeKey::CLASS_NODE, $repositoryClassName);
|
||||
return $this->createPropertyAssignmentWithExpr('repository', $methodCall);
|
||||
}
|
||||
}
|
||||
|
48
rules/doctrine-code-quality/src/TypeAnalyzer/TypeFinder.php
Normal file
48
rules/doctrine-code-quality/src/TypeAnalyzer/TypeFinder.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DoctrineCodeQuality\TypeAnalyzer;
|
||||
|
||||
use PHPStan\Type\ArrayType;
|
||||
use PHPStan\Type\IntersectionType;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\Type;
|
||||
use PHPStan\Type\UnionType;
|
||||
|
||||
final class TypeFinder
|
||||
{
|
||||
public function find(Type $type, string $desiredTypeClass): Type
|
||||
{
|
||||
if (is_a($type, $desiredTypeClass, true)) {
|
||||
return $type;
|
||||
}
|
||||
|
||||
if ($type instanceof ArrayType && is_a($type->getItemType(), $desiredTypeClass, true)) {
|
||||
return $type->getItemType();
|
||||
}
|
||||
if ($type instanceof UnionType) {
|
||||
return $this->findInJoinedType($type, $desiredTypeClass);
|
||||
}
|
||||
if ($type instanceof IntersectionType) {
|
||||
return $this->findInJoinedType($type, $desiredTypeClass);
|
||||
}
|
||||
|
||||
return new MixedType();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UnionType|IntersectionType $type
|
||||
*/
|
||||
private function findInJoinedType(Type $type, string $desiredTypeClass): Type
|
||||
{
|
||||
foreach ($type->getTypes() as $joinedType) {
|
||||
$foundType = $this->find($joinedType, $desiredTypeClass);
|
||||
if (! $foundType instanceof MixedType) {
|
||||
return $foundType;
|
||||
}
|
||||
}
|
||||
|
||||
return new MixedType();
|
||||
}
|
||||
}
|
@ -5,17 +5,16 @@ declare(strict_types=1);
|
||||
namespace Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Architecture\Rector\MethodCall\ReplaceParentRepositoryCallsByRepositoryPropertyRector;
|
||||
use Rector\Architecture\Rector\MethodCall\ServiceLocatorToDIRector;
|
||||
use Rector\Doctrine\Rector\Class_\RemoveRepositoryFromEntityAnnotationRector;
|
||||
use Rector\Doctrine\Rector\MethodCall\ReplaceParentRepositoryCallsByRepositoryPropertyRector;
|
||||
use Rector\DoctrineCodeQuality\Rector\Class_\MoveRepositoryFromParentToConstructorRector;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
/**
|
||||
* @see \Rector\Architecture\Rector\MethodCall\ReplaceParentRepositoryCallsByRepositoryPropertyRector
|
||||
* @see \Rector\Doctrine\Rector\MethodCall\ReplaceParentRepositoryCallsByRepositoryPropertyRector
|
||||
* @see \Rector\DoctrineCodeQuality\Rector\Class_\MoveRepositoryFromParentToConstructorRector
|
||||
* @see \Rector\Architecture\Rector\MethodCall\ServiceLocatorToDIRector
|
||||
* @see \Rector\Doctrine\Rector\MethodCall\EntityRepositoryServiceLocatorToDIRector
|
||||
*/
|
||||
final class DoctrineRepositoryAsServiceTest extends AbstractRectorTestCase
|
||||
{
|
||||
@ -40,7 +39,6 @@ final class DoctrineRepositoryAsServiceTest extends AbstractRectorTestCase
|
||||
return [
|
||||
# order matters, this needs to be first to correctly detect parent repository
|
||||
MoveRepositoryFromParentToConstructorRector::class => [],
|
||||
ServiceLocatorToDIRector::class => [],
|
||||
ReplaceParentRepositoryCallsByRepositoryPropertyRector::class => [],
|
||||
RemoveRepositoryFromEntityAnnotationRector::class => [],
|
||||
];
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\Fixture;
|
||||
|
||||
use Rector\Core\Tests\Rector\Architecture\DoctrineRepositoryAsService\Source\Entity\Post;
|
||||
use Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\Source\Entity\Post;
|
||||
use Rector\Core\Tests\Rector\Architecture\DoctrineRepositoryAsService\Source\SymfonyController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
@ -23,7 +23,7 @@ final class PostController extends SymfonyController
|
||||
|
||||
namespace Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\Fixture;
|
||||
|
||||
use Rector\Core\Tests\Rector\Architecture\DoctrineRepositoryAsService\Source\Entity\Post;
|
||||
use Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\Source\Entity\Post;
|
||||
use Rector\Core\Tests\Rector\Architecture\DoctrineRepositoryAsService\Source\SymfonyController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Architecture\Tests\Rector\DoctrineRepositoryAsService\Fixture;
|
||||
namespace Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\Fixture;
|
||||
|
||||
use App\Entity\Post;
|
||||
use Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\Source\Entity\Post;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
final class FirstPostRepository extends EntityRepository
|
||||
@ -18,21 +18,15 @@ final class FirstPostRepository extends EntityRepository
|
||||
'author' => $authorId
|
||||
]);
|
||||
}
|
||||
|
||||
public function shouldSkip()
|
||||
{
|
||||
$anotherClass = new \stdClass();
|
||||
$anotherClass->findBy();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Architecture\Tests\Rector\DoctrineRepositoryAsService\Fixture;
|
||||
namespace Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\Fixture;
|
||||
|
||||
use App\Entity\Post;
|
||||
use Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\Source\Entity\Post;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
final class FirstPostRepository
|
||||
@ -40,7 +34,7 @@ final class FirstPostRepository
|
||||
private \Doctrine\ORM\EntityRepository $repository;
|
||||
public function __construct(\Doctrine\ORM\EntityManager $entityManager)
|
||||
{
|
||||
$this->repository = $entityManager->getRepository(\App\Entity\FirstPost::class);
|
||||
$this->repository = $entityManager->getRepository(\Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\Source\Entity\Post::class);
|
||||
}
|
||||
/**
|
||||
* Our custom method
|
||||
@ -53,12 +47,6 @@ final class FirstPostRepository
|
||||
'author' => $authorId
|
||||
]);
|
||||
}
|
||||
|
||||
public function shouldSkip()
|
||||
{
|
||||
$anotherClass = new \stdClass();
|
||||
$anotherClass->findBy();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -6,7 +6,7 @@ use Doctrine\ORM\EntityManagerInterface;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Prophecy\Argument;
|
||||
|
||||
final class ItemRepositoryTest extends TestCase
|
||||
final class SkipTestCase extends TestCase
|
||||
{
|
||||
public function testGetThrowsExceptionIfNotFound(): void
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Architecture\Tests\Rector\DoctrineRepositoryAsService\Fixture;
|
||||
namespace Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\Fixture;
|
||||
|
||||
use App\Entity\Post;
|
||||
use Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\Source\RandomClass;
|
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\Source\Entity;
|
||||
|
||||
final class Post
|
||||
{
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\Source;
|
||||
|
||||
final class EntityManagerClass
|
||||
{
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Core\Tests\Rector\Architecture\DoctrineRepositoryAsService\Source;
|
||||
namespace Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\Source;
|
||||
|
||||
class EntityRepositoryClass
|
||||
{
|
@ -6,5 +6,4 @@ namespace Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\So
|
||||
|
||||
abstract class RandomClass
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\Source\Repository;
|
||||
|
||||
final class PostRepository
|
||||
{
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\Source;
|
||||
|
||||
class SymfonyController
|
||||
{
|
||||
}
|
@ -2,8 +2,6 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\Doctrine\Contract\Mapper\DoctrineEntityAndRepositoryMapperInterface;
|
||||
use Rector\Doctrine\Mapper\DefaultDoctrineEntityAndRepositoryMapper;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
@ -16,9 +14,4 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
|
||||
$services->load('Rector\Doctrine\\', __DIR__ . '/../src')
|
||||
->exclude([__DIR__ . '/../src/Rector']);
|
||||
|
||||
$services->alias(
|
||||
DoctrineEntityAndRepositoryMapperInterface::class,
|
||||
DefaultDoctrineEntityAndRepositoryMapper::class
|
||||
);
|
||||
};
|
||||
|
@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Doctrine\Contract\Mapper;
|
||||
|
||||
interface DoctrineEntityAndRepositoryMapperInterface
|
||||
{
|
||||
public function mapRepositoryToEntity(string $name): ?string;
|
||||
|
||||
public function mapEntityToRepository(string $name): ?string;
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Doctrine\Mapper;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
use Rector\Doctrine\Contract\Mapper\DoctrineEntityAndRepositoryMapperInterface;
|
||||
|
||||
final class DefaultDoctrineEntityAndRepositoryMapper implements DoctrineEntityAndRepositoryMapperInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private const REPOSITORY = 'Repository';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @see https://regex101.com/r/WrYZ0d/1
|
||||
*/
|
||||
private const REPOSITORY_REGEX = '#Repository#';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @see https://regex101.com/r/2a2CY6/1
|
||||
*/
|
||||
private const ENTITY_REGEX = '#Entity#';
|
||||
|
||||
public function mapRepositoryToEntity(string $repository): ?string
|
||||
{
|
||||
// "SomeRepository" => "Some"
|
||||
$withoutSuffix = Strings::substring($repository, 0, - strlen(self::REPOSITORY));
|
||||
|
||||
// "App\Repository\Some" => "App\Entity\Some"
|
||||
return Strings::replace($withoutSuffix, self::REPOSITORY_REGEX, 'Entity');
|
||||
}
|
||||
|
||||
public function mapEntityToRepository(string $entity): ?string
|
||||
{
|
||||
// "Some" => "SomeRepository"
|
||||
$withSuffix = $entity . self::REPOSITORY;
|
||||
|
||||
// "App\Entity\SomeRepository" => "App\Repository\SomeRepository"
|
||||
return Strings::replace($withSuffix, self::ENTITY_REGEX, self::REPOSITORY);
|
||||
}
|
||||
}
|
@ -68,6 +68,10 @@ CODE_SAMPLE
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $entityTagValueNode->hasRepositoryClass()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$entityTagValueNode->removeRepositoryClass();
|
||||
$phpDocInfo->markAsChanged();
|
||||
|
||||
|
@ -27,7 +27,7 @@ final class EntityAliasToClassConstantReferenceRector extends AbstractRector imp
|
||||
* @api
|
||||
* @var string
|
||||
*/
|
||||
public const ALIASES_TO_NAMESPACES = '$aliasesToNamespaces';
|
||||
public const ALIASES_TO_NAMESPACES = 'aliases_to_namespaces';
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Architecture\Rector\MethodCall;
|
||||
namespace Rector\Doctrine\Rector\MethodCall;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
@ -117,9 +117,9 @@ trait NodeFactoryTrait
|
||||
return $this->nodeFactory->createFuncCall($name, $arguments);
|
||||
}
|
||||
|
||||
protected function createClassConstReference(string $class): ClassConstFetch
|
||||
protected function createClassConstReference(string $className): ClassConstFetch
|
||||
{
|
||||
return $this->nodeFactory->createClassConstReference($class);
|
||||
return $this->nodeFactory->createClassConstReference($className);
|
||||
}
|
||||
|
||||
protected function createPropertyAssignmentWithExpr(string $propertyName, Expr $expr): Assign
|
||||
|
Loading…
x
Reference in New Issue
Block a user