vendor/symfony/config/Resource/GlobResource.php line 94

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\Config\Resource;
  11. use Symfony\Component\Finder\Finder;
  12. use Symfony\Component\Finder\Glob;
  13. /**
  14.  * GlobResource represents a set of resources stored on the filesystem.
  15.  *
  16.  * Only existence/removal is tracked (not mtimes.)
  17.  *
  18.  * @author Nicolas Grekas <p@tchwork.com>
  19.  *
  20.  * @final since Symfony 4.3
  21.  */
  22. class GlobResource implements \IteratorAggregateSelfCheckingResourceInterface
  23. {
  24.     private $prefix;
  25.     private $pattern;
  26.     private $recursive;
  27.     private $hash;
  28.     private $forExclusion;
  29.     private $excludedPrefixes;
  30.     /**
  31.      * @param string $prefix    A directory prefix
  32.      * @param string $pattern   A glob pattern
  33.      * @param bool   $recursive Whether directories should be scanned recursively or not
  34.      *
  35.      * @throws \InvalidArgumentException
  36.      */
  37.     public function __construct(?string $prefixstring $patternbool $recursivebool $forExclusion false, array $excludedPrefixes = [])
  38.     {
  39.         $this->prefix realpath($prefix) ?: (file_exists($prefix) ? $prefix false);
  40.         $this->pattern $pattern;
  41.         $this->recursive $recursive;
  42.         $this->forExclusion $forExclusion;
  43.         $this->excludedPrefixes $excludedPrefixes;
  44.         if (false === $this->prefix) {
  45.             throw new \InvalidArgumentException(sprintf('The path "%s" does not exist.'$prefix));
  46.         }
  47.     }
  48.     public function getPrefix()
  49.     {
  50.         return $this->prefix;
  51.     }
  52.     /**
  53.      * {@inheritdoc}
  54.      */
  55.     public function __toString()
  56.     {
  57.         return 'glob.'.$this->prefix.$this->pattern.(int) $this->recursive;
  58.     }
  59.     /**
  60.      * {@inheritdoc}
  61.      */
  62.     public function isFresh($timestamp)
  63.     {
  64.         $hash $this->computeHash();
  65.         if (null === $this->hash) {
  66.             $this->hash $hash;
  67.         }
  68.         return $this->hash === $hash;
  69.     }
  70.     /**
  71.      * @internal
  72.      */
  73.     public function __sleep(): array
  74.     {
  75.         if (null === $this->hash) {
  76.             $this->hash $this->computeHash();
  77.         }
  78.         return ['prefix''pattern''recursive''hash''forExclusion''excludedPrefixes'];
  79.     }
  80.     public function getIterator()
  81.     {
  82.         if (!file_exists($this->prefix) || (!$this->recursive && '' === $this->pattern)) {
  83.             return;
  84.         }
  85.         $prefix str_replace('\\''/'$this->prefix);
  86.         if (!== strpos($this->prefix'phar://') && false === strpos($this->pattern'/**/') && (\defined('GLOB_BRACE') || false === strpos($this->pattern'{'))) {
  87.             foreach (glob($this->prefix.$this->pattern, \defined('GLOB_BRACE') ? GLOB_BRACE 0) as $path) {
  88.                 if ($this->excludedPrefixes) {
  89.                     $normalizedPath str_replace('\\''/'$path);
  90.                     do {
  91.                         if (isset($this->excludedPrefixes[$dirPath $normalizedPath])) {
  92.                             continue 2;
  93.                         }
  94.                     } while ($prefix !== $dirPath && $dirPath !== $normalizedPath = \dirname($dirPath));
  95.                 }
  96.                 if (is_file($path)) {
  97.                     yield $path => new \SplFileInfo($path);
  98.                 }
  99.                 if (!is_dir($path)) {
  100.                     continue;
  101.                 }
  102.                 if ($this->forExclusion) {
  103.                     yield $path => new \SplFileInfo($path);
  104.                     continue;
  105.                 }
  106.                 if (!$this->recursive || isset($this->excludedPrefixes[str_replace('\\''/'$path)])) {
  107.                     continue;
  108.                 }
  109.                 $files iterator_to_array(new \RecursiveIteratorIterator(
  110.                     new \RecursiveCallbackFilterIterator(
  111.                         new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS),
  112.                         function (\SplFileInfo $file$path) {
  113.                             return !isset($this->excludedPrefixes[str_replace('\\''/'$path)]) && '.' !== $file->getBasename()[0];
  114.                         }
  115.                     ),
  116.                     \RecursiveIteratorIterator::LEAVES_ONLY
  117.                 ));
  118.                 uasort($files'strnatcmp');
  119.                 foreach ($files as $path => $info) {
  120.                     if ($info->isFile()) {
  121.                         yield $path => $info;
  122.                     }
  123.                 }
  124.             }
  125.             return;
  126.         }
  127.         if (!class_exists(Finder::class)) {
  128.             throw new \LogicException(sprintf('Extended glob pattern "%s" cannot be used as the Finder component is not installed.'$this->pattern));
  129.         }
  130.         $finder = new Finder();
  131.         $regex Glob::toRegex($this->pattern);
  132.         if ($this->recursive) {
  133.             $regex substr_replace($regex'(/|$)', -21);
  134.         }
  135.         $prefixLen = \strlen($this->prefix);
  136.         foreach ($finder->followLinks()->sortByName()->in($this->prefix) as $path => $info) {
  137.             $normalizedPath str_replace('\\''/'$path);
  138.             if (!preg_match($regexsubstr($normalizedPath$prefixLen)) || !$info->isFile()) {
  139.                 continue;
  140.             }
  141.             if ($this->excludedPrefixes) {
  142.                 do {
  143.                     if (isset($this->excludedPrefixes[$dirPath $normalizedPath])) {
  144.                         continue 2;
  145.                     }
  146.                 } while ($prefix !== $dirPath && $dirPath !== $normalizedPath = \dirname($dirPath));
  147.             }
  148.             yield $path => $info;
  149.         }
  150.     }
  151.     private function computeHash()
  152.     {
  153.         $hash hash_init('md5');
  154.         foreach ($this->getIterator() as $path => $info) {
  155.             hash_update($hash$path."\n");
  156.         }
  157.         return hash_final($hash);
  158.     }
  159. }