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 20namespace Doctrine\Common\Annotations; 21 22/** 23 * File cache reader for annotations. 24 * 25 * @author Johannes M. Schmitt <schmittjoh@gmail.com> 26 * @author Benjamin Eberlei <kontakt@beberlei.de> 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 */ 32class FileCacheReader implements Reader 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 = array(); 53 54 /** 55 * @var array 56 */ 57 private $classNameHashes = array(); 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); 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); 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 getMethodAnnotations(\ReflectionMethod $method) 166 { 167 $class = $method->getDeclaringClass(); 168 if ( ! isset($this->classNameHashes[$class->name])) { 169 $this->classNameHashes[$class->name] = sha1($class->name); 170 } 171 $key = $this->classNameHashes[$class->name].'#'.$method->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->getMethodAnnotations($method); 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); 188 189 $annot = $this->reader->getMethodAnnotations($method); 190 $this->saveCacheFile($path, $annot); 191 return $this->loadedAnnotations[$key] = $annot; 192 } 193 194 return $this->loadedAnnotations[$key] = include $path; 195 } 196 197 /** 198 * Saves the cache file. 199 * 200 * @param string $path 201 * @param mixed $data 202 * 203 * @return void 204 */ 205 private function saveCacheFile($path, $data) 206 { 207 if (!is_writable($this->dir)) { 208 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)); 209 } 210 211 $tempfile = tempnam($this->dir, uniqid('', true)); 212 213 if (false === $tempfile) { 214 throw new \RuntimeException(sprintf('Unable to create tempfile in directory: %s', $this->dir)); 215 } 216 217 @chmod($tempfile, 0666 & (~$this->umask)); 218 219 $written = file_put_contents($tempfile, '<?php return unserialize('.var_export(serialize($data), true).');'); 220 221 if (false === $written) { 222 throw new \RuntimeException(sprintf('Unable to write cached file to: %s', $tempfile)); 223 } 224 225 @chmod($tempfile, 0666 & (~$this->umask)); 226 227 if (false === rename($tempfile, $path)) { 228 @unlink($tempfile); 229 throw new \RuntimeException(sprintf('Unable to rename %s to %s', $tempfile, $path)); 230 } 231 } 232 233 /** 234 * {@inheritDoc} 235 */ 236 public function getClassAnnotation(\ReflectionClass $class, $annotationName) 237 { 238 $annotations = $this->getClassAnnotations($class); 239 240 foreach ($annotations as $annotation) { 241 if ($annotation instanceof $annotationName) { 242 return $annotation; 243 } 244 } 245 246 return null; 247 } 248 249 /** 250 * {@inheritDoc} 251 */ 252 public function getMethodAnnotation(\ReflectionMethod $method, $annotationName) 253 { 254 $annotations = $this->getMethodAnnotations($method); 255 256 foreach ($annotations as $annotation) { 257 if ($annotation instanceof $annotationName) { 258 return $annotation; 259 } 260 } 261 262 return null; 263 } 264 265 /** 266 * {@inheritDoc} 267 */ 268 public function getPropertyAnnotation(\ReflectionProperty $property, $annotationName) 269 { 270 $annotations = $this->getPropertyAnnotations($property); 271 272 foreach ($annotations as $annotation) { 273 if ($annotation instanceof $annotationName) { 274 return $annotation; 275 } 276 } 277 278 return null; 279 } 280 281 /** 282 * Clears loaded annotations. 283 * 284 * @return void 285 */ 286 public function clearLoadedAnnotations() 287 { 288 $this->loadedAnnotations = array(); 289 } 290} 291