ILIAS  release_8 Revision v8.23
Finder.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
6 
8 use ArrayIterator;
9 use Closure;
10 use Countable;
15 use Iterator as PhpIterator;
17 use LogicException;
20 use 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 
44 final 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 
70  public function __construct(Filesystem $filesystem)
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 }
size($sizes)
Adds tests for file sizes.
Definition: Finder.php:204
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
depth($level)
Adds tests for the directory depth.
Definition: Finder.php:158
ignoreVCS(bool $ignoreVCS)
Definition: Finder.php:227
__construct(Filesystem $filesystem)
Definition: Finder.php:70
sort(Closure $closure)
Sorts files and directories by an anonymous function.
Definition: Finder.php:273
addVCSPattern(array $pattern)
Definition: Finder.php:244
searchInDirectory(string $dir)
Definition: Finder.php:340
ILIAS Filesystem Filesystem $filesystem
Definition: Finder.php:49
exclude(array $directories)
Definition: Finder.php:105
Class MetadataType.
date(string $date)
Adds tests for file dates.
Definition: Finder.php:182
append(iterable $iterator)
Appends an existing set of files/directories to the finder.
Definition: Finder.php:315
Class FlySystemFileAccessTest disabled disabled disabled.
in(array $directories)
Definition: Finder.php:128
sortByName(bool $useNaturalSort=false)
Definition: Finder.php:281