FileCacheReader::getMethodAnnotation()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 11
rs 10
c 0
b 0
f 0
cc 3
nc 3
nop 2
1
<?php
2
3
namespace Doctrine\Common\Annotations;
4
5
/**
6
 * File cache reader for annotations.
7
 *
8
 * @author Johannes M. Schmitt <[email protected]>
9
 * @author Benjamin Eberlei <[email protected]>
10
 *
11
 * @deprecated the FileCacheReader is deprecated and will be removed
12
 *             in version 2.0.0 of doctrine/annotations. Please use the
13
 *             {@see \Doctrine\Common\Annotations\CachedReader} instead.
14
 */
15
class FileCacheReader implements Reader
16
{
17
    /**
18
     * @var Reader
19
     */
20
    private $reader;
21
22
    /**
23
     * @var string
24
     */
25
    private $dir;
26
27
    /**
28
     * @var bool
29
     */
30
    private $debug;
31
32
    /**
33
     * @var array
34
     */
35
    private $loadedAnnotations = [];
36
37
    /**
38
     * @var array
39
     */
40
    private $classNameHashes = [];
41
42
    /**
43
     * @var int
44
     */
45
    private $umask;
46
47
    /**
48
     * Constructor.
49
     *
50
     * @param Reader  $reader
51
     * @param string  $cacheDir
52
     * @param boolean $debug
53
     *
54
     * @throws \InvalidArgumentException
55
     */
56
    public function __construct(Reader $reader, $cacheDir, $debug = false, $umask = 0002)
57
    {
58
        if ( ! is_int($umask)) {
59
            throw new \InvalidArgumentException(sprintf(
60
                'The parameter umask must be an integer, was: %s',
61
                gettype($umask)
62
            ));
63
        }
64
65
        $this->reader = $reader;
66
        $this->umask = $umask;
67
68
        if (!is_dir($cacheDir) && !@mkdir($cacheDir, 0777 & (~$this->umask), true)) {
69
            throw new \InvalidArgumentException(sprintf('The directory "%s" does not exist and could not be created.', $cacheDir));
70
        }
71
72
        $this->dir   = rtrim($cacheDir, '\\/');
73
        $this->debug = $debug;
74
    }
75
76
    /**
77
     * {@inheritDoc}
78
     */
79
    public function getClassAnnotations(\ReflectionClass $class)
80
    {
81
        if ( ! isset($this->classNameHashes[$class->name])) {
82
            $this->classNameHashes[$class->name] = sha1($class->name);
83
        }
84
        $key = $this->classNameHashes[$class->name];
85
86
        if (isset($this->loadedAnnotations[$key])) {
87
            return $this->loadedAnnotations[$key];
88
        }
89
90
        $path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php';
91
        if (!is_file($path)) {
92
            $annot = $this->reader->getClassAnnotations($class);
93
            $this->saveCacheFile($path, $annot);
94
            return $this->loadedAnnotations[$key] = $annot;
95
        }
96
97
        if ($this->debug
98
            && (false !== $filename = $class->getFileName())
99
            && filemtime($path) < filemtime($filename)) {
100
            @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

100
            /** @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...
101
102
            $annot = $this->reader->getClassAnnotations($class);
103
            $this->saveCacheFile($path, $annot);
104
            return $this->loadedAnnotations[$key] = $annot;
105
        }
106
107
        return $this->loadedAnnotations[$key] = include $path;
108
    }
109
110
    /**
111
     * {@inheritDoc}
112
     */
113
    public function getPropertyAnnotations(\ReflectionProperty $property)
114
    {
115
        $class = $property->getDeclaringClass();
116
        if ( ! isset($this->classNameHashes[$class->name])) {
117
            $this->classNameHashes[$class->name] = sha1($class->name);
118
        }
119
        $key = $this->classNameHashes[$class->name].'$'.$property->getName();
120
121
        if (isset($this->loadedAnnotations[$key])) {
122
            return $this->loadedAnnotations[$key];
123
        }
124
125
        $path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php';
126
        if (!is_file($path)) {
127
            $annot = $this->reader->getPropertyAnnotations($property);
128
            $this->saveCacheFile($path, $annot);
129
            return $this->loadedAnnotations[$key] = $annot;
130
        }
131
132
        if ($this->debug
133
            && (false !== $filename = $class->getFilename())
134
            && filemtime($path) < filemtime($filename)) {
135
            @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

135
            /** @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...
136
137
            $annot = $this->reader->getPropertyAnnotations($property);
138
            $this->saveCacheFile($path, $annot);
139
            return $this->loadedAnnotations[$key] = $annot;
140
        }
141
142
        return $this->loadedAnnotations[$key] = include $path;
143
    }
144
145
    /**
146
     * {@inheritDoc}
147
     */
148
    public function getMethodAnnotations(\ReflectionMethod $method)
149
    {
150
        $class = $method->getDeclaringClass();
151
        if ( ! isset($this->classNameHashes[$class->name])) {
152
            $this->classNameHashes[$class->name] = sha1($class->name);
153
        }
154
        $key = $this->classNameHashes[$class->name].'#'.$method->getName();
155
156
        if (isset($this->loadedAnnotations[$key])) {
157
            return $this->loadedAnnotations[$key];
158
        }
159
160
        $path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php';
161
        if (!is_file($path)) {
162
            $annot = $this->reader->getMethodAnnotations($method);
163
            $this->saveCacheFile($path, $annot);
164
            return $this->loadedAnnotations[$key] = $annot;
165
        }
166
167
        if ($this->debug
168
            && (false !== $filename = $class->getFilename())
169
            && filemtime($path) < filemtime($filename)) {
170
            @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

170
            /** @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...
171
172
            $annot = $this->reader->getMethodAnnotations($method);
173
            $this->saveCacheFile($path, $annot);
174
            return $this->loadedAnnotations[$key] = $annot;
175
        }
176
177
        return $this->loadedAnnotations[$key] = include $path;
178
    }
179
180
    /**
181
     * Saves the cache file.
182
     *
183
     * @param string $path
184
     * @param mixed  $data
185
     *
186
     * @return void
187
     */
188
    private function saveCacheFile($path, $data)
189
    {
190
        if (!is_writable($this->dir)) {
191
            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));
192
        }
193
194
        $tempfile = tempnam($this->dir, uniqid('', true));
195
196
        if (false === $tempfile) {
197
            throw new \RuntimeException(sprintf('Unable to create tempfile in directory: %s', $this->dir));
198
        }
199
200
        @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

200
        /** @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...
201
202
        $written = file_put_contents($tempfile, '<?php return unserialize('.var_export(serialize($data), true).');');
203
204
        if (false === $written) {
205
            throw new \RuntimeException(sprintf('Unable to write cached file to: %s', $tempfile));
206
        }
207
208
        @chmod($tempfile, 0666 & (~$this->umask));
209
210
        if (false === rename($tempfile, $path)) {
211
            @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

211
            /** @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...
212
            throw new \RuntimeException(sprintf('Unable to rename %s to %s', $tempfile, $path));
213
        }
214
    }
215
216
    /**
217
     * {@inheritDoc}
218
     */
219
    public function getClassAnnotation(\ReflectionClass $class, $annotationName)
220
    {
221
        $annotations = $this->getClassAnnotations($class);
222
223
        foreach ($annotations as $annotation) {
224
            if ($annotation instanceof $annotationName) {
225
                return $annotation;
226
            }
227
        }
228
229
        return null;
230
    }
231
232
    /**
233
     * {@inheritDoc}
234
     */
235
    public function getMethodAnnotation(\ReflectionMethod $method, $annotationName)
236
    {
237
        $annotations = $this->getMethodAnnotations($method);
238
239
        foreach ($annotations as $annotation) {
240
            if ($annotation instanceof $annotationName) {
241
                return $annotation;
242
            }
243
        }
244
245
        return null;
246
    }
247
248
    /**
249
     * {@inheritDoc}
250
     */
251
    public function getPropertyAnnotation(\ReflectionProperty $property, $annotationName)
252
    {
253
        $annotations = $this->getPropertyAnnotations($property);
254
255
        foreach ($annotations as $annotation) {
256
            if ($annotation instanceof $annotationName) {
257
                return $annotation;
258
            }
259
        }
260
261
        return null;
262
    }
263
264
    /**
265
     * Clears loaded annotations.
266
     *
267
     * @return void
268
     */
269
    public function clearLoadedAnnotations()
270
    {
271
        $this->loadedAnnotations = [];
272
    }
273
}
274