Skip to content

Commit ff07aaa

Browse files
committed
added Finder::and()
1 parent 8a5cb73 commit ff07aaa

File tree

3 files changed

+109
-23
lines changed

3 files changed

+109
-23
lines changed

src/Utils/Finder.php

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,19 @@ class Finder implements \IteratorAggregate
2626
{
2727
use Nette\SmartObject;
2828

29-
private array $find = [];
30-
private array $in = [];
31-
private array $filters = [];
32-
private array $recurseFilters = [];
29+
/** @var FinderBatch[] */
30+
private array $batches = [];
31+
private FinderBatch $batch;
3332
private bool $selfFirst = true;
3433
private int $maxDepth = -1;
3534

3635

36+
public function __construct()
37+
{
38+
$this->and();
39+
}
40+
41+
3742
/**
3843
* Begins search for files and directories matching mask.
3944
* @param string ...$masks
@@ -80,7 +85,7 @@ public function files(string ...$masks): static
8085
if (str_starts_with($mask, '**/')) {
8186
$mask = substr($mask, 3);
8287
}
83-
$this->find[] = [$mask, 'isFile'];
88+
$this->batch->find[] = [$mask, 'isFile'];
8489
}
8590

8691
return $this;
@@ -100,7 +105,7 @@ public function directories(string ...$masks): static
100105
if (str_starts_with($mask, '**/')) {
101106
$mask = substr($mask, 3);
102107
}
103-
$this->find[] = [$mask, 'isDir'];
108+
$this->batch->find[] = [$mask, 'isDir'];
104109
}
105110

106111
return $this;
@@ -119,7 +124,7 @@ public function in(...$paths): static
119124
throw new Nette\InvalidArgumentException("Invalid directory '$path'");
120125
}
121126
$path = rtrim(self::normalizeSlashes($path), '/');
122-
$this->in[] = $path;
127+
$this->batch->in[] = $path;
123128
}
124129

125130
return $this;
@@ -138,7 +143,7 @@ public function from(...$paths): static
138143
throw new Nette\InvalidArgumentException("Invalid directory '$path'");
139144
}
140145
$path = rtrim(self::normalizeSlashes($path), '/');
141-
$this->in[] = $path . '/**';
146+
$this->batch->in[] = $path . '/**';
142147
}
143148

144149
return $this;
@@ -155,6 +160,16 @@ public function childFirst(): static
155160
}
156161

157162

163+
/**
164+
* Starts defining a new search group.
165+
*/
166+
public function and(): static
167+
{
168+
$this->batches[] = $this->batch = new FinderBatch;
169+
return $this;
170+
}
171+
172+
158173
/********************* filtering ****************d*g**/
159174

160175

@@ -185,14 +200,17 @@ public function exclude(...$masks): static
185200
}
186201

187202

203+
/********************* filtering ****************d*g**/
204+
205+
188206
/**
189207
* Restricts the search using callback.
190208
* @param callable(FileInfo): bool $callback
191209
* @param string ...$masks
192210
*/
193211
public function filter(callable $callback): static
194212
{
195-
$this->filters[] = $callback;
213+
$this->batch->filters[] = $callback;
196214
return $this;
197215
}
198216

@@ -203,7 +221,7 @@ public function filter(callable $callback): static
203221
*/
204222
public function recurseFilter(callable $callback): static
205223
{
206-
$this->recurseFilters[] = $callback;
224+
$this->batch->recurseFilters[] = $callback;
207225
return $this;
208226
}
209227

@@ -304,7 +322,7 @@ private function traverseDir(string $dir, array $searches, array $subDirs = []):
304322
foreach ($searches as $search) {
305323
if (
306324
$search->recursive
307-
&& $this->invokeFilters($this->recurseFilters, $file, $cache)
325+
&& $this->invokeFilters($search->batch->recurseFilters, $file, $cache)
308326
) {
309327
$into[] = $search;
310328
}
@@ -320,7 +338,7 @@ private function traverseDir(string $dir, array $searches, array $subDirs = []):
320338
if (
321339
$file->{$search->mode}()
322340
&& preg_match($search->find, $relativePathname)
323-
&& $this->invokeFilters($this->filters, $file, $cache)
341+
&& $this->invokeFilters($search->batch->filters, $file, $cache)
324342
) {
325343
yield $pathName => $file;
326344
break;
@@ -351,17 +369,19 @@ private function invokeFilters(array $filters, FileInfo $file, array &$cache): b
351369
private function prepare(): array
352370
{
353371
$groups = [];
354-
foreach ($this->find as [$mask, $mode]) {
355-
if (FileSystem::isAbsolute($mask)) {
356-
if ($this->in) {
357-
throw new Nette\InvalidStateException("You cannot combine the absolute path in the mask '$mask' and the directory to search '{$this->in[0]}'.");
358-
}
359-
[$base, $rest, $recursive] = self::splitRecursivePart($mask);
360-
$groups[$base][] = (object) ['find' => $this->buildPattern($rest), 'mode' => $mode, 'recursive' => $recursive];
361-
} else {
362-
foreach ($this->in ?: ['.'] as $in) {
363-
[$base, $rest, $recursive] = self::splitRecursivePart($in . '/' . $mask);
364-
$groups[$base][] = (object) ['find' => $this->buildPattern($rest), 'mode' => $mode, 'recursive' => $recursive];
372+
foreach ($this->batches as $batch) {
373+
foreach ($batch->find as [$mask, $mode]) {
374+
if (FileSystem::isAbsolute($mask)) {
375+
if ($batch->in) {
376+
throw new Nette\InvalidStateException("You cannot combine the absolute path in the mask '$mask' and the directory to search '{$batch->in[0]}'.");
377+
}
378+
[$base, $rest, $recursive] = self::splitRecursivePart($mask);
379+
$groups[$base][] = (object) ['find' => $this->buildPattern($rest), 'mode' => $mode, 'recursive' => $recursive, 'batch' => $batch];
380+
} else {
381+
foreach ($batch->in ?: ['.'] as $in) {
382+
[$base, $rest, $recursive] = self::splitRecursivePart($in . '/' . $mask);
383+
$groups[$base][] = (object) ['find' => $this->buildPattern($rest), 'mode' => $mode, 'recursive' => $recursive, 'batch' => $batch];
384+
}
365385
}
366386
}
367387
}

src/Utils/FinderBatch.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
/**
4+
* This file is part of the Nette Framework (https://nette.org)
5+
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace Nette\Utils;
11+
12+
use Nette;
13+
14+
15+
/** @internal */
16+
final class FinderBatch
17+
{
18+
use Nette\SmartObject;
19+
20+
public array $find = [];
21+
public array $in = [];
22+
public array $filters = [];
23+
public array $recurseFilters = [];
24+
}

tests/Utils/Finder.and.phpt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
/**
4+
* Test: Nette\Utils\Finder multiple batches.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
use Nette\Utils\Finder;
10+
use Tester\Assert;
11+
12+
13+
require __DIR__ . '/../bootstrap.php';
14+
15+
16+
function export($iterator)
17+
{
18+
$arr = [];
19+
foreach ($iterator as $key => $value) {
20+
$arr[] = strtr($key, '\\', '/');
21+
}
22+
23+
sort($arr);
24+
return $arr;
25+
}
26+
27+
28+
test('and', function () {
29+
$finder = Finder::findFiles('file.txt')
30+
->in('files')
31+
->and()
32+
->directories('subdir*')->from('files')
33+
->and()
34+
->files('file.txt')->from('files/*/subdir*');
35+
36+
Assert::same([
37+
'files/file.txt',
38+
'files/subdir',
39+
'files/subdir/subdir2',
40+
'files/subdir/subdir2/file.txt',
41+
], export($finder));
42+
});

0 commit comments

Comments
 (0)