Chris@0: . Chris@0: */ Chris@0: Chris@0: namespace Doctrine\Common\Annotations; Chris@0: Chris@0: /** Chris@0: * File cache reader for annotations. Chris@0: * Chris@0: * @author Johannes M. Schmitt Chris@0: * @author Benjamin Eberlei Chris@0: * Chris@0: * @deprecated the FileCacheReader is deprecated and will be removed Chris@0: * in version 2.0.0 of doctrine/annotations. Please use the Chris@0: * {@see \Doctrine\Common\Annotations\CachedReader} instead. Chris@0: */ Chris@0: class FileCacheReader implements Reader Chris@0: { Chris@0: /** Chris@0: * @var Reader Chris@0: */ Chris@0: private $reader; Chris@0: Chris@0: /** Chris@0: * @var string Chris@0: */ Chris@0: private $dir; Chris@0: Chris@0: /** Chris@0: * @var bool Chris@0: */ Chris@0: private $debug; Chris@0: Chris@0: /** Chris@0: * @var array Chris@0: */ Chris@0: private $loadedAnnotations = array(); Chris@0: Chris@0: /** Chris@0: * @var array Chris@0: */ Chris@0: private $classNameHashes = array(); Chris@0: Chris@0: /** Chris@0: * @var int Chris@0: */ Chris@0: private $umask; Chris@0: Chris@0: /** Chris@0: * Constructor. Chris@0: * Chris@0: * @param Reader $reader Chris@0: * @param string $cacheDir Chris@0: * @param boolean $debug Chris@0: * Chris@0: * @throws \InvalidArgumentException Chris@0: */ Chris@0: public function __construct(Reader $reader, $cacheDir, $debug = false, $umask = 0002) Chris@0: { Chris@0: if ( ! is_int($umask)) { Chris@0: throw new \InvalidArgumentException(sprintf( Chris@0: 'The parameter umask must be an integer, was: %s', Chris@0: gettype($umask) Chris@0: )); Chris@0: } Chris@0: Chris@0: $this->reader = $reader; Chris@0: $this->umask = $umask; Chris@0: Chris@0: if (!is_dir($cacheDir) && !@mkdir($cacheDir, 0777 & (~$this->umask), true)) { Chris@0: throw new \InvalidArgumentException(sprintf('The directory "%s" does not exist and could not be created.', $cacheDir)); Chris@0: } Chris@0: Chris@0: $this->dir = rtrim($cacheDir, '\\/'); Chris@0: $this->debug = $debug; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritDoc} Chris@0: */ Chris@0: public function getClassAnnotations(\ReflectionClass $class) Chris@0: { Chris@0: if ( ! isset($this->classNameHashes[$class->name])) { Chris@0: $this->classNameHashes[$class->name] = sha1($class->name); Chris@0: } Chris@0: $key = $this->classNameHashes[$class->name]; Chris@0: Chris@0: if (isset($this->loadedAnnotations[$key])) { Chris@0: return $this->loadedAnnotations[$key]; Chris@0: } Chris@0: Chris@0: $path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php'; Chris@0: if (!is_file($path)) { Chris@0: $annot = $this->reader->getClassAnnotations($class); Chris@0: $this->saveCacheFile($path, $annot); Chris@0: return $this->loadedAnnotations[$key] = $annot; Chris@0: } Chris@0: Chris@0: if ($this->debug Chris@12: && (false !== $filename = $class->getFileName()) Chris@0: && filemtime($path) < filemtime($filename)) { Chris@0: @unlink($path); Chris@0: Chris@0: $annot = $this->reader->getClassAnnotations($class); Chris@0: $this->saveCacheFile($path, $annot); Chris@0: return $this->loadedAnnotations[$key] = $annot; Chris@0: } Chris@0: Chris@0: return $this->loadedAnnotations[$key] = include $path; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritDoc} Chris@0: */ Chris@0: public function getPropertyAnnotations(\ReflectionProperty $property) Chris@0: { Chris@0: $class = $property->getDeclaringClass(); Chris@0: if ( ! isset($this->classNameHashes[$class->name])) { Chris@0: $this->classNameHashes[$class->name] = sha1($class->name); Chris@0: } Chris@0: $key = $this->classNameHashes[$class->name].'$'.$property->getName(); Chris@0: Chris@0: if (isset($this->loadedAnnotations[$key])) { Chris@0: return $this->loadedAnnotations[$key]; Chris@0: } Chris@0: Chris@0: $path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php'; Chris@0: if (!is_file($path)) { Chris@0: $annot = $this->reader->getPropertyAnnotations($property); Chris@0: $this->saveCacheFile($path, $annot); Chris@0: return $this->loadedAnnotations[$key] = $annot; Chris@0: } Chris@0: Chris@0: if ($this->debug Chris@0: && (false !== $filename = $class->getFilename()) Chris@0: && filemtime($path) < filemtime($filename)) { Chris@0: @unlink($path); Chris@0: Chris@0: $annot = $this->reader->getPropertyAnnotations($property); Chris@0: $this->saveCacheFile($path, $annot); Chris@0: return $this->loadedAnnotations[$key] = $annot; Chris@0: } Chris@0: Chris@0: return $this->loadedAnnotations[$key] = include $path; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritDoc} Chris@0: */ Chris@0: public function getMethodAnnotations(\ReflectionMethod $method) Chris@0: { Chris@0: $class = $method->getDeclaringClass(); Chris@0: if ( ! isset($this->classNameHashes[$class->name])) { Chris@0: $this->classNameHashes[$class->name] = sha1($class->name); Chris@0: } Chris@0: $key = $this->classNameHashes[$class->name].'#'.$method->getName(); Chris@0: Chris@0: if (isset($this->loadedAnnotations[$key])) { Chris@0: return $this->loadedAnnotations[$key]; Chris@0: } Chris@0: Chris@0: $path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php'; Chris@0: if (!is_file($path)) { Chris@0: $annot = $this->reader->getMethodAnnotations($method); Chris@0: $this->saveCacheFile($path, $annot); Chris@0: return $this->loadedAnnotations[$key] = $annot; Chris@0: } Chris@0: Chris@0: if ($this->debug Chris@0: && (false !== $filename = $class->getFilename()) Chris@0: && filemtime($path) < filemtime($filename)) { Chris@0: @unlink($path); Chris@0: Chris@0: $annot = $this->reader->getMethodAnnotations($method); Chris@0: $this->saveCacheFile($path, $annot); Chris@0: return $this->loadedAnnotations[$key] = $annot; Chris@0: } Chris@0: Chris@0: return $this->loadedAnnotations[$key] = include $path; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Saves the cache file. Chris@0: * Chris@0: * @param string $path Chris@0: * @param mixed $data Chris@0: * Chris@0: * @return void Chris@0: */ Chris@0: private function saveCacheFile($path, $data) Chris@0: { Chris@0: if (!is_writable($this->dir)) { Chris@0: 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)); Chris@0: } Chris@0: Chris@0: $tempfile = tempnam($this->dir, uniqid('', true)); Chris@0: Chris@0: if (false === $tempfile) { Chris@0: throw new \RuntimeException(sprintf('Unable to create tempfile in directory: %s', $this->dir)); Chris@0: } Chris@0: Chris@12: @chmod($tempfile, 0666 & (~$this->umask)); Chris@12: Chris@0: $written = file_put_contents($tempfile, 'umask)); Chris@0: Chris@0: if (false === rename($tempfile, $path)) { Chris@0: @unlink($tempfile); Chris@0: throw new \RuntimeException(sprintf('Unable to rename %s to %s', $tempfile, $path)); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritDoc} Chris@0: */ Chris@0: public function getClassAnnotation(\ReflectionClass $class, $annotationName) Chris@0: { Chris@0: $annotations = $this->getClassAnnotations($class); Chris@0: Chris@0: foreach ($annotations as $annotation) { Chris@0: if ($annotation instanceof $annotationName) { Chris@0: return $annotation; Chris@0: } Chris@0: } Chris@0: Chris@0: return null; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritDoc} Chris@0: */ Chris@0: public function getMethodAnnotation(\ReflectionMethod $method, $annotationName) Chris@0: { Chris@0: $annotations = $this->getMethodAnnotations($method); Chris@0: Chris@0: foreach ($annotations as $annotation) { Chris@0: if ($annotation instanceof $annotationName) { Chris@0: return $annotation; Chris@0: } Chris@0: } Chris@0: Chris@0: return null; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritDoc} Chris@0: */ Chris@0: public function getPropertyAnnotation(\ReflectionProperty $property, $annotationName) Chris@0: { Chris@0: $annotations = $this->getPropertyAnnotations($property); Chris@0: Chris@0: foreach ($annotations as $annotation) { Chris@0: if ($annotation instanceof $annotationName) { Chris@0: return $annotation; Chris@0: } Chris@0: } Chris@0: Chris@0: return null; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Clears loaded annotations. Chris@0: * Chris@0: * @return void Chris@0: */ Chris@0: public function clearLoadedAnnotations() Chris@0: { Chris@0: $this->loadedAnnotations = array(); Chris@0: } Chris@0: }