ILIAS  release_8 Revision v8.24
Finder.php
Go to the documentation of this file.
1<?php
2
3declare(strict_types=1);
4
6
7use AppendIterator;
8use ArrayIterator;
9use Closure;
10use Countable;
14use InvalidArgumentException;
15use Iterator as PhpIterator;
16use IteratorAggregate;
17use LogicException;
18use RecursiveIteratorIterator;
19use ReturnTypeWillChange;
20use Traversable;
22
23/******************************************************************************
24 *
25 * This file is part of ILIAS, a powerful learning management system.
26 *
27 * ILIAS is licensed with the GPL-3.0, you should have received a copy
28 * of said license along with the source code.
29 *
30 * If this is not the case or you just want to try ILIAS, you'll find
31 * us at:
32 * https://www.ilias.de
33 * https://github.com/ILIAS-eLearning
34 *
35 *****************************************************************************/
36
44final class Finder implements IteratorAggregate, Countable
45{
46 private const IGNORE_VCS_FILES = 1;
47 private const IGNORE_DOT_FILES = 2;
48
49 private \ILIAS\Filesystem\Filesystem $filesystem;
51 private array $vcsPatterns = ['.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg'];
53 private array $iterators = [];
55 protected array $dirs = [];
57 private array $exclude = [];
58 private int $ignore = 0;
60 private bool $reverseSorting = false;
62 private array $dates = [];
64 private array $sizes = [];
66 private array $depths = [];
69
71 {
72 $this->filesystem = $filesystem;
73 $this->ignore = self::IGNORE_VCS_FILES | self::IGNORE_DOT_FILES;
74 }
75
76 public function files(): self
77 {
78 $clone = clone $this;
80
81 return $clone;
82 }
83
84 public function directories(): self
85 {
86 $clone = clone $this;
88
89 return $clone;
90 }
91
92 public function allTypes(): self
93 {
94 $clone = clone $this;
96
97 return $clone;
98 }
99
105 public function exclude(array $directories): self
106 {
107 array_walk($directories, static function ($directory): void {
108 if (!is_string($directory)) {
109 if (is_object($directory)) {
110 throw new InvalidArgumentException(sprintf('Invalid directory given: %s', get_class($directory)));
111 }
112
113 throw new InvalidArgumentException(sprintf('Invalid directory given: %s', gettype($directory)));
114 }
115 });
116
117 $clone = clone $this;
118 $clone->exclude = array_merge($clone->exclude, $directories);
119
120 return $clone;
121 }
122
128 public function in(array $directories): self
129 {
130 array_walk($directories, static function ($directory): void {
131 if (!is_string($directory)) {
132 if (is_object($directory)) {
133 throw new InvalidArgumentException(sprintf('Invalid directory given: %s', get_class($directory)));
134 }
135
136 throw new InvalidArgumentException(sprintf('Invalid directory given: %s', gettype($directory)));
137 }
138 });
139
140 $clone = clone $this;
141 $clone->dirs = array_unique(array_merge($clone->dirs, $directories));
142
143 return $clone;
144 }
145
158 public function depth($level): self
159 {
160 $clone = clone $this;
161 $clone->depths[] = new Comparator\NumberComparator((string) $level);
162
163 return $clone;
164 }
165
182 public function date(string $date): self
183 {
184 $clone = clone $this;
185 $clone->dates[] = new Comparator\DateComparator($date);
186
187 return $clone;
188 }
189
204 public function size($sizes): self
205 {
206 if (!is_array($sizes)) {
207 $sizes = [$sizes];
208 }
209
210 $clone = clone $this;
211
212 foreach ($sizes as $size) {
213 $clone->sizes[] = new Comparator\NumberComparator((string) $size);
214 }
215
216 return $clone;
217 }
218
219 public function reverseSorting(): self
220 {
221 $clone = clone $this;
222 $clone->reverseSorting = true;
223
224 return $clone;
225 }
226
227 public function ignoreVCS(bool $ignoreVCS): self
228 {
229 $clone = clone $this;
230 if ($ignoreVCS) {
231 $clone->ignore |= self::IGNORE_VCS_FILES;
232 } else {
233 $clone->ignore &= ~self::IGNORE_VCS_FILES;
234 }
235
236 return $clone;
237 }
238
244 public function addVCSPattern(array $pattern): self
245 {
246 array_walk($pattern, static function ($p): void {
247 if (!is_string($p)) {
248 if (is_object($p)) {
249 throw new InvalidArgumentException(sprintf('Invalid pattern given: %s', get_class($p)));
250 }
251
252 throw new InvalidArgumentException(sprintf('Invalid pattern given: %s', gettype($p)));
253 }
254 });
255
256 $clone = clone $this;
257 foreach ($pattern as $p) {
258 $clone->vcsPatterns[] = $p;
259 }
260
261 $clone->vcsPatterns = array_unique($clone->vcsPatterns);
262
263 return $clone;
264 }
265
273 public function sort(Closure $closure): self
274 {
275 $clone = clone $this;
276 $clone->sort = $closure;
277
278 return $clone;
279 }
280
281 public function sortByName(bool $useNaturalSort = false): self
282 {
283 $clone = clone $this;
285 if ($useNaturalSort) {
287 }
288
289 return $clone;
290 }
291
292 public function sortByType(): self
293 {
294 $clone = clone $this;
296
297 return $clone;
298 }
299
300 public function sortByTime(): self
301 {
302 $clone = clone $this;
304
305 return $clone;
306 }
307
315 public function append(iterable $iterator): self
316 {
317 $clone = clone $this;
318
319 if ($iterator instanceof IteratorAggregate) {
320 $clone->iterators[] = $iterator->getIterator();
321 } elseif ($iterator instanceof PhpIterator) {
322 $clone->iterators[] = $iterator;
323 } elseif ($iterator instanceof Traversable || is_array($iterator)) {
324 $it = new ArrayIterator();
325 foreach ($iterator as $file) {
326 if ($file instanceof MetadataType) {
327 $it->append($file);
328 } else {
329 throw new InvalidArgumentException('Finder::append() method wrong argument type in passed iterator.');
330 }
331 }
332 $clone->iterators[] = $it;
333 } else {
334 throw new InvalidArgumentException('Finder::append() method wrong argument type.');
335 }
336
337 return $clone;
338 }
339
340 private function searchInDirectory(string $dir): PhpIterator
341 {
342 if (self::IGNORE_VCS_FILES === (self::IGNORE_VCS_FILES & $this->ignore)) {
343 $this->exclude = array_merge($this->exclude, $this->vcsPatterns);
344 }
345
346 $iterator = new Iterator\RecursiveDirectoryIterator($this->filesystem, $dir);
347
348 if ($this->exclude) {
349 $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
350 }
351
352 $iterator = new RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST);
353
354 if ($this->depths) {
355 $iterator = new Iterator\DepthRangeFilterIterator($iterator, $this->depths);
356 }
357
358 if ($this->mode) {
359 $iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode);
360 }
361
362 if ($this->dates) {
363 $iterator = new Iterator\DateRangeFilterIterator($this->filesystem, $iterator, $this->dates);
364 }
365
366 if ($this->sizes) {
367 $iterator = new Iterator\SizeRangeFilterIterator($this->filesystem, $iterator, $this->sizes);
368 }
369
370 if ($this->sort || $this->reverseSorting) {
371 $iteratorAggregate = new Iterator\SortableIterator(
372 $this->filesystem,
373 $iterator,
374 $this->sort,
375 $this->reverseSorting
376 );
377 $iterator = $iteratorAggregate->getIterator();
378 }
379
380 return $iterator;
381 }
382
388 #[\ReturnTypeWillChange]
389 public function getIterator()
390 {
391 if (0 === count($this->dirs) && 0 === count($this->iterators)) {
392 throw new LogicException('You must call one of in() or append() methods before iterating over a Finder.');
393 }
394
395 if (1 === count($this->dirs) && 0 === count($this->iterators)) {
396 return $this->searchInDirectory($this->dirs[0]);
397 }
398
399 $iterator = new AppendIterator();
400 foreach ($this->dirs as $dir) {
401 $iterator->append($this->searchInDirectory($dir));
402 }
403
404 foreach ($this->iterators as $it) {
405 $iterator->append($it);
406 }
407
408 return $iterator;
409 }
410
414 public function count(): int
415 {
416 return iterator_count($this->getIterator());
417 }
418}
append(iterable $iterator)
Appends an existing set of files/directories to the finder.
Definition: Finder.php:315
searchInDirectory(string $dir)
Definition: Finder.php:340
size($sizes)
Adds tests for file sizes.
Definition: Finder.php:204
__construct(Filesystem $filesystem)
Definition: Finder.php:70
exclude(array $directories)
Definition: Finder.php:105
sort(Closure $closure)
Sorts files and directories by an anonymous function.
Definition: Finder.php:273
ILIAS Filesystem Filesystem $filesystem
Definition: Finder.php:49
addVCSPattern(array $pattern)
Definition: Finder.php:244
ignoreVCS(bool $ignoreVCS)
Definition: Finder.php:227
depth($level)
Adds tests for the directory depth.
Definition: Finder.php:158
in(array $directories)
Definition: Finder.php:128
date(string $date)
Adds tests for file dates.
Definition: Finder.php:182
sortByName(bool $useNaturalSort=false)
Definition: Finder.php:281
Interface Filesystem.
Definition: Filesystem.php:40
Class FlySystemFileAccessTest \Provider\FlySystem @runTestsInSeparateProcesses @preserveGlobalState d...