diff --git a/composer-dependency-analyser.php b/composer-dependency-analyser.php new file mode 100644 index 000000000..bc9bc5657 --- /dev/null +++ b/composer-dependency-analyser.php @@ -0,0 +1,17 @@ +addPathToScan(__DIR__ . '/src', false) + ->addPathToScan(__DIR__ . '/tests', false) + // test fixture + ->ignoreErrorsOnPath( + __DIR__ . '/tests/EntityClassResolver/Fixture/Anything/SomeAttributeDocument.php', + [ErrorType::UNKNOWN_CLASS] + ); diff --git a/src/PhpParser/NodeVisitor/EntityClassNameCollectingNodeVisitor.php b/src/PhpParser/NodeVisitor/EntityClassNameCollectingNodeVisitor.php index 6f68fa79c..a8eb848ef 100644 --- a/src/PhpParser/NodeVisitor/EntityClassNameCollectingNodeVisitor.php +++ b/src/PhpParser/NodeVisitor/EntityClassNameCollectingNodeVisitor.php @@ -9,9 +9,20 @@ use PhpParser\Node\Name; use PhpParser\Node\Stmt\Class_; use PhpParser\NodeVisitorAbstract; +use Webmozart\Assert\Assert; final class EntityClassNameCollectingNodeVisitor extends NodeVisitorAbstract { + /** + * @var string[] + */ + private const ODM_SUFFIXES = ['Document', 'EmbeddedDocument']; + + /** + * @var string[] + */ + private const ORM_SUFFIXES = ['Entity', 'Embeddable']; + /** * @var string[] */ @@ -28,13 +39,7 @@ public function enterNode(Node $node): ?Node return null; } - // dummy check for entity namespace + odm - if (array_intersect(['Entity', 'Entities', 'Document'], $node->namespacedName->getParts())) { - $this->entityClassNames[] = $node->namespacedName->toString(); - return null; - } - - if ($this->hasEntityDocBlock($node) || $this->hasEntityAttribute($node)) { + if ($this->hasEntityAnnotation($node) || $this->hasEntityAttribute($node)) { $this->entityClassNames[] = $node->namespacedName->toString(); return null; } @@ -53,8 +58,13 @@ public function getEntityClassNames(): array return $uniqueEntityClassNames; } - private function hasEntityDocBlock(Class_ $class): bool + /** + * @param string[] $suffixes + */ + private function hasDocBlockSuffixes(Class_ $class, array $suffixes): bool { + Assert::allString($suffixes); + $docComment = $class->getDocComment(); if ($docComment instanceof Doc) { // dummy check @@ -62,32 +72,51 @@ private function hasEntityDocBlock(Class_ $class): bool return false; } - if (str_contains($docComment->getText(), 'Entity')) { - return true; - } - - if (str_contains($docComment->getText(), 'Embeddable')) { - return true; + foreach ($suffixes as $suffix) { + if (str_contains($docComment->getText(), $suffix)) { + return true; + } } } return false; } - private function hasEntityAttribute(Class_ $class): bool + /** + * @param string[] $suffixes + */ + private function hasAttributeSuffixes(Class_ $class, array $suffixes): bool { + Assert::allString($suffixes); + foreach ($class->attrGroups as $attrGroup) { foreach ($attrGroup->attrs as $attr) { - if (str_ends_with($attr->name->toString(), 'Entity')) { - return true; - } - - if (str_ends_with($attr->name->toString(), 'Embeddable')) { - return true; + foreach ($suffixes as $suffix) { + if (str_ends_with($attr->name->toString(), $suffix)) { + return true; + } } } } return false; } + + private function hasEntityAnnotation(Class_ $class): bool + { + if ($this->hasDocBlockSuffixes($class, self::ODM_SUFFIXES)) { + return true; + } + + return $this->hasDocBlockSuffixes($class, self::ORM_SUFFIXES); + } + + private function hasEntityAttribute(Class_ $class): bool + { + if ($this->hasAttributeSuffixes($class, self::ODM_SUFFIXES)) { + return true; + } + + return $this->hasAttributeSuffixes($class, self::ORM_SUFFIXES); + } } diff --git a/tests/EntityClassResolver/EntityClassResolverTest.php b/tests/EntityClassResolver/EntityClassResolverTest.php index 3cbe946b9..e482b6bfb 100644 --- a/tests/EntityClassResolver/EntityClassResolverTest.php +++ b/tests/EntityClassResolver/EntityClassResolverTest.php @@ -6,6 +6,8 @@ use Rector\SwissKnife\EntityClassResolver; use Rector\SwissKnife\Tests\AbstractTestCase; +use Rector\SwissKnife\Tests\EntityClassResolver\Fixture\Anything\SomeAttributeDocument; +use Rector\SwissKnife\Tests\EntityClassResolver\Fixture\Anything\SomeDocument; use Rector\SwissKnife\Tests\EntityClassResolver\Fixture\Entity\SomeEntity; final class EntityClassResolverTest extends AbstractTestCase @@ -21,12 +23,26 @@ protected function setUp(): void public function test(): void { - $entityClasses = $this->entityClassResolver->resolve([__DIR__ . '/Fixture'], static function (): void { - }); + $entityClasses = $this->entityClassResolver->resolve( + [__DIR__ . '/Fixture/Entity', __DIR__ . '/Fixture/config'], + static function (): void { + } + ); $this->assertSame( ['App\Some\Entity\Conference', 'App\Some\Entity\Project', 'App\Some\Entity\Talk', SomeEntity::class], $entityClasses ); } + + public function testODMDocument(): void + { + $documentClasses = $this->entityClassResolver->resolve( + [__DIR__ . '/Fixture/Anything'], + static function (): void { + } + ); + + $this->assertSame([SomeAttributeDocument::class, SomeDocument::class], $documentClasses); + } } diff --git a/tests/EntityClassResolver/Fixture/Anything/SomeAttributeDocument.php b/tests/EntityClassResolver/Fixture/Anything/SomeAttributeDocument.php new file mode 100644 index 000000000..be65b1ce2 --- /dev/null +++ b/tests/EntityClassResolver/Fixture/Anything/SomeAttributeDocument.php @@ -0,0 +1,10 @@ +