Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add YAML config discovery of entities for finalize-classes command #6

Merged
merged 1 commit into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Command/FinalizeClassesCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int

$this->symfonyStyle->title('1. Detecting parent and entity classes');

$phpFileInfos = PhpFilesFinder::findPhpFileInfos($paths);
$phpFileInfos = PhpFilesFinder::find($paths);

// double to count for both parent and entity resolver
$this->symfonyStyle->progressStart(2 * count($phpFileInfos));
Expand All @@ -69,7 +69,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
};

$parentClassNames = $this->parentClassResolver->resolve($phpFileInfos, $progressClosure);
$entityClassNames = $this->entityClassResolver->resolve($phpFileInfos, $progressClosure);
$entityClassNames = $this->entityClassResolver->resolve($paths, $progressClosure);

$this->symfonyStyle->progressFinish();

Expand Down
59 changes: 52 additions & 7 deletions src/EntityClassResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,56 @@

namespace Rector\SwissKnife;

use Closure;
use PhpParser\NodeTraverser;
use Rector\SwissKnife\Finder\PhpFilesFinder;
use Rector\SwissKnife\Finder\YamlFilesFinder;
use Rector\SwissKnife\PhpParser\CachedPhpParser;
use Rector\SwissKnife\PhpParser\NodeVisitor\EntityClassNameCollectingNodeVisitor;
use Symfony\Component\Finder\SplFileInfo;
use Webmozart\Assert\Assert;

/**
* @see \Rector\SwissKnife\Tests\EntityClassResolver\EntityClassResolverTest
*/
final readonly class EntityClassResolver
{
/**
* @var string
* @see https://regex101.com/r/YFbH1x/1
*/
private const YAML_ENTITY_CLASS_NAME_REGEX = '#^(?<class_name>[\w+\\\\]+)\:\n#m';

public function __construct(
private CachedPhpParser $cachedPhpParser
) {
}

/**
* @param SplFileInfo[] $phpFileInfos
* @param string[] $paths
* @return string[]
*/
public function resolve(array $phpFileInfos, Closure $progressClosure): array
public function resolve(array $paths, ?callable $progressClosure = null): array
{
Assert::allString($paths);
Assert::allFileExists($paths);

// 1. resolve from yaml annotations
$yamlEntityClassNames = $this->resolveYamlEntityClassNames($paths);

// 2. resolve from direct class names with namespace parts, doctrine annotation or docblock
$phpFileInfos = PhpFilesFinder::find($paths);
$entityClassNameCollectingNodeVisitor = new EntityClassNameCollectingNodeVisitor();

$nodeTraverser = new NodeTraverser();
$nodeTraverser->addVisitor($entityClassNameCollectingNodeVisitor);

$this->traverseFileInfos($phpFileInfos, $nodeTraverser, $progressClosure);

return $entityClassNameCollectingNodeVisitor->getEntityClassNames();
$markedEntityClassNames = $entityClassNameCollectingNodeVisitor->getEntityClassNames();

$entityClassNames = array_merge($yamlEntityClassNames, $markedEntityClassNames);
sort($entityClassNames);

return array_unique($entityClassNames);
}

/**
Expand All @@ -42,13 +62,38 @@ public function resolve(array $phpFileInfos, Closure $progressClosure): array
private function traverseFileInfos(
array $phpFileInfos,
NodeTraverser $nodeTraverser,
callable $progressClosure
?callable $progressClosure = null
): void {
foreach ($phpFileInfos as $phpFileInfo) {
$stmts = $this->cachedPhpParser->parseFile($phpFileInfo->getRealPath());

$nodeTraverser->traverse($stmts);
$progressClosure();

if (is_callable($progressClosure)) {
$progressClosure();
}
}
}

/**
* @param string[] $paths
* @return string[]
*/
private function resolveYamlEntityClassNames(array $paths): array
{
$yamlFileInfos = YamlFilesFinder::find($paths);

$yamlEntityClassNames = [];

/** @var SplFileInfo $yamlFileInfo */
foreach ($yamlFileInfos as $yamlFileInfo) {
$matches = \Nette\Utils\Strings::matchAll($yamlFileInfo->getContents(), self::YAML_ENTITY_CLASS_NAME_REGEX);

foreach ($matches as $match) {
$yamlEntityClassNames[] = $match['class_name'];
}
}

return $yamlEntityClassNames;
}
}
10 changes: 7 additions & 3 deletions src/Finder/PhpFilesFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,24 @@

use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
use Webmozart\Assert\Assert;

final class PhpFilesFinder
{
/**
* @param string[] $paths
* @return SplFileInfo[]
*/
public static function findPhpFileInfos(array $paths): array
public static function find(array $paths): array
{
$phpFinder = Finder::create()
Assert::allString($paths);
Assert::allFileExists($paths);

$finder = Finder::create()
->files()
->in($paths)
->name('*.php');

return iterator_to_array($phpFinder);
return iterator_to_array($finder);
}
}
30 changes: 30 additions & 0 deletions src/Finder/YamlFilesFinder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace Rector\SwissKnife\Finder;

use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
use Webmozart\Assert\Assert;

final class YamlFilesFinder
{
/**
* @param string[] $paths
* @return SplFileInfo[]
*/
public static function find(array $paths): array
{
Assert::allString($paths);
Assert::allFileExists($paths);

$finder = Finder::create()
->files()
->in($paths)
->name('*.yml')
->name('*.yaml');

return iterator_to_array($finder);
}
}
9 changes: 5 additions & 4 deletions tests/EntityClassResolver/EntityClassResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace Rector\SwissKnife\Tests\EntityClassResolver;

use Rector\SwissKnife\EntityClassResolver;
use Rector\SwissKnife\Finder\PhpFilesFinder;
use Rector\SwissKnife\Tests\AbstractTestCase;
use Rector\SwissKnife\Tests\EntityClassResolver\Fixture\Entity\SomeEntity;

Expand All @@ -22,10 +21,12 @@ protected function setUp(): void

public function test(): void
{
$fileInfos = PhpFilesFinder::findPhpFileInfos([__DIR__ . '/Fixture']);
$entityClasses = $this->entityClassResolver->resolve($fileInfos, function () {
$entityClasses = $this->entityClassResolver->resolve([__DIR__ . '/Fixture'], function () {
});

$this->assertSame([SomeEntity::class], $entityClasses);
$this->assertSame(
['App\Some\Entity\Conference', 'App\Some\Entity\Project', 'App\Some\Entity\Talk', SomeEntity::class],
$entityClasses
);
}
}
7 changes: 7 additions & 0 deletions tests/EntityClassResolver/Fixture/config/next.orm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
App\Some\Entity\Talk:
type: entity
manyToOne:
property:

App\Some\Entity\Project:
type: entity
2 changes: 2 additions & 0 deletions tests/EntityClassResolver/Fixture/config/some.orm.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
App\Some\Entity\Conference:
type: entity
Loading