TYPO3  7.6
Finder.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11 
12 namespace Symfony\Component\Finder;
13 
29 
45 class Finder implements \IteratorAggregate, \Countable
46 {
47  const IGNORE_VCS_FILES = 1;
48  const IGNORE_DOT_FILES = 2;
49 
50  private $mode = 0;
51  private $names = array();
52  private $notNames = array();
53  private $exclude = array();
54  private $filters = array();
55  private $depths = array();
56  private $sizes = array();
57  private $followLinks = false;
58  private $sort = false;
59  private $ignore = 0;
60  private $dirs = array();
61  private $dates = array();
62  private $iterators = array();
63  private $contains = array();
64  private $notContains = array();
65  private $adapters = array();
66  private $paths = array();
67  private $notPaths = array();
68  private $ignoreUnreadableDirs = false;
69 
70  private static $vcsPatterns = array('.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg');
71 
75  public function __construct()
76  {
77  $this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES;
78 
79  $this
80  ->addAdapter(new GnuFindAdapter())
81  ->addAdapter(new BsdFindAdapter())
82  ->addAdapter(new PhpAdapter(), -50)
83  ->setAdapter('php')
84  ;
85  }
86 
94  public static function create()
95  {
96  return new static();
97  }
98 
107  public function addAdapter(AdapterInterface $adapter, $priority = 0)
108  {
109  $this->adapters[$adapter->getName()] = array(
110  'adapter' => $adapter,
111  'priority' => $priority,
112  'selected' => false,
113  );
114 
115  return $this->sortAdapters();
116  }
117 
123  public function useBestAdapter()
124  {
125  $this->resetAdapterSelection();
126 
127  return $this->sortAdapters();
128  }
129 
139  public function setAdapter($name)
140  {
141  if (!isset($this->adapters[$name])) {
142  throw new \InvalidArgumentException(sprintf('Adapter "%s" does not exist.', $name));
143  }
144 
145  $this->resetAdapterSelection();
146  $this->adapters[$name]['selected'] = true;
147 
148  return $this->sortAdapters();
149  }
150 
156  public function removeAdapters()
157  {
158  $this->adapters = array();
159 
160  return $this;
161  }
162 
168  public function getAdapters()
169  {
170  return array_values(array_map(function (array $adapter) {
171  return $adapter['adapter'];
172  }, $this->adapters));
173  }
174 
182  public function directories()
183  {
184  $this->mode = Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES;
185 
186  return $this;
187  }
188 
196  public function files()
197  {
198  $this->mode = Iterator\FileTypeFilterIterator::ONLY_FILES;
199 
200  return $this;
201  }
202 
220  public function depth($level)
221  {
222  $this->depths[] = new Comparator\NumberComparator($level);
223 
224  return $this;
225  }
226 
247  public function date($date)
248  {
249  $this->dates[] = new Comparator\DateComparator($date);
250 
251  return $this;
252  }
253 
271  public function name($pattern)
272  {
273  $this->names[] = $pattern;
274 
275  return $this;
276  }
277 
289  public function notName($pattern)
290  {
291  $this->notNames[] = $pattern;
292 
293  return $this;
294  }
295 
310  public function contains($pattern)
311  {
312  $this->contains[] = $pattern;
313 
314  return $this;
315  }
316 
331  public function notContains($pattern)
332  {
333  $this->notContains[] = $pattern;
334 
335  return $this;
336  }
337 
354  public function path($pattern)
355  {
356  $this->paths[] = $pattern;
357 
358  return $this;
359  }
360 
377  public function notPath($pattern)
378  {
379  $this->notPaths[] = $pattern;
380 
381  return $this;
382  }
383 
400  public function size($size)
401  {
402  $this->sizes[] = new Comparator\NumberComparator($size);
403 
404  return $this;
405  }
406 
418  public function exclude($dirs)
419  {
420  $this->exclude = array_merge($this->exclude, (array) $dirs);
421 
422  return $this;
423  }
424 
436  public function ignoreDotFiles($ignoreDotFiles)
437  {
438  if ($ignoreDotFiles) {
439  $this->ignore |= static::IGNORE_DOT_FILES;
440  } else {
441  $this->ignore &= ~static::IGNORE_DOT_FILES;
442  }
443 
444  return $this;
445  }
446 
458  public function ignoreVCS($ignoreVCS)
459  {
460  if ($ignoreVCS) {
461  $this->ignore |= static::IGNORE_VCS_FILES;
462  } else {
463  $this->ignore &= ~static::IGNORE_VCS_FILES;
464  }
465 
466  return $this;
467  }
468 
476  public static function addVCSPattern($pattern)
477  {
478  foreach ((array) $pattern as $p) {
479  self::$vcsPatterns[] = $p;
480  }
481 
482  self::$vcsPatterns = array_unique(self::$vcsPatterns);
483  }
484 
500  public function sort(\Closure $closure)
501  {
502  $this->sort = $closure;
503 
504  return $this;
505  }
506 
518  public function sortByName()
519  {
520  $this->sort = Iterator\SortableIterator::SORT_BY_NAME;
521 
522  return $this;
523  }
524 
536  public function sortByType()
537  {
538  $this->sort = Iterator\SortableIterator::SORT_BY_TYPE;
539 
540  return $this;
541  }
542 
556  public function sortByAccessedTime()
557  {
558  $this->sort = Iterator\SortableIterator::SORT_BY_ACCESSED_TIME;
559 
560  return $this;
561  }
562 
578  public function sortByChangedTime()
579  {
580  $this->sort = Iterator\SortableIterator::SORT_BY_CHANGED_TIME;
581 
582  return $this;
583  }
584 
598  public function sortByModifiedTime()
599  {
600  $this->sort = Iterator\SortableIterator::SORT_BY_MODIFIED_TIME;
601 
602  return $this;
603  }
604 
619  public function filter(\Closure $closure)
620  {
621  $this->filters[] = $closure;
622 
623  return $this;
624  }
625 
633  public function followLinks()
634  {
635  $this->followLinks = true;
636 
637  return $this;
638  }
639 
649  public function ignoreUnreadableDirs($ignore = true)
650  {
651  $this->ignoreUnreadableDirs = (bool) $ignore;
652 
653  return $this;
654  }
655 
667  public function in($dirs)
668  {
669  $resolvedDirs = array();
670 
671  foreach ((array) $dirs as $dir) {
672  if (is_dir($dir)) {
673  $resolvedDirs[] = $dir;
674  } elseif ($glob = glob($dir, (defined('GLOB_BRACE') ? GLOB_BRACE : 0) | GLOB_ONLYDIR)) {
675  $resolvedDirs = array_merge($resolvedDirs, $glob);
676  } else {
677  throw new \InvalidArgumentException(sprintf('The "%s" directory does not exist.', $dir));
678  }
679  }
680 
681  $this->dirs = array_merge($this->dirs, $resolvedDirs);
682 
683  return $this;
684  }
685 
695  public function getIterator()
696  {
697  if (0 === count($this->dirs) && 0 === count($this->iterators)) {
698  throw new \LogicException('You must call one of in() or append() methods before iterating over a Finder.');
699  }
700 
701  if (1 === count($this->dirs) && 0 === count($this->iterators)) {
702  return $this->searchInDirectory($this->dirs[0]);
703  }
704 
705  $iterator = new \AppendIterator();
706  foreach ($this->dirs as $dir) {
707  $iterator->append($this->searchInDirectory($dir));
708  }
709 
710  foreach ($this->iterators as $it) {
711  $iterator->append($it);
712  }
713 
714  return $iterator;
715  }
716 
728  public function append($iterator)
729  {
730  if ($iterator instanceof \IteratorAggregate) {
731  $this->iterators[] = $iterator->getIterator();
732  } elseif ($iterator instanceof \Iterator) {
733  $this->iterators[] = $iterator;
734  } elseif ($iterator instanceof \Traversable || is_array($iterator)) {
735  $it = new \ArrayIterator();
736  foreach ($iterator as $file) {
737  $it->append($file instanceof \SplFileInfo ? $file : new \SplFileInfo($file));
738  }
739  $this->iterators[] = $it;
740  } else {
741  throw new \InvalidArgumentException('Finder::append() method wrong argument type.');
742  }
743 
744  return $this;
745  }
746 
752  public function count()
753  {
754  return iterator_count($this->getIterator());
755  }
756 
760  private function sortAdapters()
761  {
762  uasort($this->adapters, function (array $a, array $b) {
763  if ($a['selected'] || $b['selected']) {
764  return $a['selected'] ? -1 : 1;
765  }
766 
767  return $a['priority'] > $b['priority'] ? -1 : 1;
768  });
769 
770  return $this;
771  }
772 
780  private function searchInDirectory($dir)
781  {
782  if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) {
783  $this->exclude = array_merge($this->exclude, self::$vcsPatterns);
784  }
785 
786  if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) {
787  $this->notPaths[] = '#(^|/)\..+(/|$)#';
788  }
789 
790  foreach ($this->adapters as $adapter) {
791  if ($adapter['adapter']->isSupported()) {
792  try {
793  return $this
794  ->buildAdapter($adapter['adapter'])
795  ->searchInDirectory($dir);
796  } catch (ExceptionInterface $e) {
797  }
798  }
799  }
800 
801  throw new \RuntimeException('No supported adapter found.');
802  }
803 
809  private function buildAdapter(AdapterInterface $adapter)
810  {
811  return $adapter
812  ->setFollowLinks($this->followLinks)
813  ->setDepths($this->depths)
814  ->setMode($this->mode)
815  ->setExclude($this->exclude)
816  ->setNames($this->names)
817  ->setNotNames($this->notNames)
818  ->setContains($this->contains)
819  ->setNotContains($this->notContains)
820  ->setSizes($this->sizes)
821  ->setDates($this->dates)
822  ->setFilters($this->filters)
823  ->setSort($this->sort)
824  ->setPath($this->paths)
825  ->setNotPath($this->notPaths)
826  ->ignoreUnreadableDirs($this->ignoreUnreadableDirs);
827  }
828 
832  private function resetAdapterSelection()
833  {
834  $this->adapters = array_map(function (array $properties) {
835  $properties['selected'] = false;
836 
837  return $properties;
838  }, $this->adapters);
839  }
840 }