Skip to content

Commit dbed9f5

Browse files
committed
Introduce ClassLocator to find classes names for attribute drivers
1 parent a241c82 commit dbed9f5

File tree

11 files changed

+431
-174
lines changed

11 files changed

+431
-174
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@
3030
"phpstan/phpstan-strict-rules": "^1.1",
3131
"doctrine/coding-standard": "^12",
3232
"phpunit/phpunit": "^9.6",
33-
"symfony/cache": "^4.4 || ^5.4 || ^6.0 || ^7.0"
33+
"symfony/cache": "^4.4 || ^5.4 || ^6.0 || ^7.0",
34+
"symfony/finder": "^4.4 || ^5.4 || ^6.0 || ^7.0"
3435
},
3536
"autoload": {
3637
"psr-4": {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Persistence\Mapping\Driver;
6+
7+
/**
8+
* ClassLocator is an interface for classes that can provide a list of class names.
9+
*/
10+
interface ClassLocator
11+
{
12+
/** @return list<class-string> */
13+
public function getClassNames(): array;
14+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Persistence\Mapping\Driver;
6+
7+
/**
8+
* Basic implementation of ClassLocator that passes a list of class names.
9+
*/
10+
final class ClassNames implements ClassLocator
11+
{
12+
/** @param list<class-string> $classNames */
13+
public function __construct(
14+
private array $classNames,
15+
) {
16+
}
17+
18+
/** @return list<class-string> */
19+
public function getClassNames(): array
20+
{
21+
return $this->classNames;
22+
}
23+
}

src/Persistence/Mapping/Driver/ColocatedMappingDriver.php

Lines changed: 17 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,17 @@
55
namespace Doctrine\Persistence\Mapping\Driver;
66

77
use Doctrine\Persistence\Mapping\MappingException;
8-
use ReflectionClass;
98

9+
use function array_filter;
1010
use function array_merge;
1111
use function array_unique;
12-
use function assert;
13-
use function get_declared_classes;
14-
use function preg_match;
15-
use function realpath;
16-
use function str_contains;
17-
use function str_replace;
1812

1913
/**
2014
* The ColocatedMappingDriver reads the mapping metadata located near the code.
2115
*/
2216
trait ColocatedMappingDriver
2317
{
24-
/** @var iterable<array-key,string> */
25-
private iterable $filePaths;
18+
private ClassLocator $classLocator;
2619

2720
/**
2821
* The directory paths where to look for mapping files.
@@ -123,75 +116,24 @@ public function getAllClassNames(): array
123116
return $this->classNames;
124117
}
125118

126-
if ($this->paths === [] && ! isset($this->filePaths)) {
127-
throw MappingException::pathRequiredForDriver(static::class);
128-
}
129-
130-
$dirFilesIterator = new DirectoryFilesIterator($this->paths, $this->fileExtension);
131-
132-
/** @var iterable<string> $filePathsIterator */
133-
$filePathsIterator = $this->concatIterables(
134-
$this->filePaths ?? [],
135-
new FilePathNameIterator($dirFilesIterator),
136-
);
137-
138-
/** @var array<string,true> $includedFiles */
139-
$includedFiles = [];
140-
141-
foreach ($filePathsIterator as $sourceFile) {
142-
if (preg_match('(^phar:)i', $sourceFile) === 0) {
143-
$sourceFile = realpath($sourceFile);
144-
assert($sourceFile !== false);
145-
}
146-
147-
foreach ($this->excludePaths as $excludePath) {
148-
$realExcludePath = realpath($excludePath);
149-
assert($realExcludePath !== false);
150-
$exclude = str_replace('\\', '/', $realExcludePath);
151-
$current = str_replace('\\', '/', $sourceFile);
152-
153-
if (str_contains($current, $exclude)) {
154-
continue 2;
155-
}
156-
}
157-
158-
require_once $sourceFile;
159-
160-
$includedFiles[$sourceFile] = true;
161-
}
119+
if ($this->paths !== []) {
120+
$classNames = FileClassLocator::createFromDirectories($this->paths, $this->excludePaths, $this->fileExtension)->getClassNames();
162121

163-
$classes = [];
164-
$declared = get_declared_classes();
165-
166-
foreach ($declared as $className) {
167-
$rc = new ReflectionClass($className);
168-
169-
$sourceFile = $rc->getFileName();
170-
171-
if (! isset($includedFiles[$sourceFile]) || $this->isTransient($className)) {
172-
continue;
122+
if (isset($this->classLocator)) {
123+
$classNames = array_unique([
124+
...$classNames,
125+
...$this->classLocator->getClassNames(),
126+
]);
173127
}
174-
175-
$classes[] = $className;
128+
} elseif (isset($this->classLocator)) {
129+
$classNames = $this->classLocator->getClassNames();
130+
} else {
131+
throw MappingException::pathRequiredForDriver(static::class);
176132
}
177133

178-
$this->classNames = $classes;
179-
180-
return $classes;
181-
}
182-
183-
/**
184-
* @param iterable<TKey, T> $iterable1
185-
* @param iterable<TKey, T> $iterable2
186-
*
187-
* @return iterable<TKey, T>
188-
*
189-
* @template TKey
190-
* @template T
191-
*/
192-
private function concatIterables(iterable $iterable1, iterable $iterable2): iterable
193-
{
194-
yield from $iterable1;
195-
yield from $iterable2;
134+
return $this->classNames = array_filter(
135+
$classNames,
136+
fn (string $className): bool => ! $this->isTransient($className),
137+
);
196138
}
197139
}

src/Persistence/Mapping/Driver/DirectoryFilesIterator.php

Lines changed: 0 additions & 61 deletions
This file was deleted.

0 commit comments

Comments
 (0)