21 protected $_altParams = [self::TYPE_ARRAY =>
null,
null =>
null];
33 $this->
publish([
'type',
'refresh']);
37 if($type == self::TYPE_CHAIN){
39 foreach($params as $sub_type => $sub_params)
41 $params = [$providers];
43 $reflect = new \ReflectionClass(
'\\Doctrine\\Common\\Cache\\' . ucfirst($type) .
'Cache');
44 return $reflect->newInstanceArgs($params ?: []);
53 public function save($id,$data,$ttl =
null){
55 $log->debug(__CLASS__ .
"::save('$id',...,$ttl)",__FILE__,__LINE__);
56 if($data ===
false) $log->warning(
"Saving false in cache for id '$id' (means 'no cache found')",__FILE__,__LINE__);
57 if($this->_refresh) $this->_refreshed[] = $id;
59 if($this->ttlVariation) $ttl *= 1 + rand(-1000,1000) * $this->ttlVariation / 100000;
61 return $this->provider->save($id,$data,$ttl);
64 $log->error($e,compact(
'id',
'data'));
75 public function fetch($id,$ttl =
null,$callback =
null){
77 $time = $this->statPrefix ? microtime(
true) :
null;
80 $data = $this->_refresh && !in_array($id,$this->_refreshed) ? false : $this->provider->fetch($id);
81 if($busy = $this->busyPlaceholder && ($data === $this->busyPlaceholder)) sleep(1);
86 $data = $busy =
false;
87 $log->error($e,compact(
'id'));
89 $log->debug(__CLASS__ .
"::fetch('$id',$ttl,...)",__FILE__,__LINE__,[
'cache' => $id,
'found' => $data !==
false]);
90 if($data !==
false) $time =
false;
92 if($this->busyPlaceholder) $this->
save($id,$this->busyPlaceholder,$this->_busyTtl ?: ini_get(
'max_execution_time'));
93 $this->
save($id,$data = call_user_func($callback,$id),$ttl);
95 if($this->statPrefix) $this->
component(
'stats')->inc(
96 $this->statPrefix .
':' . $id .
':' . ($time ?
'miss' :
'hit'),
97 $time && $callback ? microtime(
true) - $time :
null
99 if($this->_fred->debug){
100 if(array_key_exists($id,$this->_duploCount))
101 $log->info(
'Duplicate fetch' . ($this->_duploCount[$id]++ ?
' (' . $this->_duploCount[$id] .
')' :
''),__FILE__,__LINE__,compact(
'id',
'ttl'));
102 else $this->_duploCount[$id] = 0;
111 public function purge(&$errors =
null){
113 $stats = $errors = [];
114 if($this->provider instanceof \Doctrine\Common\
Cache\FilesystemCache) $type =
'file';
115 elseif($this->provider instanceof \Doctrine\Common\
Cache\PhpFileCache) $type =
'php';
118 $files = new \RegexIterator(
119 new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($this->getDirectory())),
120 '/^.+' . preg_quote($this->getExtension(),
'/') .
'$/i'
123 $count = $purged = $total = $largest = $dirs = 0;
124 foreach($files as $path => $file)
try{
127 if(($size = filesize($path)) > $largest) $largest = $size;
130 $resource = fopen($path,
'r');
131 $purge = (int)fgets($resource) < $time;
135 $purge = !is_array($data = include($path)) || !array_key_exists(
'lifetime',$data) || ($data[
'lifetime'] < $time);
140 $purged += unlink($path);
141 if(!(
new \FilesystemIterator($dir = dirname($path)))->valid()) $dirs += rmdir($dir);
145 $errors[] =
"Could not purge $path: " . $e->getMessage();
147 $stats = compact(
'type',
'count',
'purged',
'total',
'largest',
'dirs');
149 else $errors[] =
'Cache type not supported';
154 if(!$this->_provider) $this->_provider = $this->
createProvider($this->_type,$this->_params);
156 if(!$this->_altProvider) $this->_altProvider = $this->
createProvider($this->_altType,$this->_altParams);
161 $this->_refresh = $value;
162 $this->_refreshed = [];
168 public function __call($func_name,$params){
169 if($this->_useAlt = substr($func_name,0,1) ==
'_'){
170 $result = call_user_func_array([$this,substr($func_name,1)],$params);
171 $this->_useAlt =
false;
174 if(in_array($func_name,[
'save',
'contains',
'fetch',
'delete']))
175 $this->
component(
'log')->debug(__CLASS__ .
"::$func_name('$params[0]')",__FILE__,__LINE__);
176 return call_user_func_array([$this->provider,$func_name],$params);
180 return $this->provider->fetch($id);