AutoloadManager::getSpec()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
nc 4
nop 0
dl 0
loc 12
ccs 0
cts 10
cp 0
crap 20
rs 9.8666
c 0
b 0
f 0
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 = array();
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 6
	public function __construct(\Elgg\ClassLoader $loader) {
43 6
		$this->loader = $loader;
44 6
	}
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 = array();
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
	 * Register the location of a class on the class map
100
	 *
101
	 * @param string $class Class name
102
	 * @param string $path  Path of class file
103
	 * @return \Elgg\AutoloadManager
104
	 */
105
	public function setClassPath($class, $path) {
106
		$this->loader->getClassMap()->setPath($class, $path);
107
		return $this;
108
	}
109
110
	/**
111
	 * If necessary, save necessary state details
112
	 *
113
	 * @return \Elgg\AutoloadManager
114
	 */
115
	public function saveCache() {
116
		if ($this->storage) {
117
			$map = $this->loader->getClassMap();
118
			if ($this->altered || $map->getAltered()) {
119
				$spec[self::KEY_CLASSES] = $map->getMap();
0 ignored issues
show
Coding Style Comprehensibility introduced by
$spec was never initialized. Although not strictly required by PHP, it is generally a good practice to add $spec = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
120
				$spec[self::KEY_SCANNED_DIRS] = $this->scannedDirs;
121
				$this->storage->save(self::FILENAME, serialize($spec));
122
			}
123
		}
124
		return $this;
125
	}
126
127
	/**
128
	 * Set the state of the manager from the cache
129
	 *
130
	 * @return bool was the cache loaded?
131
	 */
132
	public function loadCache() {
133
		$spec = $this->getSpec();
134
		if ($spec) {
135
			// the cached class map will have the full scanned core classes, so
136
			// don't consider the earlier mappings as "altering" the map
137
			$this->loader->getClassMap()
138
				->setMap($spec[self::KEY_CLASSES])
139
				->setAltered(false);
140
			$this->scannedDirs = $spec[self::KEY_SCANNED_DIRS];
141
			return true;
142
		}
143
		$this->altered = true;
144
		return false;
145
	}
146
147
	/**
148
	 * Some method that does something
149
	 * 
150
	 * @todo what is a spec?
151
	 * @return bool|array
152
	 */
153
	protected function getSpec() {
154
		if ($this->storage) {
155
			$serialization = $this->storage->load(self::FILENAME);
156
			if ($serialization) {
157
				$spec = unserialize($serialization);
158
				if (isset($spec[self::KEY_CLASSES])) {
159
					return $spec;
160
				}
161
			}
162
		}
163
		return false;
164
	}
165
166
	/**
167
	 * Delete the cache file
168
	 *
169
	 * @return \Elgg\AutoloadManager
170
	 */
171
	public function deleteCache() {
172
		if ($this->storage) {
173
			$this->storage->delete(self::FILENAME);
174
		}
175
		return $this;
176
	}
177
178
	/**
179
	 * Get the class loader
180
	 * 
181
	 * @return \Elgg\ClassLoader
182
	 */
183
	public function getLoader() {
184
		return $this->loader;
185
	}
186
187
	/**
188
	 * Set the cache storage object
189
	 * 
190
	 * @param \ElggCache $storage Cache object
191
	 * @return void
192
	 */
193
	public function setStorage(\ElggCache $storage) {
194
		$this->storage = $storage;
195
	}
196
}
197
198