1<?php 2declare(strict_types=1); 3 4namespace ILIAS\Filesystem\Finder\Iterator; 5 6use ILIAS\Filesystem\DTO\Metadata; 7 8/** 9 * Class ExcludeDirectoryFilterIterator 10 * @package ILIAS\Filesystem\Finder\Iterator 11 * @author Michael Jansen <mjansen@databay.de> 12 */ 13class ExcludeDirectoryFilterIterator extends \FilterIterator implements \RecursiveIterator 14{ 15 /** @var \Iterator|\RecursiveIterator */ 16 private $iterator; 17 18 /** @var bool */ 19 private $isRecursive = false; 20 21 /** @var string[] */ 22 private $excludedDirs = []; 23 24 /** @var string */ 25 private $excludedPattern = ''; 26 27 /** 28 * @param \Iterator $iterator The Iterator to filter 29 * @param string[] $directories An array of directories to exclude 30 */ 31 public function __construct(\Iterator $iterator, array $directories) 32 { 33 array_walk($directories, function ($directory) { 34 if (!is_string($directory)) { 35 if (is_object($directory)) { 36 throw new \InvalidArgumentException(sprintf('Invalid directory given: %s', get_class($directory))); 37 } 38 39 throw new \InvalidArgumentException(sprintf('Invalid directory given: %s', gettype($directory))); 40 } 41 }); 42 43 $this->iterator = $iterator; 44 $this->isRecursive = $iterator instanceof \RecursiveIterator; 45 46 $patterns = []; 47 foreach ($directories as $directory) { 48 $directory = rtrim($directory, '/'); 49 if (!$this->isRecursive || false !== strpos($directory, '/')) { 50 $patterns[] = preg_quote($directory, '#'); 51 } else { 52 $this->excludedDirs[$directory] = true; 53 } 54 } 55 56 if ($patterns) { 57 $this->excludedPattern = '#(?:^|/)(?:' . implode('|', $patterns) . ')(?:/|$)#'; 58 } 59 60 parent::__construct($iterator); 61 } 62 63 /** 64 * @inheritdoc 65 */ 66 public function accept() 67 { 68 /** @var Metadata $metadata */ 69 $metadata = $this->current(); 70 71 if ($this->isRecursive && isset($this->excludedDirs[$metadata->getPath()]) && $metadata->isDir()) { 72 return false; 73 } 74 75 if ($this->excludedPattern) { 76 $path = $metadata->getPath(); 77 $path = str_replace('\\', '/', $path); 78 79 return !preg_match($this->excludedPattern, $path); 80 } 81 82 return true; 83 } 84 85 /** 86 * @inheritdoc 87 */ 88 public function hasChildren() 89 { 90 return $this->isRecursive && $this->iterator->hasChildren(); 91 } 92 93 /** 94 * @inheritdoc 95 */ 96 public function getChildren() 97 { 98 $children = new self($this->iterator->getChildren(), []); 99 $children->excludedDirs = $this->excludedDirs; 100 $children->excludedPattern = $this->excludedPattern; 101 102 return $children; 103 } 104} 105