1<?php 2 3declare(strict_types=1); 4 5namespace Metadata\Cache; 6 7use Metadata\ClassMetadata; 8 9class FileCache implements CacheInterface 10{ 11 /** 12 * @var string 13 */ 14 private $dir; 15 16 public function __construct(string $dir) 17 { 18 if (!is_dir($dir)) { 19 throw new \InvalidArgumentException(sprintf('The directory "%s" does not exist.', $dir)); 20 } 21 22 $this->dir = rtrim($dir, '\\/'); 23 } 24 25 /** 26 * {@inheritDoc} 27 */ 28 public function load(string $class): ?ClassMetadata 29 { 30 $path = $this->dir . '/' . strtr($class, '\\', '-') . '.cache.php'; 31 if (!file_exists($path)) { 32 return null; 33 } 34 35 return include $path; 36 } 37 38 /** 39 * {@inheritDoc} 40 */ 41 public function put(ClassMetadata $metadata): void 42 { 43 if (!is_writable($this->dir)) { 44 throw new \InvalidArgumentException(sprintf('The directory "%s" is not writable.', $this->dir)); 45 } 46 47 $path = $this->dir . '/' . strtr($metadata->name, '\\', '-') . '.cache.php'; 48 49 $tmpFile = tempnam($this->dir, 'metadata-cache'); 50 file_put_contents($tmpFile, '<?php return unserialize(' . var_export(serialize($metadata), true) . ');'); 51 52 // Let's not break filesystems which do not support chmod. 53 @chmod($tmpFile, 0666 & ~umask()); 54 55 $this->renameFile($tmpFile, $path); 56 } 57 58 /** 59 * Renames a file with fallback for windows 60 * 61 */ 62 private function renameFile(string $source, string $target): void 63 { 64 if (false === @rename($source, $target)) { 65 if (defined('PHP_WINDOWS_VERSION_BUILD')) { 66 if (false === copy($source, $target)) { 67 throw new \RuntimeException(sprintf('(WIN) Could not write new cache file to %s.', $target)); 68 } 69 if (false === unlink($source)) { 70 throw new \RuntimeException(sprintf('(WIN) Could not delete temp cache file to %s.', $source)); 71 } 72 } else { 73 throw new \RuntimeException(sprintf('Could not write new cache file to %s.', $target)); 74 } 75 } 76 } 77 78 /** 79 * {@inheritDoc} 80 */ 81 public function evict(string $class): void 82 { 83 $path = $this->dir . '/' . strtr($class, '\\', '-') . '.cache.php'; 84 if (file_exists($path)) { 85 unlink($path); 86 } 87 } 88} 89