Passed
Push — master ( 403133...7cfee1 )
by Alexander
11:46
created

CacheManager::getCache()   A

Complexity

Conditions 5
Paths 3

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5

Importance

Changes 0
Metric Value
eloc 9
c 0
b 0
f 0
dl 0
loc 18
ccs 10
cts 10
cp 1
rs 9.6111
cc 5
nc 3
nop 3
crap 5
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 11
	public function setCache($name, $value, $invalidator = null, $duration = null)
73
	{
74 11
		$duration = $this->durationIntoSeconds($duration);
75
76 11
		$storage = $this->_getStorage($name, $duration);
77 10
		$storage->set(array(
78 10
			'name' => $name,
79 10
			'invalidator' => $invalidator,
80 10
			'duration' => $duration,
81 10
			'expiration' => $duration ? time() + $duration : null,
82 10
			'data' => $value,
83 10
		));
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
103 4
			return null;
104
		}
105
106 6
		if ( $cache['expiration'] && $cache['expiration'] < time() ) {
107 1
			$storage->invalidate();
108
109 1
			return null;
110
		}
111
112 6
		return $cache['data'];
113
	}
114
115
	/**
116
	 * Deletes value from cache.
117
	 *
118
	 * @param string  $name     Name.
119
	 * @param integer $duration Duration in seconds.
120
	 *
121
	 * @return void
122
	 */
123 3
	public function deleteCache($name, $duration = null)
124
	{
125 3
		$storage = $this->_getStorage($name, $this->durationIntoSeconds($duration));
126 3
		$storage->invalidate();
127
	}
128
129
	/**
130
	 * Converts duration into seconds.
131
	 *
132
	 * @param integer $duration Duration in seconds.
133
	 *
134
	 * @return integer|null
135
	 */
136 15
	protected function durationIntoSeconds($duration = null)
137
	{
138 15
		if ( !isset($duration) ) {
139 14
			return null;
140
		}
141
142 2
		if ( is_numeric($duration) ) {
0 ignored issues
show
introduced by
The condition is_numeric($duration) is always true.
Loading history...
143 1
			$duration .= ' seconds';
144
		}
145
146 2
		$now = time();
147
148 2
		return strtotime('+' . $duration, $now) - $now;
149
	}
150
151
	/**
152
	 * Returns file-based cache storage.
153
	 *
154
	 * @param string  $name     Cache name.
155
	 * @param integer $duration Duration in seconds.
156
	 *
157
	 * @return ICacheStorage
158
	 * @throws \InvalidArgumentException When namespace is missing in the name.
159
	 */
160 15
	private function _getStorage($name, $duration = null)
161
	{
162 15
		$name_parts = explode(':', $name, 2);
163
164 15
		if ( count($name_parts) != 2 ) {
165 1
			throw new \InvalidArgumentException('The $name parameter must be in "namespace:name" format.');
166
		}
167
168 14
		$filename_parts = array(
169 14
			$name_parts[0],
170 14
			substr(hash_hmac('sha1', $name_parts[1], 'svn-buddy'), 0, 8),
171 14
			'D' . (isset($duration) ? $duration : 'INF'),
172 14
		);
173
174 14
		$cache_filename = $this->_workingDirectory . DIRECTORY_SEPARATOR . implode('_', $filename_parts) . '.cache';
175
176 14
		if ( isset($this->_io) && $this->_io->isVerbose() ) {
177 2
			$message = $cache_filename;
178
179 2
			if ( !array_key_exists($cache_filename, $this->_statistics) ) {
180 2
				$this->_statistics[$cache_filename] = array('hits' => 0, 'misses' => 0);
181
			}
182
183 2
			if ( file_exists($cache_filename) ) {
184 1
				$this->_statistics[$cache_filename]['hits']++;
185 1
				$message .= sprintf(
186 1
					' (hit #%d: %s)',
187 1
					$this->_statistics[$cache_filename]['hits'],
188 1
					$this->_sizeHelper->formatSize(filesize($cache_filename))
189 1
				);
190
			}
191
			else {
192 2
				$this->_statistics[$cache_filename]['misses']++;
193 2
				$message .= sprintf(
194 2
					' (miss #%d)',
195 2
					$this->_statistics[$cache_filename]['misses']
196 2
				);
197
			}
198
199 2
			$this->_io->writeln(array(
200 2
				'',
201 2
				'<debug>[cache]: ' . $message . '</debug>',
202 2
			));
203
		}
204
205 14
		return new FileCacheStorage($cache_filename);
206
	}
207
208
}
209