Security update to Drupal 8.4.6
[yaffs-website] / vendor / doctrine / common / lib / Doctrine / Common / Persistence / Mapping / Driver / AnnotationDriver.php
1 <?php
2 /*
3  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14  *
15  * This software consists of voluntary contributions made by many individuals
16  * and is licensed under the MIT license. For more information, see
17  * <http://www.doctrine-project.org>.
18  */
19
20 namespace Doctrine\Common\Persistence\Mapping\Driver;
21
22 use Doctrine\Common\Annotations\AnnotationReader;
23 use Doctrine\Common\Persistence\Mapping\MappingException;
24
25 /**
26  * The AnnotationDriver reads the mapping metadata from docblock annotations.
27  *
28  * @since  2.2
29  * @author Benjamin Eberlei <kontakt@beberlei.de>
30  * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
31  * @author Jonathan H. Wage <jonwage@gmail.com>
32  * @author Roman Borschel <roman@code-factory.org>
33  */
34 abstract class AnnotationDriver implements MappingDriver
35 {
36     /**
37      * The AnnotationReader.
38      *
39      * @var AnnotationReader
40      */
41     protected $reader;
42
43     /**
44      * The paths where to look for mapping files.
45      *
46      * @var array
47      */
48     protected $paths = [];
49
50     /**
51      * The paths excluded from path where to look for mapping files.
52      *
53      * @var array
54      */
55     protected $excludePaths = [];
56
57     /**
58      * The file extension of mapping documents.
59      *
60      * @var string
61      */
62     protected $fileExtension = '.php';
63
64     /**
65      * Cache for AnnotationDriver#getAllClassNames().
66      *
67      * @var array|null
68      */
69     protected $classNames;
70
71     /**
72      * Name of the entity annotations as keys.
73      *
74      * @var array
75      */
76     protected $entityAnnotationClasses = [];
77
78     /**
79      * Initializes a new AnnotationDriver that uses the given AnnotationReader for reading
80      * docblock annotations.
81      *
82      * @param AnnotationReader  $reader The AnnotationReader to use, duck-typed.
83      * @param string|array|null $paths  One or multiple paths where mapping classes can be found.
84      */
85     public function __construct($reader, $paths = null)
86     {
87         $this->reader = $reader;
88         if ($paths) {
89             $this->addPaths((array) $paths);
90         }
91     }
92
93     /**
94      * Appends lookup paths to metadata driver.
95      *
96      * @param array $paths
97      *
98      * @return void
99      */
100     public function addPaths(array $paths)
101     {
102         $this->paths = array_unique(array_merge($this->paths, $paths));
103     }
104
105     /**
106      * Retrieves the defined metadata lookup paths.
107      *
108      * @return array
109      */
110     public function getPaths()
111     {
112         return $this->paths;
113     }
114
115     /**
116      * Append exclude lookup paths to metadata driver.
117      *
118      * @param array $paths
119      */
120     public function addExcludePaths(array $paths)
121     {
122         $this->excludePaths = array_unique(array_merge($this->excludePaths, $paths));
123     }
124
125     /**
126      * Retrieve the defined metadata lookup exclude paths.
127      *
128      * @return array
129      */
130     public function getExcludePaths()
131     {
132         return $this->excludePaths;
133     }
134
135     /**
136      * Retrieve the current annotation reader
137      *
138      * @return AnnotationReader
139      */
140     public function getReader()
141     {
142         return $this->reader;
143     }
144
145     /**
146      * Gets the file extension used to look for mapping files under.
147      *
148      * @return string
149      */
150     public function getFileExtension()
151     {
152         return $this->fileExtension;
153     }
154
155     /**
156      * Sets the file extension used to look for mapping files under.
157      *
158      * @param string $fileExtension The file extension to set.
159      *
160      * @return void
161      */
162     public function setFileExtension($fileExtension)
163     {
164         $this->fileExtension = $fileExtension;
165     }
166
167     /**
168      * Returns whether the class with the specified name is transient. Only non-transient
169      * classes, that is entities and mapped superclasses, should have their metadata loaded.
170      *
171      * A class is non-transient if it is annotated with an annotation
172      * from the {@see AnnotationDriver::entityAnnotationClasses}.
173      *
174      * @param string $className
175      *
176      * @return boolean
177      */
178     public function isTransient($className)
179     {
180         $classAnnotations = $this->reader->getClassAnnotations(new \ReflectionClass($className));
181
182         foreach ($classAnnotations as $annot) {
183             if (isset($this->entityAnnotationClasses[get_class($annot)])) {
184                 return false;
185             }
186         }
187         return true;
188     }
189
190     /**
191      * {@inheritDoc}
192      */
193     public function getAllClassNames()
194     {
195         if ($this->classNames !== null) {
196             return $this->classNames;
197         }
198
199         if (!$this->paths) {
200             throw MappingException::pathRequired();
201         }
202
203         $classes = [];
204         $includedFiles = [];
205
206         foreach ($this->paths as $path) {
207             if ( ! is_dir($path)) {
208                 throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path);
209             }
210
211             $iterator = new \RegexIterator(
212                 new \RecursiveIteratorIterator(
213                     new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS),
214                     \RecursiveIteratorIterator::LEAVES_ONLY
215                 ),
216                 '/^.+' . preg_quote($this->fileExtension) . '$/i',
217                 \RecursiveRegexIterator::GET_MATCH
218             );
219
220             foreach ($iterator as $file) {
221                 $sourceFile = $file[0];
222
223                 if ( ! preg_match('(^phar:)i', $sourceFile)) {
224                     $sourceFile = realpath($sourceFile);
225                 }
226
227                 foreach ($this->excludePaths as $excludePath) {
228                     $exclude = str_replace('\\', '/', realpath($excludePath));
229                     $current = str_replace('\\', '/', $sourceFile);
230
231                     if (strpos($current, $exclude) !== false) {
232                         continue 2;
233                     }
234                 }
235
236                 require_once $sourceFile;
237
238                 $includedFiles[] = $sourceFile;
239             }
240         }
241
242         $declared = get_declared_classes();
243
244         foreach ($declared as $className) {
245             $rc = new \ReflectionClass($className);
246             $sourceFile = $rc->getFileName();
247             if (in_array($sourceFile, $includedFiles) && ! $this->isTransient($className)) {
248                 $classes[] = $className;
249             }
250         }
251
252         $this->classNames = $classes;
253
254         return $classes;
255     }
256 }