25
25
use RecursiveIteratorIterator ;
26
26
use RuntimeException ;
27
27
use SplFileInfo ;
28
+ use Toolkit \Stdlib \Str ;
28
29
use Traversable ;
29
30
use UnexpectedValueException ;
30
31
use function array_flip ;
34
35
use function fnmatch ;
35
36
use function get_object_vars ;
36
37
use function is_iterable ;
38
+ use function is_string ;
37
39
use function iterator_count ;
38
40
use function str_contains ;
39
41
use function stream_get_meta_data ;
@@ -78,16 +80,14 @@ final class FileFinder implements IteratorAggregate, Countable
78
80
/** @var bool */
79
81
private bool $ ignoreVcsAdded = false ;
80
82
81
- /**
82
- * @var bool
83
- */
83
+ /** @var bool */
84
84
private bool $ skipUnreadableDirs = true ;
85
85
86
86
/** @var array */
87
87
private array $ dirs = [];
88
88
89
89
/**
90
- * File ,dir name match.
90
+ * add include file ,dir name match.
91
91
*
92
92
* eg: '.php' '*.php' 'test.php'
93
93
*
@@ -96,26 +96,28 @@ final class FileFinder implements IteratorAggregate, Countable
96
96
private array $ names = [];
97
97
98
98
/**
99
- * File ,dir name exclude
99
+ * add exclude file ,dir name patterns
100
100
*
101
101
* eg: '.php' '*.php' 'test.php'
102
102
*
103
103
* @var array
104
104
*/
105
105
private array $ notNames = [];
106
106
107
- /** @var array */
107
+ /** @var array<string> include paths pattern. */
108
108
private array $ paths = [];
109
109
110
- /** @var array */
110
+ /** @var array<string> exclude paths pattern */
111
111
private array $ notPaths = [];
112
112
113
- /**
114
- * @var array exclude directories
115
- */
113
+ /** @var array<string> exclude directory names */
116
114
private array $ excludes = [];
117
115
118
- /** @var array */
116
+ /**
117
+ * path filters. each filter like: `Closure(SplFileInfo):bool`, return FALSE to exclude.
118
+ *
119
+ * @var array
120
+ */
119
121
private array $ filters = [];
120
122
121
123
/** @var array */
@@ -213,6 +215,8 @@ public function onlyFiles(): self
213
215
}
214
216
215
217
/**
218
+ * add include file,dir name match pattern.
219
+ *
216
220
* $finder->name('*.php')
217
221
* $finder->name('test.php')
218
222
*
@@ -222,28 +226,29 @@ public function onlyFiles(): self
222
226
*/
223
227
public function name (string $ pattern ): self
224
228
{
225
- if ($ pattern ) {
226
- $ this ->names [] = $ pattern ;
227
- }
228
-
229
- return $ this ;
229
+ return $ this ->addNames ($ pattern );
230
230
}
231
231
232
232
/**
233
+ * add include file,dir name match pattern.
234
+ *
233
235
* @param array|string $patterns
234
236
*
235
237
* @return FileFinder
236
238
*/
237
239
public function addNames (array |string $ patterns ): self
238
240
{
239
241
if ($ patterns ) {
240
- $ this ->names = array_merge ($ this ->names , (array )$ patterns );
242
+ $ patterns = is_string ($ patterns ) ? Str::splitTrimmed ($ patterns ) : $ patterns ;
243
+ // append
244
+ $ this ->names = array_merge ($ this ->names , $ patterns );
241
245
}
242
-
243
246
return $ this ;
244
247
}
245
248
246
249
/**
250
+ * add exclude file,dir name patterns
251
+ *
247
252
* @param string $pattern
248
253
*
249
254
* @return FileFinder
@@ -255,20 +260,25 @@ public function notName(string $pattern): self
255
260
}
256
261
257
262
/**
263
+ * add exclude file,dir name patterns
264
+ *
258
265
* @param array|string $patterns
259
266
*
260
267
* @return FileFinder
261
268
*/
262
269
public function notNames (array |string $ patterns ): self
263
270
{
264
271
if ($ patterns ) {
265
- $ this ->notNames = array_merge ($ this ->notNames , (array )$ patterns );
272
+ $ patterns = is_string ($ patterns ) ? Str::splitTrimmed ($ patterns ) : $ patterns ;
273
+ // append
274
+ $ this ->notNames = array_merge ($ this ->notNames , $ patterns );
266
275
}
267
-
268
276
return $ this ;
269
277
}
270
278
271
279
/**
280
+ * add exclude file,dir name patterns
281
+ *
272
282
* @param array|string $patterns
273
283
*
274
284
* @return FileFinder
@@ -279,6 +289,8 @@ public function addNotNames(array|string $patterns): self
279
289
}
280
290
281
291
/**
292
+ * add include paths pattern.
293
+ * eg:
282
294
* $finder->path('some/special/dir')
283
295
*
284
296
* @param string $pattern
@@ -292,33 +304,37 @@ public function path(string $pattern): self
292
304
}
293
305
294
306
/**
307
+ * add include paths pattern.
308
+ *
295
309
* @param array|string $patterns
296
310
*
297
311
* @return FileFinder
298
312
*/
299
313
public function addPaths (array |string $ patterns ): self
300
314
{
301
315
if ($ patterns ) {
302
- $ this ->paths = array_merge ($ this ->paths , (array )$ patterns );
316
+ $ patterns = is_string ($ patterns ) ? Str::splitTrimmed ($ patterns ) : $ patterns ;
317
+ // append
318
+ $ this ->paths = array_merge ($ this ->paths , $ patterns );
303
319
}
304
-
305
320
return $ this ;
306
321
}
307
322
308
323
/**
324
+ * add exclude paths pattern
325
+ *
309
326
* @param string $pattern
310
327
*
311
328
* @return FileFinder
312
329
*/
313
330
public function notPath (string $ pattern ): self
314
331
{
315
- if ($ pattern ) {
316
- $ this ->notPaths [] = $ pattern ;
317
- }
318
- return $ this ;
332
+ return $ this ->addNotPaths ($ pattern );
319
333
}
320
334
321
335
/**
336
+ * add exclude paths pattern. alias of addNotPaths()
337
+ *
322
338
* @param array|string $patterns
323
339
*
324
340
* @return FileFinder
@@ -329,30 +345,37 @@ public function notPaths(array|string $patterns): self
329
345
}
330
346
331
347
/**
348
+ * add exclude paths pattern.
349
+ * eg: $finder->addNotPaths(['vendor', 'node_modules', 'bin/'])
350
+ *
332
351
* @param array|string $patterns
333
352
*
334
353
* @return FileFinder
335
354
*/
336
355
public function addNotPaths (array |string $ patterns ): self
337
356
{
338
357
if ($ patterns ) {
339
- $ this ->notPaths = array_merge ($ this ->notPaths , (array )$ patterns );
358
+ $ patterns = is_string ($ patterns ) ? Str::splitTrimmed ($ patterns ) : $ patterns ;
359
+ // append
360
+ $ this ->notPaths = array_merge ($ this ->notPaths , $ patterns );
340
361
}
341
-
342
362
return $ this ;
343
363
}
344
364
345
365
/**
346
- * @param $dirs
366
+ * exclude directory names
367
+ *
368
+ * @param array|string $dirNames
347
369
*
348
370
* @return FileFinder
349
371
*/
350
- public function exclude ($ dirs ): self
372
+ public function exclude (array | string $ dirNames ): self
351
373
{
352
- if ($ dirs ) {
353
- $ this ->excludes = array_merge ($ this ->excludes , (array )$ dirs );
374
+ if ($ dirNames ) {
375
+ $ dirNames = is_string ($ dirNames ) ? Str::splitTrimmed ($ dirNames ) : $ dirNames ;
376
+ // append
377
+ $ this ->excludes = array_merge ($ this ->excludes , $ dirNames );
354
378
}
355
-
356
379
return $ this ;
357
380
}
358
381
@@ -429,14 +452,13 @@ public function followLinks(mixed $followLinks = true): self
429
452
}
430
453
431
454
/**
432
- * @param Closure $closure
455
+ * @param Closure(SplFileInfo): bool $closure
433
456
*
434
457
* @return FileFinder
435
458
*/
436
459
public function filter (Closure $ closure ): self
437
460
{
438
461
$ this ->filters [] = $ closure ;
439
-
440
462
return $ this ;
441
463
}
442
464
@@ -460,9 +482,10 @@ public function in(array|string $dirs): self
460
482
public function inDir (array |string $ dirs ): self
461
483
{
462
484
if ($ dirs ) {
463
- $ this ->dirs = array_merge ($ this ->dirs , (array )$ dirs );
485
+ $ dirs = is_string ($ dirs ) ? Str::splitTrimmed ($ dirs ) : $ dirs ;
486
+ // append
487
+ $ this ->dirs = array_merge ($ this ->dirs , $ dirs );
464
488
}
465
-
466
489
return $ this ;
467
490
}
468
491
@@ -585,7 +608,7 @@ private function findInDirectory(string $dir): Iterator
585
608
$ flags |= RecursiveDirectoryIterator::FOLLOW_SYMLINKS ;
586
609
}
587
610
588
- $ iterator = new class ($ dir , $ flags ) extends RecursiveDirectoryIterator {
611
+ $ iterator = new class ($ dir , $ flags, $ this -> skipUnreadableDirs ) extends RecursiveDirectoryIterator {
589
612
private string $ rootPath ;
590
613
private string $ subPath = '' ;
591
614
private bool |null $ rewindable = null ;
@@ -610,8 +633,9 @@ public function __construct(string $path, int $flags, bool $skipUnreadableDirs =
610
633
611
634
public function current (): SplFileInfo
612
635
{
636
+ // vdump($this->getPathname(), $this);
613
637
if (null === $ subPathname = $ this ->subPath ) {
614
- $ subPathname = $ this ->subPath = ( string ) $ this ->getSubPath ();
638
+ $ subPathname = $ this ->subPath = $ this ->getSubPath ();
615
639
}
616
640
617
641
if ('' !== $ subPathname ) {
@@ -620,8 +644,9 @@ public function current(): SplFileInfo
620
644
621
645
$ subPathname .= $ this ->getFilename ();
622
646
623
- // $fileInfo = new \SplFileInfo($this->getPathname());
624
- $ fileInfo = new SplFileInfo ($ this ->rootPath . $ this ->directorySep . $ subPathname );
647
+ $ fileInfo = new SplFileInfo ($ this ->getPathname ());
648
+ // $fileInfo = new SplFileInfo($this->rootPath . $this->directorySep . $subPathname);
649
+ // vdump($this->rootPath, $subPathname, $fileInfo);
625
650
// add props
626
651
$ fileInfo ->relativePath = $ this ->subPath ;
627
652
$ fileInfo ->relativePathname = $ subPathname ;
@@ -634,7 +659,7 @@ public function getChildren(): RecursiveDirectoryIterator
634
659
try {
635
660
$ children = parent ::getChildren ();
636
661
if ($ children instanceof self) {
637
- $ children ->rootPath = $ this ->rootPath ;
662
+ $ children ->rootPath = $ this ->rootPath ;
638
663
$ children ->rewindable = &$ this ->rewindable ;
639
664
$ children ->skipUnreadableDirs = $ this ->skipUnreadableDirs ;
640
665
}
@@ -680,6 +705,7 @@ public function isRewindable(): ?bool
680
705
// exclude directories
681
706
if ($ this ->excludes ) {
682
707
$ iterator = new class ($ iterator , $ this ->excludes ) extends FilterIterator implements RecursiveIterator {
708
+ /** @var array<string, int> */
683
709
private array $ excludes ;
684
710
685
711
private RecursiveIterator $ iterator ;
@@ -734,6 +760,7 @@ public function __construct(Iterator $iterator, int $mode)
734
760
735
761
public function accept (): bool
736
762
{
763
+ /** @var SplFileInfo $info */
737
764
$ info = $ this ->current ();
738
765
if (FileFinder::ONLY_DIR === $ this ->mode && $ info ->isFile ()) {
739
766
return false ;
@@ -796,6 +823,7 @@ public function __construct(Iterator $iterator, array $filters)
796
823
797
824
public function accept (): bool
798
825
{
826
+ /** @var SplFileInfo $fileInfo */
799
827
$ fileInfo = $ this ->current ();
800
828
foreach ($ this ->filters as $ filter ) {
801
829
if (false === $ filter ($ fileInfo )) {
@@ -810,8 +838,9 @@ public function accept(): bool
810
838
811
839
if ($ this ->paths || $ this ->notPaths ) {
812
840
$ iterator = new class ($ iterator , $ this ->paths , $ this ->notPaths ) extends FilterIterator {
841
+ /** @var array<string> */
813
842
private array $ paths ;
814
-
843
+ /** @var array<string> */
815
844
private array $ notPaths ;
816
845
817
846
public function __construct (Iterator $ iterator , array $ paths , array $ notPaths )
@@ -823,7 +852,8 @@ public function __construct(Iterator $iterator, array $paths, array $notPaths)
823
852
824
853
public function accept (): bool
825
854
{
826
- $ pathname = $ this ->current ()->relativePathname ;
855
+ /** @var string $pathname {@see SplFileInfo::getPathname()} */
856
+ $ pathname = $ this ->current ()->getPathname ();
827
857
if ('\\' === DIRECTORY_SEPARATOR ) {
828
858
$ pathname = str_replace ('\\' , '/ ' , $ pathname );
829
859
}
0 commit comments