Completed
Push — master ( a05d8f...d51291 )
by Peter
18:15
created

MetaCache   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 199
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 85.71%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 30
c 3
b 0
f 0
lcom 1
cbo 6
dl 0
loc 199
ccs 84
cts 98
cp 0.8571
rs 10

13 Methods

Rating   Name   Duplication   Size   Complexity  
A setComponent() 0 4 1
A setOptions() 0 4 1
A __construct() 0 19 3
C prepare() 0 30 8
B get() 0 25 4
A set() 0 14 1
A remove() 0 10 2
A clear() 0 4 1
A _clearCurrent() 0 4 1
B _clear() 0 12 5
A _getFilename() 0 4 1
A _classToFile() 0 4 1
A mkdir() 0 6 1
1
<?php
2
3
/**
4
 * This software package is licensed under AGPL, Commercial license.
5
 *
6
 * @package maslosoft/addendum
7
 * @licence AGPL, Commercial
8
 * @copyright Copyright (c) Piotr Masełkowski <[email protected]> (Meta container, further improvements, bugfixes)
9
 * @copyright Copyright (c) Maslosoft (Meta container, further improvements, bugfixes)
10
 * @copyright Copyright (c) Jan Suchal (Original version, builder, parser)
11
 * @link http://maslosoft.com/addendum/ - maslosoft addendum
12
 * @link https://code.google.com/p/addendum/ - original addendum project
13
 */
14
15
namespace Maslosoft\Addendum\Cache;
16
17
use FilesystemIterator;
18
use Maslosoft\Addendum\Addendum;
19
use Maslosoft\Addendum\Collections\Meta;
20
use Maslosoft\Addendum\Helpers\SoftIncluder;
21
use Maslosoft\Addendum\Interfaces\AnnotatedInterface;
22
use Maslosoft\Addendum\Options\MetaOptions;
23
use Maslosoft\Cli\Shared\ConfigDetector;
24
use Maslosoft\Cli\Shared\Helpers\PhpExporter;
25
use RecursiveDirectoryIterator;
26
use RecursiveIteratorIterator;
27
use RuntimeException;
28
29
class MetaCache
30
{
31
32
	private $_metaClass = null;
33
	private $_component = null;
34
35
	/**
36
	 * Options
37
	 * @var string
38
	 */
39
	private $_instanceId = null;
40
41
	/**
42
	 * Addendum runtime path
43
	 * @var string
44
	 */
45
	private $_path = '';
46
47
	/**
48
	 *
49
	 * @var NsCache
50
	 */
51
	private $_nsCache = null;
52
53
	/**
54
	 * Runtime path
55
	 * @var string
56
	 */
57
	private static $_runtimePath = null;
58
59
	/**
60
	 * Local cacheq
61
	 * @var type
62
	 */
63
	private static $_cache = [];
64
65 3
	public function __construct($metaClass = null, AnnotatedInterface $component = null, MetaOptions $options = null)
66
	{
67 3
		if (null === self::$_runtimePath)
68 3
		{
69
			self::$_runtimePath = (new ConfigDetector)->getRuntimePath();
70
		}
71 3
		$this->_path = self::$_runtimePath . '/addendum';
72 3
		$this->_metaClass = $metaClass;
73 3
		$this->_component = $component;
74 3
		if (empty($options))
75 3
		{
76 3
			$this->_instanceId = Addendum::DefaultInstanceId;
77 3
		}
78
		else
79
		{
80
			$this->_instanceId = $options->instanceId;
81
		}
82 3
		$this->_nsCache = new NsCache(dirname($this->_getFilename()), Addendum::fly($this->_instanceId));
83 3
	}
84
85 28
	public function setComponent(AnnotatedInterface $component = null)
86
	{
87 28
		$this->_component = $component;
88 28
	}
89
90 28
	public function setOptions(MetaOptions $options = null)
91
	{
92 28
		$this->_nsCache->setOptions($options);
93 28
	}
94
95 28
	public function prepare()
96
	{
97 28
		if (!file_exists($this->_path))
98 28
		{
99 28
			if (!file_exists(self::$_runtimePath))
100 28
			{
101
102 1
				if (is_writable(dirname(self::$_runtimePath)))
103 1
				{
104 1
					$this->mkdir(self::$_runtimePath);
105 1
				}
106 1
				if (!is_writable(self::$_runtimePath))
107 1
				{
108
					throw new RuntimeException(sprintf("Runtime path `%s` must exists and be writable", self:: $_runtimePath));
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces after double colon; 1 found

This check looks for references to static members where there are spaces between the name of the type and the actual member.

An example:

Certificate:: TRIPLEDES_CBC

will actually work, but is not very readable.

Loading history...
109
				}
110 1
			}
111 28
			if (is_writable(self::$_runtimePath))
112 28
			{
113 28
				$this->mkdir($this->_path);
114 28
			}
115 28
			if (!is_writable($this->_path))
116 28
			{
117
				throw new RuntimeException(sprintf("Addendum runtime path `%s` must exists and be writable", $this->_path));
118
			}
119 28
		}
120 28
		if (!file_exists(dirname($this->_getFilename())))
121 28
		{
122 28
			$this->mkdir(dirname($this->_getFilename()));
123 28
		}
124 28
	}
125
126 28
	public function get()
127
	{
128 28
		$this->prepare();
129 28
		$filename = $this->_getFilename();
130
131 28
		if (!$this->_nsCache->valid())
132 28
		{
133 2
			$this->_clearCurrent();
134 2
			return false;
135
		}
136
137 27
		if (isset(self::$_cache[$filename]))
138 27
		{
139 2
			return self::$_cache[$filename];
140
		}
141
142 25
		$data = SoftIncluder::includeFile($filename);
143
144 25
		if (empty($data))
145 25
		{
146 25
			return false;
147
		}
148
		self::$_cache[$filename] = $data;
149
		return $data;
150
	}
151
152 19
	public function set(Meta $meta)
153
	{
154
155
156
157 19
		$filename = $this->_getFilename();
158
159 19
		self::$_cache[$filename] = $meta;
160
161 19
		file_put_contents($filename, PhpExporter ::export($meta));
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces before double colon; 1 found

This check looks for references to static members where there are spaces between the name of the type and the actual member.

An example:

Certificate ::TRIPLEDES_CBC

will actually work, but is not very readable.

Loading history...
162 19
		chmod($filename, 0666);
163 19
		$this->_nsCache->set();
164 19
		return $meta;
165
	}
166
167
	public function remove()
168
	{
169
		$filename = $this->_getFilename();
170
		unset(self::$_cache[$filename]);
171
		if (file_exists($filename))
172
		{
173
			return unlink($filename);
174
		}
175
		return false;
176
	}
177
178
	/**
179
	 * Clear entire cache
180
	 * @return boolean
181
	 */
182 3
	public function clear()
183
	{
184 3
		return $this->_clear($this->_path);
185
	}
186
187 2
	private function _clearCurrent()
188
	{
189 2
		return $this->_classToFile(dirname($this->_getFilename()));
190
	}
191
192 3
	private function _clear($path)
193
	{
194 3
		if (!file_exists($path))
195 3
		{
196 3
			return false;
197
		}
198 1
		foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST) as $dir)
199
		{
200 1
			$dir->isDir() && !$dir->isLink() ? rmdir($dir->getPathname()) : unlink($dir->getPathname());
201 1
		}
202 1
		return rmdir($path);
203
	}
204
205 30
	private function _getFilename()
206
	{
207 30
		return sprintf('%s/%s@%s/%s.php', $this->_path, $this->_classToFile($this->_metaClass), $this->_instanceId, str_replace('\\', '/', $this->_classToFile(get_class($this->_component))));
208
	}
209
210 30
	private function _classToFile($className)
211
	{
212 30
		return str_replace('\\', '.', $className);
213
	}
214
215
	/**
216
	 * Recursively create dir with proper permissions.
217
	 * FIXME Apply chmod recursively
218
	 * @param string $path
219
	 */
220 28
	private function mkdir($path)
221
	{
222 28
		$mask = umask(0000);
223 28
		mkdir($path, 0777, true);
224 28
		umask($mask);
225 28
	}
226
227
}
228