ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
Finder.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
31use AppendIterator;
32use ArrayIterator;
33use Closure;
34use Countable;
38use InvalidArgumentException;
39use Iterator as PhpIterator;
40use IteratorAggregate;
41use LogicException;
42use RecursiveIteratorIterator;
44
52final class Finder implements IteratorAggregate, Countable
53{
57 private const IGNORE_VCS_FILES = 1;
61 private const IGNORE_DOT_FILES = 2;
63 private array $vcsPatterns = ['.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg'];
65 private array $iterators = [];
67 protected array $dirs = [];
69 private array $exclude = [];
70 private int $ignore = 0;
72 private bool $reverseSorting = false;
74 private array $dates = [];
76 private array $sizes = [];
78 private array $depths = [];
81
82 public function __construct(private Filesystem $filesystem)
83 {
84 $this->ignore = self::IGNORE_VCS_FILES | self::IGNORE_DOT_FILES;
85 }
86
87 public function files(): self
88 {
89 $clone = clone $this;
91
92 return $clone;
93 }
94
95 public function directories(): self
96 {
97 $clone = clone $this;
99
100 return $clone;
101 }
102
103 public function allTypes(): self
104 {
105 $clone = clone $this;
106 $clone->mode = FileTypeFilterIterator::ALL;
107
108 return $clone;
109 }
110
115 public function exclude(array $directories): self
116 {
117 array_walk($directories, static function ($directory): void {
118 if (!is_string($directory)) {
119 throw new InvalidArgumentException(sprintf('Invalid directory given: %s', $directory::class));
120 }
121 });
122
123 $clone = clone $this;
124 $clone->exclude = array_merge($clone->exclude, $directories);
125
126 return $clone;
127 }
128
133 public function in(array $directories): self
134 {
135 array_walk($directories, static function ($directory): void {
136 if (!is_string($directory)) {
137 throw new InvalidArgumentException(sprintf('Invalid directory given: %s', $directory::class));
138 }
139 });
140
141 $clone = clone $this;
142 $clone->dirs = array_unique(array_merge($clone->dirs, $directories));
143
144 return $clone;
145 }
146
158 public function depth(string|int $level): self
159 {
160 $clone = clone $this;
161 $clone->depths[] = new NumberComparator((string) $level);
162
163 return $clone;
164 }
165
181 public function date(string $date): self
182 {
183 $clone = clone $this;
184 $clone->dates[] = new DateComparator($date);
185
186 return $clone;
187 }
188
202 public function size(string|int|array $sizes): self
203 {
204 $sizes = is_array($sizes) ? $sizes : [$sizes];
205
206 $clone = clone $this;
207
208 foreach ($sizes as $size) {
209 $clone->sizes[] = new NumberComparator((string) $size);
210 }
211
212 return $clone;
213 }
214
215 public function reverseSorting(): self
216 {
217 $clone = clone $this;
218 $clone->reverseSorting = true;
219
220 return $clone;
221 }
222
223 public function ignoreVCS(bool $ignoreVCS): self
224 {
225 $clone = clone $this;
226 if ($ignoreVCS) {
227 $clone->ignore |= self::IGNORE_VCS_FILES;
228 } else {
229 $clone->ignore &= ~self::IGNORE_VCS_FILES;
230 }
231
232 return $clone;
233 }
234
239 public function addVCSPattern(array $pattern): self
240 {
241 array_walk($pattern, static function ($p): void {
242 if (!is_string($p)) {
243 throw new InvalidArgumentException(sprintf('Invalid pattern given: %s', $p::class));
244 }
245 });
246
247 $clone = clone $this;
248 foreach ($pattern as $p) {
249 $clone->vcsPatterns[] = $p;
250 }
251
252 $clone->vcsPatterns = array_unique($clone->vcsPatterns);
253
254 return $clone;
255 }
256
262 public function sort(Closure $closure): self
263 {
264 $clone = clone $this;
265 $clone->sort = $closure;
266
267 return $clone;
268 }
269
270 public function sortByName(bool $useNaturalSort = false): self
271 {
272 $clone = clone $this;
273 $clone->sort = SortableIterator::SORT_BY_NAME;
274 if ($useNaturalSort) {
276 }
277
278 return $clone;
279 }
280
281 public function sortByType(): self
282 {
283 $clone = clone $this;
284 $clone->sort = SortableIterator::SORT_BY_TYPE;
285
286 return $clone;
287 }
288
289 public function sortByTime(): self
290 {
291 $clone = clone $this;
292 $clone->sort = SortableIterator::SORT_BY_TIME;
293
294 return $clone;
295 }
296
302 public function append(iterable $iterator): self
303 {
304 $clone = clone $this;
305
306 if ($iterator instanceof IteratorAggregate) {
307 $clone->iterators[] = $iterator->getIterator();
308 } elseif ($iterator instanceof PhpIterator) {
309 $clone->iterators[] = $iterator;
310 } elseif (is_iterable($iterator)) {
311 $it = new ArrayIterator();
312 foreach ($iterator as $file) {
313 if ($file instanceof MetadataType) {
314 $it->append($file);
315 } else {
316 throw new InvalidArgumentException(
317 'Finder::append() method wrong argument type in passed iterator.'
318 );
319 }
320 }
321 $clone->iterators[] = $it;
322 } else {
323 throw new InvalidArgumentException('Finder::append() method wrong argument type.');
324 }
325
326 return $clone;
327 }
328
329 private function searchInDirectory(string $dir): \Traversable
330 {
331 if (self::IGNORE_VCS_FILES === (self::IGNORE_VCS_FILES & $this->ignore)) {
332 $this->exclude = array_merge($this->exclude, $this->vcsPatterns);
333 }
334
335 $iterator = new RecursiveDirectoryIterator($this->filesystem, $dir);
336
337 if ($this->exclude) {
338 $iterator = new ExcludeDirectoryFilterIterator($iterator, $this->exclude);
339 }
340
341 $iterator = new RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST);
342
343 if ($this->depths) {
344 $iterator = new DepthRangeFilterIterator($iterator, $this->depths);
345 }
346
347 if ($this->mode !== 0) {
348 $iterator = new FileTypeFilterIterator($iterator, $this->mode);
349 }
350
351 if ($this->dates) {
352 $iterator = new DateRangeFilterIterator($this->filesystem, $iterator, $this->dates);
353 }
354
355 if ($this->sizes) {
356 $iterator = new SizeRangeFilterIterator($this->filesystem, $iterator, $this->sizes);
357 }
358
359 if ($this->sort || $this->reverseSorting) {
360 $iteratorAggregate = new SortableIterator(
361 $this->filesystem,
362 $iterator,
363 $this->sort,
364 $this->reverseSorting
365 );
366 $iterator = $iteratorAggregate->getIterator();
367 }
368
369 return $iterator;
370 }
371
377 #[\ReturnTypeWillChange]
378 public function getIterator(): \Iterator
379 {
380 if ([] === $this->dirs && [] === $this->iterators) {
381 throw new LogicException('You must call one of in() or append() methods before iterating over a Finder.');
382 }
383
384 if (1 === count($this->dirs) && [] === $this->iterators) {
385 return $this->searchInDirectory($this->dirs[0]);
386 }
387
388 $iterator = new AppendIterator();
389 foreach ($this->dirs as $dir) {
390 $iterator->append($this->searchInDirectory($dir));
391 }
392
393 foreach ($this->iterators as $it) {
394 $iterator->append($it);
395 }
396
397 return $iterator;
398 }
399
403 public function count(): int
404 {
405 return iterator_count($this->getIterator());
406 }
407}
This class holds all default metadata send by the filesystem adapters.
Definition: Metadata.php:33
append(iterable $iterator)
Appends an existing set of files/directories to the finder.
Definition: Finder.php:302
searchInDirectory(string $dir)
Definition: Finder.php:329
size(string|int|array $sizes)
Adds tests for file sizes.
Definition: Finder.php:202
exclude(array $directories)
Definition: Finder.php:115
sort(Closure $closure)
Sorts files and directories by an anonymous function.
Definition: Finder.php:262
depth(string|int $level)
Adds tests for the directory depth.
Definition: Finder.php:158
addVCSPattern(array $pattern)
Definition: Finder.php:239
ignoreVCS(bool $ignoreVCS)
Definition: Finder.php:223
in(array $directories)
Definition: Finder.php:133
date(string $date)
Adds tests for file dates.
Definition: Finder.php:181
sortByName(bool $useNaturalSort=false)
Definition: Finder.php:270
__construct(private Filesystem $filesystem)
Definition: Finder.php:82
The filesystem interface provides the public interface for the Filesystem service API consumer.
Definition: Filesystem.php:37
The possible metadata types of the filesystem metadata.