Issues (155)

src/SVNBuddy/Cache/CacheManager.php (2 issues)

1
<?php
2
/**
3
 * This file is part of the SVN-Buddy library.
4
 * For the full copyright and license information, please view
5
 * the LICENSE file that was distributed with this source code.
6
 *
7
 * @copyright Alexander Obuhovich <[email protected]>
8
 * @link      https://github.com/console-helpers/svn-buddy
9
 */
10
11
namespace ConsoleHelpers\SVNBuddy\Cache;
12
13
14
use ConsoleHelpers\ConsoleKit\ConsoleIO;
15
use ConsoleHelpers\SVNBuddy\Helper\SizeHelper;
16
17
class CacheManager
18
{
19
20
	/**
21
	 * Working directory.
22
	 *
23
	 * @var string
24
	 */
25
	private $_workingDirectory;
26
27
	/**
28
	 * Console IO.
29
	 *
30
	 * @var ConsoleIO
31
	 */
32
	private $_io;
33
34
	/**
35
	 * Size helper.
36
	 *
37
	 * @var SizeHelper
38
	 */
39
	private $_sizeHelper;
40
41
	/**
42
	 * Statistics.
43
	 *
44
	 * @var array
45
	 */
46
	private $_statistics = array();
47
48
	/**
49
	 * Create cache manager.
50
	 *
51
	 * @param string     $working_directory Working directory.
52
	 * @param SizeHelper $size_helper       Size helper.
53
	 * @param ConsoleIO  $io                Console IO.
54
	 */
55 25
	public function __construct($working_directory, SizeHelper $size_helper, ConsoleIO $io = null)
56
	{
57 25
		$this->_workingDirectory = $working_directory;
58 25
		$this->_sizeHelper = $size_helper;
59 25
		$this->_io = $io;
60
	}
61
62
	/**
63
	 * Sets value in cache.
64
	 *
65
	 * @param string  $name        Name.
66
	 * @param mixed   $value       Value.
67
	 * @param mixed   $invalidator Invalidator.
68
	 * @param integer $duration    Duration in seconds.
69
	 *
70
	 * @return void
71
	 */
72 12
	public function setCache($name, $value, $invalidator = null, $duration = null)
73
	{
74 12
		$duration = $this->durationIntoSeconds($duration);
75
76 12
		$storage = $this->_getStorage($name, $duration);
77 11
		$storage->set(array(
78 11
			'name' => $name,
79 11
			'invalidator' => $invalidator,
80 11
			'duration' => $duration,
81 11
			'expiration' => $duration ? time() + $duration : null,
82 11
			'data' => $value,
83 11
		));
84
	}
85
86
	/**
87
	 * Gets value from cache.
88
	 *
89
	 * @param string  $name        Name.
90
	 * @param mixed   $invalidator Invalidator.
91
	 * @param integer $duration    Duration in seconds.
92
	 *
93
	 * @return mixed
94
	 */
95 10
	public function getCache($name, $invalidator = null, $duration = null)
96
	{
97 10
		$storage = $this->_getStorage($name, $this->durationIntoSeconds($duration));
98 10
		$cache = $storage->get();
99
100 10
		if ( !is_array($cache) || $cache['invalidator'] !== $invalidator ) {
101 4
			$storage->invalidate();
102 4
			$this->registerMiss($storage, is_array($cache) ? 'invalidated' : 'absent');
0 ignored issues
show
The condition is_array($cache) is always false.
Loading history...
103
104 4
			return null;
105
		}
106
107 7
		if ( $cache['expiration'] && $cache['expiration'] < time() ) {
108 2
			$storage->invalidate();
109 2
			$this->registerMiss($storage, 'expired');
110
111 2
			return null;
112
		}
113
114 6
		$this->registerHit($storage);
115
116 6
		return $cache['data'];
117
	}
118
119
	/**
120
	 * Registers hit.
121
	 *
122
	 * @param ICacheStorage $storage Storage.
123
	 *
124
	 * @return void
125
	 */
126 6
	protected function registerHit(ICacheStorage $storage)
127
	{
128 6
		if ( !isset($this->_io) || !$this->_io->isVerbose() ) {
129 5
			return;
130
		}
131
132 1
		$unique_id = $storage->getUniqueId();
133 1
		$message = $unique_id;
134
135 1
		$this->initStatistics($storage);
136
137 1
		$this->_statistics[$unique_id]['hits']++;
138 1
		$message .= sprintf(
139 1
			' (hit #%d: %s)',
140 1
			$this->_statistics[$unique_id]['hits'],
141 1
			$this->_sizeHelper->formatSize($storage->getSize())
142 1
		);
143
144 1
		$this->_io->writeln(array(
145 1
			'',
146 1
			'<debug>[cache]: ' . $message . '</debug>',
147 1
		));
148
	}
149
150
	/**
151
	 * Registers miss.
152
	 *
153
	 * @param ICacheStorage $storage Storage.
154
	 * @param string        $reason  Reason.
155
	 *
156
	 * @return void
157
	 */
158 5
	protected function registerMiss(ICacheStorage $storage, $reason)
159
	{
160 5
		if ( !isset($this->_io) || !$this->_io->isVerbose() ) {
161 4
			return;
162
		}
163
164 1
		$unique_id = $storage->getUniqueId();
165 1
		$message = $unique_id;
166
167 1
		$this->initStatistics($storage);
168
169 1
		$this->_statistics[$unique_id]['misses']++;
170 1
		$message .= sprintf(
171 1
			' (miss:' . $reason . ' #%d)',
172 1
			$this->_statistics[$unique_id]['misses']
173 1
		);
174
175 1
		$this->_io->writeln(array(
176 1
			'',
177 1
			'<debug>[cache]: ' . $message . '</debug>',
178 1
		));
179
	}
180
181
	/**
182
	 * Initializes statistics.
183
	 *
184
	 * @param ICacheStorage $storage Storage.
185
	 *
186
	 * @return void
187
	 */
188 2
	protected function initStatistics(ICacheStorage $storage)
189
	{
190 2
		$unique_id = $storage->getUniqueId();
191
192 2
		if ( !array_key_exists($unique_id, $this->_statistics) ) {
193 2
			$this->_statistics[$unique_id] = array('hits' => 0, 'misses' => 0);
194
		}
195
	}
196
197
	/**
198
	 * Deletes value from cache.
199
	 *
200
	 * @param string  $name     Name.
201
	 * @param integer $duration Duration in seconds.
202
	 *
203
	 * @return void
204
	 */
205 3
	public function deleteCache($name, $duration = null)
206
	{
207 3
		$storage = $this->_getStorage($name, $this->durationIntoSeconds($duration));
208 3
		$storage->invalidate();
209
	}
210
211
	/**
212
	 * Converts duration into seconds.
213
	 *
214
	 * @param integer $duration Duration in seconds.
215
	 *
216
	 * @return integer|null
217
	 */
218 15
	protected function durationIntoSeconds($duration = null)
219
	{
220 15
		if ( !isset($duration) ) {
221 14
			return null;
222
		}
223
224 3
		if ( is_numeric($duration) ) {
0 ignored issues
show
The condition is_numeric($duration) is always true.
Loading history...
225 2
			$duration .= ' seconds';
226
		}
227
228 3
		$now = time();
229
230 3
		return strtotime('+' . $duration, $now) - $now;
231
	}
232
233
	/**
234
	 * Returns file-based cache storage.
235
	 *
236
	 * @param string  $name     Cache name.
237
	 * @param integer $duration Duration in seconds.
238
	 *
239
	 * @return ICacheStorage
240
	 * @throws \InvalidArgumentException When namespace is missing in the name.
241
	 */
242 15
	private function _getStorage($name, $duration = null)
243
	{
244 15
		$name_parts = explode(':', $name, 2);
245
246 15
		if ( count($name_parts) != 2 ) {
247 1
			throw new \InvalidArgumentException('The $name parameter must be in "namespace:name" format.');
248
		}
249
250 14
		$filename_parts = array(
251 14
			$name_parts[0],
252 14
			substr(hash_hmac('sha1', $name_parts[1], 'svn-buddy'), 0, 8),
253 14
			'D' . (isset($duration) ? $duration : 'INF'),
254 14
		);
255
256 14
		return new FileCacheStorage(
257 14
			$this->_workingDirectory . DIRECTORY_SEPARATOR . implode('_', $filename_parts) . '.cache'
258 14
		);
259
	}
260
261
}
262