44
55namespace Doctrine \Persistence \Mapping \Driver ;
66
7- use AppendIterator ;
87use Doctrine \Persistence \Mapping \MappingException ;
9- use FilesystemIterator ;
10- use Generator ;
11- use Iterator ;
12- use RecursiveDirectoryIterator ;
13- use RecursiveIteratorIterator ;
14- use ReflectionClass ;
15- use RegexIterator ;
16- use SplFileInfo ;
178
9+ use function array_filter ;
1810use function array_merge ;
1911use function array_unique ;
20- use function assert ;
21- use function get_declared_classes ;
22- use function in_array ;
23- use function is_dir ;
24- use function preg_match ;
25- use function preg_quote ;
26- use function realpath ;
27- use function sprintf ;
28- use function str_contains ;
29- use function str_replace ;
12+ use function array_values ;
3013
3114/**
3215 * The ColocatedMappingDriver reads the mapping metadata located near the code.
3316 */
3417trait ColocatedMappingDriver
3518{
19+ private ClassLocator |null $ classLocator = null ;
20+
3621 /**
37- * The paths where to look for mapping files.
22+ * The directory paths where to look for mapping files.
3823 *
3924 * @var array<int, string>
4025 */
@@ -51,7 +36,7 @@ trait ColocatedMappingDriver
5136 protected string $ fileExtension = '.php ' ;
5237
5338 /**
54- * Cache for getAllClassNames().
39+ * Cache for {@see getAllClassNames()} .
5540 *
5641 * @var array<int, string>|null
5742 * @phpstan-var list<class-string>|null
@@ -79,7 +64,7 @@ public function getPaths(): array
7964 }
8065
8166 /**
82- * Append exclude lookup paths to metadata driver.
67+ * Append exclude lookup paths to a metadata driver.
8368 *
8469 * @param string[] $paths
8570 */
@@ -132,85 +117,22 @@ public function getAllClassNames(): array
132117 return $ this ->classNames ;
133118 }
134119
135- if ($ this ->paths === []) {
120+ if ($ this ->paths === [] && $ this -> classLocator === null ) {
136121 throw MappingException::pathRequiredForDriver (static ::class);
137122 }
138123
139- /** @var AppendIterator<array-key,SplFileInfo,Iterator<array-key,SplFileInfo>> $filesIterator */
140- $ filesIterator = new AppendIterator ();
141-
142- foreach ($ this ->paths as $ path ) {
143- if (! is_dir ($ path )) {
144- throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath ($ path );
145- }
146-
147- /** @var Iterator<array-key,SplFileInfo> $iterator */
148- $ iterator = new RegexIterator (
149- new RecursiveIteratorIterator (
150- new RecursiveDirectoryIterator ($ path , FilesystemIterator::SKIP_DOTS ),
151- RecursiveIteratorIterator::LEAVES_ONLY ,
152- ),
153- sprintf ('/%s$/ ' , preg_quote ($ this ->fileExtension , '/ ' )),
154- RegexIterator::MATCH ,
155- );
156-
157- $ filesIterator ->append ($ iterator );
158- }
159-
160- $ sourceFilePathNames = $ this ->pathNameIterator ($ filesIterator );
161- $ includedFiles = [];
162-
163- foreach ($ sourceFilePathNames as $ sourceFile ) {
164- if (preg_match ('(^phar:)i ' , $ sourceFile ) === 0 ) {
165- $ sourceFile = realpath ($ sourceFile );
166- assert ($ sourceFile !== false );
167- }
168-
169- foreach ($ this ->excludePaths as $ excludePath ) {
170- $ realExcludePath = realpath ($ excludePath );
171- assert ($ realExcludePath !== false );
172- $ exclude = str_replace ('\\' , '/ ' , $ realExcludePath );
173- $ current = str_replace ('\\' , '/ ' , $ sourceFile );
174-
175- if (str_contains ($ current , $ exclude )) {
176- continue 2 ;
177- }
178- }
124+ $ classNames = $ this ->classLocator ?->getClassNames() ?? [];
179125
180- require_once $ sourceFile ;
181-
182- $ includedFiles [] = $ sourceFile ;
126+ if ($ this ->paths !== []) {
127+ $ classNames = array_unique ([
128+ ...FileClassLocator::createFromDirectories ($ this ->paths , $ this ->excludePaths , $ this ->fileExtension )->getClassNames (),
129+ ...$ classNames ,
130+ ]);
183131 }
184132
185- $ classes = [];
186- $ declared = get_declared_classes ();
187-
188- foreach ($ declared as $ className ) {
189- $ rc = new ReflectionClass ($ className );
190-
191- $ sourceFile = $ rc ->getFileName ();
192-
193- if (! in_array ($ sourceFile , $ includedFiles , true ) || $ this ->isTransient ($ className )) {
194- continue ;
195- }
196-
197- $ classes [] = $ className ;
198- }
199-
200- $ this ->classNames = $ classes ;
201-
202- return $ classes ;
203- }
204-
205- /**
206- * @param iterable<SplFileInfo> $filesIterator
207- *
208- * @return Generator<int,string>
209- */
210- private function pathNameIterator (iterable $ filesIterator ): Generator
211- {
212- foreach ($ filesIterator as $ file ) {
213- yield $ file ->getPathname ();
214- }
133+ return $ this ->classNames = array_values (array_filter (
134+ $ classNames ,
135+ fn (string $ className ): bool => ! $ this ->isTransient ($ className ),
136+ ));
215137 }
216138}
0 commit comments