Passed
Push — master ( 5063d9...a1994b )
by Jeroen
22:08
created

AutoloadManager   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 183
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 44.26%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 183
rs 10
c 1
b 0
f 0
ccs 27
cts 61
cp 0.4426
wmc 23
lcom 1
cbo 3

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A addClasses() 0 10 2
B scanClassesDir() 0 21 5
A deleteCache() 0 6 2
A getLoader() 0 3 1
A __destruct() 0 3 1
A saveCache() 0 11 4
A setStorage() 0 3 1
A loadCache() 0 14 2
A getSpec() 0 12 4
1
<?php
2
namespace Elgg;
3
/**
4
 * Manages core autoloading and caching of class maps
5
 *
6
 * @access private
7
 *
8
 * @package    Elgg.Core
9
 * @subpackage Autoloader
10
 */
11
class AutoloadManager {
12
13
	const FILENAME = 'autoload_data.php';
14
	const KEY_CLASSES = 'classes';
15
	const KEY_SCANNED_DIRS = 'scannedDirs';
16
17
	/**
18
	 * @var \Elgg\ClassLoader
19
	 */
20
	protected $loader;
21
22
	/**
23
	 * @var array directories that have already been scanned for classes
24
	 */
25
	protected $scannedDirs = [];
26
27
	/**
28
	 * @var bool was data in the manager altered?
29
	 */
30
	protected $altered = false;
31
32
	/**
33
	 * @var \ElggCache
34
	 */
35
	protected $storage = null;
36
37
	/**
38
	 * Constructor
39
	 *
40
	 * @param \Elgg\ClassLoader $loader Class loader object
41
	 */
42 1
	public function __construct(\Elgg\ClassLoader $loader) {
43 1
		$this->loader = $loader;
44 1
	}
45
46
	/**
47
	 * Add classes found in this directory to the class map and allow classes in
48
	 * subdirectories to be found by PSR-0 rules.
49
	 *
50
	 * We keep track of which dirs were scanned on previous requests so we don't need to
51
	 * rescan unless the cache is emptied.
52
	 *
53
	 * @param string $dir Directory of classes
54
	 * @return \Elgg\AutoloadManager
55
	 */
56
	public function addClasses($dir) {
57
		if (!in_array($dir, $this->scannedDirs)) {
58
			$map = $this->loader->getClassMap();
59
			$map->mergeMap($this->scanClassesDir($dir));
60
			$this->scannedDirs[] = $dir;
61
			$this->altered = true;
62
		}
63
		$this->loader->addFallback($dir);
64
		return $this;
65
	}
66
67
	/**
68
	 * Scan (non-recursively) a /classes directory for PHP files to map directly to classes.
69
	 *
70
	 * For BC with Elgg 1.8's autoloader we map these files directly, but besides this
71
	 * the autoloader is PSR-0 compatible.
72
	 *
73
	 * @param string $dir Directory of classes
74
	 * @return array
75
	 */
76
	protected function scanClassesDir($dir) {
77
		$dir = new \DirectoryIterator($dir);
78
		$map = [];
79
80
		foreach ($dir as $file) {
81
			/* @var \SplFileInfo $file */
82
			if (!$file->isFile() || !$file->isReadable()) {
83
				continue;
84
			}
85
86
			$path = $file->getRealPath();
87
88
			if (pathinfo($path, PATHINFO_EXTENSION) !== 'php') {
89
				continue;
90
			}
91
92
			$class = $file->getBasename('.php');
93
			$map[$class] = $path;
94
		}
95
		return $map;
96
	}
97
98
	/**
99
	 * If necessary, save necessary state details
100
	 *
101
	 * @return \Elgg\AutoloadManager
102
	 */
103 1
	public function saveCache() {
104 1
		if ($this->storage) {
105 1
			$map = $this->loader->getClassMap();
106 1
			if ($this->altered || $map->getAltered()) {
107 1
				$spec[self::KEY_CLASSES] = $map->getMap();
108 1
				$spec[self::KEY_SCANNED_DIRS] = $this->scannedDirs;
109 1
				$this->storage->save(self::FILENAME, serialize($spec));
110
			}
111
		}
112 1
		return $this;
113
	}
114
115
	/**
116
	 * Set the state of the manager from the cache
117
	 *
118
	 * @return bool was the cache loaded?
119
	 */
120 1
	public function loadCache() {
121 1
		$spec = $this->getSpec();
122 1
		if ($spec) {
123
			// the cached class map will have the full scanned core classes, so
124
			// don't consider the earlier mappings as "altering" the map
125
			$this->loader->getClassMap()
126
				->setMap($spec[self::KEY_CLASSES])
127
				->setAltered(false);
128
			$this->scannedDirs = $spec[self::KEY_SCANNED_DIRS];
129
			return true;
130
		}
131 1
		$this->altered = true;
132 1
		return false;
133
	}
134
135
	/**
136
	 * Some method that does something
137
	 *
138
	 * @todo what is a spec?
139
	 * @return bool|array
140
	 */
141 1
	protected function getSpec() {
142 1
		if ($this->storage) {
143 1
			$serialization = $this->storage->load(self::FILENAME);
144 1
			if ($serialization) {
145
				$spec = unserialize($serialization);
146
				if (isset($spec[self::KEY_CLASSES])) {
147
					return $spec;
148
				}
149
			}
150
		}
151 1
		return false;
152
	}
153
154
	/**
155
	 * Delete the cache file
156
	 *
157
	 * @return \Elgg\AutoloadManager
158
	 */
159
	public function deleteCache() {
160
		if ($this->storage) {
161
			$this->storage->delete(self::FILENAME);
162
		}
163
		return $this;
164
	}
165
166
	/**
167
	 * Get the class loader
168
	 *
169
	 * @return \Elgg\ClassLoader
170
	 */
171
	public function getLoader() {
172
		return $this->loader;
173
	}
174
175
	/**
176
	 * Set the cache storage object
177
	 *
178
	 * @param \ElggCache $storage Cache object
179
	 * @return void
180
	 */
181 1
	public function setStorage(\ElggCache $storage) {
182 1
		$this->storage = $storage;
183 1
	}
184
185
	/**
186
	 * Save the cache on object destruction
187
	 *
188
	 * @return void
189
	 */
190 1
	public function __destruct() {
191 1
		$this->saveCache();
192 1
	}
193
}
194