Completed
Pull Request — master (#263)
by
unknown
03:26
created

FileCacheReader::getConstantAnnotations()   B

Complexity

Conditions 7
Paths 8

Size

Total Lines 30
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 19
c 0
b 0
f 0
nc 8
nop 1
dl 0
loc 30
rs 8.8333
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\Annotations;
21
22
/**
23
 * File cache reader for annotations.
24
 *
25
 * @author Johannes M. Schmitt <[email protected]>
26
 * @author Benjamin Eberlei <[email protected]>
27
 *
28
 * @deprecated the FileCacheReader is deprecated and will be removed
29
 *             in version 2.0.0 of doctrine/annotations. Please use the
30
 *             {@see \Doctrine\Common\Annotations\CachedReader} instead.
31
 */
32
class FileCacheReader implements Reader, ReaderWithConstantsAnnotations
0 ignored issues
show
Deprecated Code introduced by
The interface Doctrine\Common\Annotati...ithConstantsAnnotations has been deprecated: This interface will be merged into Reader interface and removed in version 2.0. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

32
class FileCacheReader implements Reader, /** @scrutinizer ignore-deprecated */ ReaderWithConstantsAnnotations

This interface has been deprecated. The supplier of the interface has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the interface will be removed and what other interface to use instead.

Loading history...
33
{
34
    /**
35
     * @var Reader
36
     */
37
    private $reader;
38
39
    /**
40
     * @var string
41
     */
42
    private $dir;
43
44
    /**
45
     * @var bool
46
     */
47
    private $debug;
48
49
    /**
50
     * @var array
51
     */
52
    private $loadedAnnotations = [];
53
54
    /**
55
     * @var array
56
     */
57
    private $classNameHashes = [];
58
59
    /**
60
     * @var int
61
     */
62
    private $umask;
63
64
    /**
65
     * Constructor.
66
     *
67
     * @param Reader  $reader
68
     * @param string  $cacheDir
69
     * @param boolean $debug
70
     *
71
     * @throws \InvalidArgumentException
72
     */
73
    public function __construct(Reader $reader, $cacheDir, $debug = false, $umask = 0002)
74
    {
75
        if ( ! is_int($umask)) {
76
            throw new \InvalidArgumentException(sprintf(
77
                'The parameter umask must be an integer, was: %s',
78
                gettype($umask)
79
            ));
80
        }
81
82
        $this->reader = $reader;
83
        $this->umask = $umask;
84
85
        if (!is_dir($cacheDir) && !@mkdir($cacheDir, 0777 & (~$this->umask), true)) {
86
            throw new \InvalidArgumentException(sprintf('The directory "%s" does not exist and could not be created.', $cacheDir));
87
        }
88
89
        $this->dir   = rtrim($cacheDir, '\\/');
90
        $this->debug = $debug;
91
    }
92
93
    /**
94
     * {@inheritDoc}
95
     */
96
    public function getClassAnnotations(\ReflectionClass $class)
97
    {
98
        if ( ! isset($this->classNameHashes[$class->name])) {
99
            $this->classNameHashes[$class->name] = sha1($class->name);
100
        }
101
        $key = $this->classNameHashes[$class->name];
102
103
        if (isset($this->loadedAnnotations[$key])) {
104
            return $this->loadedAnnotations[$key];
105
        }
106
107
        $path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php';
108
        if (!is_file($path)) {
109
            $annot = $this->reader->getClassAnnotations($class);
110
            $this->saveCacheFile($path, $annot);
111
            return $this->loadedAnnotations[$key] = $annot;
112
        }
113
114
        if ($this->debug
115
            && (false !== $filename = $class->getFileName())
116
            && filemtime($path) < filemtime($filename)) {
117
            @unlink($path);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

117
            /** @scrutinizer ignore-unhandled */ @unlink($path);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
118
119
            $annot = $this->reader->getClassAnnotations($class);
120
            $this->saveCacheFile($path, $annot);
121
            return $this->loadedAnnotations[$key] = $annot;
122
        }
123
124
        return $this->loadedAnnotations[$key] = include $path;
125
    }
126
127
    /**
128
     * {@inheritDoc}
129
     */
130
    public function getPropertyAnnotations(\ReflectionProperty $property)
131
    {
132
        $class = $property->getDeclaringClass();
133
        if ( ! isset($this->classNameHashes[$class->name])) {
134
            $this->classNameHashes[$class->name] = sha1($class->name);
135
        }
136
        $key = $this->classNameHashes[$class->name].'$'.$property->getName();
137
138
        if (isset($this->loadedAnnotations[$key])) {
139
            return $this->loadedAnnotations[$key];
140
        }
141
142
        $path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php';
143
        if (!is_file($path)) {
144
            $annot = $this->reader->getPropertyAnnotations($property);
145
            $this->saveCacheFile($path, $annot);
146
            return $this->loadedAnnotations[$key] = $annot;
147
        }
148
149
        if ($this->debug
150
            && (false !== $filename = $class->getFilename())
151
            && filemtime($path) < filemtime($filename)) {
152
            @unlink($path);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

152
            /** @scrutinizer ignore-unhandled */ @unlink($path);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
153
154
            $annot = $this->reader->getPropertyAnnotations($property);
155
            $this->saveCacheFile($path, $annot);
156
            return $this->loadedAnnotations[$key] = $annot;
157
        }
158
159
        return $this->loadedAnnotations[$key] = include $path;
160
    }
161
162
    /**
163
     * {@inheritDoc}
164
     */
165
    public function getConstantAnnotations(\ReflectionClassConstant $constant): array
166
    {
167
        $class = $constant->getDeclaringClass();
168
        if ( ! isset($this->classNameHashes[$class->name])) {
169
            $this->classNameHashes[$class->name] = sha1($class->name);
170
        }
171
        $key = $this->classNameHashes[$class->name].'::'.$constant->getName();
172
173
        if (isset($this->loadedAnnotations[$key])) {
174
            return $this->loadedAnnotations[$key];
175
        }
176
177
        $path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php';
178
        if (!is_file($path)) {
179
            $annot = $this->reader->getConstantAnnotations($constant);
0 ignored issues
show
Bug introduced by
The method getConstantAnnotations() does not exist on Doctrine\Common\Annotations\Reader. Since it exists in all sub-types, consider adding an abstract or default implementation to Doctrine\Common\Annotations\Reader. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

179
            /** @scrutinizer ignore-call */ 
180
            $annot = $this->reader->getConstantAnnotations($constant);
Loading history...
180
            $this->saveCacheFile($path, $annot);
181
            return $this->loadedAnnotations[$key] = $annot;
182
        }
183
184
        if ($this->debug
185
            && (false !== $filename = $class->getFilename())
186
            && filemtime($path) < filemtime($filename)) {
187
            @unlink($path);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

187
            /** @scrutinizer ignore-unhandled */ @unlink($path);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
188
189
            $annot = $this->reader->getConstantAnnotations($constant);
190
            $this->saveCacheFile($path, $annot);
191
            return $this->loadedAnnotations[$key] = $annot;
192
        }
193
194
        return $this->loadedAnnotations[$key] = include $path;
195
    }
196
197
    /**
198
     * {@inheritDoc}
199
     */
200
    public function getMethodAnnotations(\ReflectionMethod $method)
201
    {
202
        $class = $method->getDeclaringClass();
203
        if ( ! isset($this->classNameHashes[$class->name])) {
204
            $this->classNameHashes[$class->name] = sha1($class->name);
205
        }
206
        $key = $this->classNameHashes[$class->name].'#'.$method->getName();
207
208
        if (isset($this->loadedAnnotations[$key])) {
209
            return $this->loadedAnnotations[$key];
210
        }
211
212
        $path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php';
213
        if (!is_file($path)) {
214
            $annot = $this->reader->getMethodAnnotations($method);
215
            $this->saveCacheFile($path, $annot);
216
            return $this->loadedAnnotations[$key] = $annot;
217
        }
218
219
        if ($this->debug
220
            && (false !== $filename = $class->getFilename())
221
            && filemtime($path) < filemtime($filename)) {
222
            @unlink($path);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

222
            /** @scrutinizer ignore-unhandled */ @unlink($path);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
223
224
            $annot = $this->reader->getMethodAnnotations($method);
225
            $this->saveCacheFile($path, $annot);
226
            return $this->loadedAnnotations[$key] = $annot;
227
        }
228
229
        return $this->loadedAnnotations[$key] = include $path;
230
    }
231
232
    /**
233
     * Saves the cache file.
234
     *
235
     * @param string $path
236
     * @param mixed  $data
237
     *
238
     * @return void
239
     */
240
    private function saveCacheFile($path, $data)
241
    {
242
        if (!is_writable($this->dir)) {
243
            throw new \InvalidArgumentException(sprintf('The directory "%s" is not writable. Both, the webserver and the console user need access. You can manage access rights for multiple users with "chmod +a". If your system does not support this, check out the acl package.', $this->dir));
244
        }
245
246
        $tempfile = tempnam($this->dir, uniqid('', true));
247
248
        if (false === $tempfile) {
249
            throw new \RuntimeException(sprintf('Unable to create tempfile in directory: %s', $this->dir));
250
        }
251
252
        @chmod($tempfile, 0666 & (~$this->umask));
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chmod(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

252
        /** @scrutinizer ignore-unhandled */ @chmod($tempfile, 0666 & (~$this->umask));

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
253
254
        $written = file_put_contents($tempfile, '<?php return unserialize('.var_export(serialize($data), true).');');
255
256
        if (false === $written) {
257
            throw new \RuntimeException(sprintf('Unable to write cached file to: %s', $tempfile));
258
        }
259
260
        @chmod($tempfile, 0666 & (~$this->umask));
261
262
        if (false === rename($tempfile, $path)) {
263
            @unlink($tempfile);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

263
            /** @scrutinizer ignore-unhandled */ @unlink($tempfile);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
264
            throw new \RuntimeException(sprintf('Unable to rename %s to %s', $tempfile, $path));
265
        }
266
    }
267
268
    /**
269
     * {@inheritDoc}
270
     */
271
    public function getClassAnnotation(\ReflectionClass $class, $annotationName)
272
    {
273
        $annotations = $this->getClassAnnotations($class);
274
275
        foreach ($annotations as $annotation) {
276
            if ($annotation instanceof $annotationName) {
277
                return $annotation;
278
            }
279
        }
280
281
        return null;
282
    }
283
284
    /**
285
     * {@inheritDoc}
286
     */
287
    public function getMethodAnnotation(\ReflectionMethod $method, $annotationName)
288
    {
289
        $annotations = $this->getMethodAnnotations($method);
290
291
        foreach ($annotations as $annotation) {
292
            if ($annotation instanceof $annotationName) {
293
                return $annotation;
294
            }
295
        }
296
297
        return null;
298
    }
299
300
    /**
301
     * {@inheritDoc}
302
     */
303
    public function getPropertyAnnotation(\ReflectionProperty $property, $annotationName)
304
    {
305
        $annotations = $this->getPropertyAnnotations($property);
306
307
        foreach ($annotations as $annotation) {
308
            if ($annotation instanceof $annotationName) {
309
                return $annotation;
310
            }
311
        }
312
313
        return null;
314
    }
315
316
    /**
317
     * {@inheritDoc}
318
     */
319
    public function getConstantAnnotation(\ReflectionClassConstant $constant, $annotationName)
320
    {
321
        $annotations = $this->getConstantAnnotations($constant);
322
323
        foreach ($annotations as $annotation) {
324
            if ($annotation instanceof $annotationName) {
325
                return $annotation;
326
            }
327
        }
328
329
        return null;
330
    }
331
332
    /**
333
     * Clears loaded annotations.
334
     *
335
     * @return void
336
     */
337
    public function clearLoadedAnnotations()
338
    {
339
        $this->loadedAnnotations = [];
340
    }
341
}
342