e3c3be12cffe58bcd88bba516cb3c503160d857d
[yaffs-website] / vendor / symfony / config / Resource / GlobResource.php
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\Config\Resource;
13
14 use Symfony\Component\Finder\Finder;
15 use Symfony\Component\Finder\Glob;
16
17 /**
18  * GlobResource represents a set of resources stored on the filesystem.
19  *
20  * Only existence/removal is tracked (not mtimes.)
21  *
22  * @author Nicolas Grekas <p@tchwork.com>
23  */
24 class GlobResource implements \IteratorAggregate, SelfCheckingResourceInterface, \Serializable
25 {
26     private $prefix;
27     private $pattern;
28     private $recursive;
29     private $hash;
30
31     /**
32      * @param string $prefix    A directory prefix
33      * @param string $pattern   A glob pattern
34      * @param bool   $recursive Whether directories should be scanned recursively or not
35      *
36      * @throws \InvalidArgumentException
37      */
38     public function __construct($prefix, $pattern, $recursive)
39     {
40         $this->prefix = realpath($prefix) ?: (file_exists($prefix) ? $prefix : false);
41         $this->pattern = $pattern;
42         $this->recursive = $recursive;
43
44         if (false === $this->prefix) {
45             throw new \InvalidArgumentException(sprintf('The path "%s" does not exist.', $prefix));
46         }
47     }
48
49     public function getPrefix()
50     {
51         return $this->prefix;
52     }
53
54     /**
55      * {@inheritdoc}
56      */
57     public function __toString()
58     {
59         return 'glob.'.$this->prefix.$this->pattern.(int) $this->recursive;
60     }
61
62     /**
63      * {@inheritdoc}
64      */
65     public function isFresh($timestamp)
66     {
67         $hash = $this->computeHash();
68
69         if (null === $this->hash) {
70             $this->hash = $hash;
71         }
72
73         return $this->hash === $hash;
74     }
75
76     public function serialize()
77     {
78         if (null === $this->hash) {
79             $this->hash = $this->computeHash();
80         }
81
82         return serialize(array($this->prefix, $this->pattern, $this->recursive, $this->hash));
83     }
84
85     public function unserialize($serialized)
86     {
87         list($this->prefix, $this->pattern, $this->recursive, $this->hash) = unserialize($serialized);
88     }
89
90     public function getIterator()
91     {
92         if (!file_exists($this->prefix) || (!$this->recursive && '' === $this->pattern)) {
93             return;
94         }
95
96         if (0 !== strpos($this->prefix, 'phar://') && false === strpos($this->pattern, '/**/') && (\defined('GLOB_BRACE') || false === strpos($this->pattern, '{'))) {
97             foreach (glob($this->prefix.$this->pattern, \defined('GLOB_BRACE') ? GLOB_BRACE : 0) as $path) {
98                 if ($this->recursive && is_dir($path)) {
99                     $files = iterator_to_array(new \RecursiveIteratorIterator(
100                         new \RecursiveCallbackFilterIterator(
101                             new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS),
102                             function (\SplFileInfo $file) { return '.' !== $file->getBasename()[0]; }
103                         ),
104                         \RecursiveIteratorIterator::LEAVES_ONLY
105                     ));
106                     uasort($files, function (\SplFileInfo $a, \SplFileInfo $b) {
107                         return (string) $a > (string) $b ? 1 : -1;
108                     });
109
110                     foreach ($files as $path => $info) {
111                         if ($info->isFile()) {
112                             yield $path => $info;
113                         }
114                     }
115                 } elseif (is_file($path)) {
116                     yield $path => new \SplFileInfo($path);
117                 }
118             }
119
120             return;
121         }
122
123         if (!class_exists(Finder::class)) {
124             throw new \LogicException(sprintf('Extended glob pattern "%s" cannot be used as the Finder component is not installed.', $this->pattern));
125         }
126
127         $finder = new Finder();
128         $regex = Glob::toRegex($this->pattern);
129         if ($this->recursive) {
130             $regex = substr_replace($regex, '(/|$)', -2, 1);
131         }
132
133         $prefixLen = \strlen($this->prefix);
134         foreach ($finder->followLinks()->sortByName()->in($this->prefix) as $path => $info) {
135             if (preg_match($regex, substr('\\' === \DIRECTORY_SEPARATOR ? str_replace('\\', '/', $path) : $path, $prefixLen)) && $info->isFile()) {
136                 yield $path => $info;
137             }
138         }
139     }
140
141     private function computeHash()
142     {
143         $hash = hash_init('md5');
144
145         foreach ($this->getIterator() as $path => $info) {
146             hash_update($hash, $path."\n");
147         }
148
149         return hash_final($hash);
150     }
151 }