44
55namespace Tempest \Core \Kernel ;
66
7- use FilesystemIterator ;
8- use RecursiveDirectoryIterator ;
9- use RecursiveIteratorIterator ;
10- use SplFileInfo ;
117use Tempest \Core \AppConfig ;
128use Tempest \Core \ConfigCache ;
139use Tempest \Core \Kernel ;
10+ use Tempest \Support \Arr \MutableArray ;
1411use Tempest \Support \Str ;
1512
16- use function Tempest \Support \arr ;
17-
1813/** @internal */
1914final readonly class LoadConfig
2015{
@@ -40,21 +35,11 @@ public function __invoke(): void
4035 */
4136 public function find (): array
4237 {
43- $ configPaths = [] ;
38+ $ configPaths = new MutableArray () ;
4439
4540 // Scan for config files in all discovery locations
4641 foreach ($ this ->kernel ->discoveryLocations as $ discoveryLocation ) {
47- $ directories = new RecursiveDirectoryIterator ($ discoveryLocation ->path , FilesystemIterator::UNIX_PATHS | FilesystemIterator::SKIP_DOTS );
48- $ files = new RecursiveIteratorIterator ($ directories );
49-
50- /** @var SplFileInfo $file */
51- foreach ($ files as $ file ) {
52- if (! str_ends_with ($ file ->getPathname (), '.config.php ' )) {
53- continue ;
54- }
55-
56- $ configPaths [] = $ file ->getPathname ();
57- }
42+ $ this ->scan ($ discoveryLocation ->path , $ configPaths );
5843 }
5944
6045 $ suffixes = [
@@ -64,7 +49,7 @@ public function find(): array
6449 'development ' => ['.dev.config.php ' , '.local.config.php ' ],
6550 ];
6651
67- return arr ( $ configPaths)
52+ return $ configPaths
6853 ->filter (fn (string $ path ) => match (true ) {
6954 $ this ->appConfig ->environment ->isLocal () => ! Str \contains ($ path , [...$ suffixes ['production ' ], ...$ suffixes ['staging ' ], ...$ suffixes ['testing ' ]]),
7055 $ this ->appConfig ->environment ->isProduction () => ! Str \contains ($ path , [...$ suffixes ['staging ' ], ...$ suffixes ['testing ' ], ...$ suffixes ['development ' ]]),
@@ -94,4 +79,54 @@ public function find(): array
9479 ->values ()
9580 ->toArray ();
9681 }
82+
83+ /**
84+ * Recursively scan a directory and apply a given set of discovery classes to all files
85+ */
86+ private function scan (string $ path , MutableArray $ configPaths ): void
87+ {
88+ $ input = realpath ($ path );
89+
90+ // Make sure the path is valid
91+ if ($ input === false ) {
92+ return ;
93+ }
94+
95+ // Directories are scanned recursively
96+ if (is_dir ($ input )) {
97+ // Make sure the current directory is not marked for skipping
98+ if ($ this ->shouldSkipDirectory ($ input )) {
99+ return ;
100+ }
101+
102+ foreach (scandir ($ input , SCANDIR_SORT_NONE ) as $ subPath ) {
103+ // `.` and `..` are skipped
104+ if ($ subPath === '. ' || $ subPath === '.. ' ) {
105+ continue ;
106+ }
107+
108+ // Scan all files and folders within this directory
109+ $ this ->scan ("{$ input }/ {$ subPath }" , $ configPaths );
110+ }
111+
112+ return ;
113+ }
114+
115+ // Only include config files
116+ if (! str_ends_with ($ input , '.config.php ' )) {
117+ return ;
118+ }
119+
120+ $ configPaths [] = $ input ;
121+ }
122+
123+ /**
124+ * Check whether a given directory should be skipped
125+ */
126+ private function shouldSkipDirectory (string $ path ): bool
127+ {
128+ $ directory = pathinfo ($ path , PATHINFO_BASENAME );
129+
130+ return $ directory === 'node_modules ' || $ directory === 'vendor ' ;
131+ }
97132}
0 commit comments