Autoloader   A
last analyzed

Complexity

Total Complexity 19

Size/Duplication

Total Lines 218
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 0
loc 218
c 0
b 0
f 0
wmc 19
lcom 1
cbo 1
ccs 79
cts 79
cp 1
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A register() 0 4 1
A registerPackages() 0 18 2
A getRegisteredPackages() 0 4 1
A includeClass() 0 21 3
A loadPackageStack() 0 21 3
A loadPackage() 0 17 2
A packageRegistered() 0 12 2
A registrationExists() 0 18 3
A requireFile() 0 17 2
1
<?php
2
namespace Subreality\Dilmun\Nabu;
3
4
use Subreality\Dilmun\LoggedClassTrait;
5
6
/**
7
 * PSR-4 compliant autoloading class
8
 *
9
 * @author derek
10
 */
11
class Autoloader
12
{
13
    use LoggedClassTrait;
14
15
    protected $packages = array();
16
17
    /**
18
     * Registers the includeClass function as an autoloader.
19
     *
20
     * @see Autoloader::includeClass
21
     *
22
     * @return void
23
     */
24 2
    public function register()
25
    {
26 2
        spl_autoload_register(array($this,"includeClass"));
27 2
    }
28
29
    /**
30
     * Registers a given package with an associated path.
31
     *
32
     * Duplicate package/path combinations will not be re-registered.
33
     *
34
     * @param string $package   The name of the package to be registered
35
     * @param string $path      The path to be associated with the registered package
36
     *
37
     * @return void
38
     */
39 14
    public function registerPackages($package, $path)
40
    {
41 14
        $this->updateLog("info", "Preparing package {$package} for registration with path {$path}.");
42
43 14
        $package = trim($package, "\\");
44 14
        $package = $package . "\\";
45
46 14
        $path = rtrim($path, DIRECTORY_SEPARATOR);
47 14
        $path = $path . "/";
48
49 14
        $path_registered = $this->registrationExists($package, $path);
50
51 14
        if (!$path_registered) {
52 10
            $this->packages[$package][] = $path;
53
54 10
            $this->updateLog("info", "Registered index {$package} as {$path}");
55 10
        }
56 14
    }
57
58
    /**
59
     * Returns an array of registered packages.
60
     *
61
     * @return array
62
     */
63 9
    public function getRegisteredPackages()
64
    {
65 9
        return $this->packages;
66
    }
67
68
    /**
69
     * Includes the file corresponding with the class name to be autoloaded
70
     *
71
     * @param string $class Class name as defined by PHP autoloading
72
     *
73
     * @return void
74
     */
75 3
    protected function includeClass($class)
76
    {
77 3
        $this->updateLog("info", "Setting up {$class} class for inclusion.");
78
79 3
        $class_bits = explode("\\", $class);
80
81 3
        $package       = "";
82 3
        $package_stack = array();
83
84 3
        foreach ($class_bits as $bit) {
85 3
            $package = $package . $bit . "\\";
86
87 3
            $package_registered = $this->packageRegistered($package);
88
89 3
            if ($package_registered) {
90 2
                $package_stack[] = $package;
91 2
            }
92 3
        }
93
94 3
        $this->loadPackageStack($class, $package_stack);
95 3
    }
96
97
    /**
98
     * Attempts to load a class from a stack of packages
99
     *
100
     * @param string $class         The fully-qualified class name
101
     * @param array $package_stack  A stack of packages for loading
102
     *
103
     * @return bool                 Returns true if the class was successfully loaded from the package stack
104
     *                              Returns false if the class could not be loaded from the package stack
105
     */
106 3
    protected function loadPackageStack($class, array $package_stack)
107
    {
108 3
        foreach ($package_stack as $package) {
109 2
            $package_length = strlen($package);
110
111 2
            $class_path = substr($class, $package_length);
112
113 2
            $this->updateLog("debug", "Found class path {$class_path} in {$class} given {$package}");
114
115 2
            $package_loaded = $this->loadPackage($package, $class_path);
116
117 2
            if ($package_loaded) {
118 1
                $this->updateLog("info", "Loaded {$class_path} using package {$package}");
119 1
                return true;
120
            }
121 3
        }
122
123 2
        $this->updateLog("alert", "No files found for {$class} in registered packages!");
124
125 2
        return false;
126
    }
127
128
    /**
129
     * Loads a package based on registered paths associated with the package.
130
     *
131
     * @param string $package_name  The name of the package in Vendor\Package format
132
     * @param string $class_name    The full, relative name of the class with the vendor and package names stripped
133
     *
134
     * @return bool                 The path to the class on success; otherwise false
135
     */
136 2
    protected function loadPackage($package_name, $class_name)
137
    {
138 2
        $this->updateLog("info", "Working on loading {$class_name} from {$package_name}");
139
140 2
        $file_required = false;
141
142 2
        foreach ($this->packages[$package_name] as $path) {
143 2
            $converted_class = str_replace('\\', DIRECTORY_SEPARATOR, $class_name);
144 2
            $class_path      = $path . $converted_class . ".php";
145
146 2
            $this->updateLog("debug", "Class file path is {$class_path}");
147
148 2
            $file_required = $this->requireFile($class_path);
149 2
        }
150
151 2
        return $file_required;
152
    }
153
154
    /**
155
     * Determines whether a given package is registered with the Autoloader
156
     *
157
     * @param string $package   The package to check
158
     *
159
     * @return bool             Returns true if the given package is registered
160
     *                          Returns false if the given package is not registered
161
     */
162 14
    private function packageRegistered($package)
163
    {
164 14
        $package_registered = array_key_exists($package, $this->packages);
165
166 14
        if ($package_registered) {
167 13
            $this->updateLog("info", "Package {$package} is registered");
168 13
        } else {
169 12
            $this->updateLog("info", "Package {$package} is not registered");
170
        }
171
172 14
        return $package_registered;
173
    }
174
175
    /**
176
     * Determines whether a given package/path combination has already been registered with the Autoloader
177
     *
178
     * @param string $package   The package to check
179
     * @param string $path      The path to check
180
     *
181
     * @return bool             Returns true if the given path has been registered with the given package
182
     *                          Returns false if the given path has not been registered with the given package
183
     */
184 14
    private function registrationExists($package, $path)
185
    {
186 14
        $package_registered = $this->packageRegistered($package);
187
188 14
        if ($package_registered) {
189 12
            $path_registered = array_search($path, $this->packages[$package]);
190
191 12
            if ($path_registered !== false) {
192 12
                $path_registered = true;
193
194 12
                $this->updateLog("info", "Path {$path} already registered for package {$package}");
195 12
            }
196 12
        } else {
197 10
            $path_registered = false;
198
        }
199
200 14
        return $path_registered;
201
    }
202
203
    /**
204
     * Requires a file only if it existss
205
     *
206
     * @param string $path  The path to the file for requiring
207
     *
208
     * @return bool         Returns true if the file at the given path exists
209
     *                      Returns false if the file at the given path does not exist
210
     */
211 2
    private function requireFile($path)
212
    {
213 2
        if (file_exists($path)) {
214 1
            $this->updateLog("debug", "File {$path} exists; requiring file");
215
216
            /** @noinspection PhpIncludeInspection */
217 1
            require $path;
218
219 1
            $this->updateLog("info", "Completed loading {$path}");
220
221 1
            return true;
222
        } else {
223 2
            $this->updateLog("debug", "File {$path} does not exist");
224
225 2
            return false;
226
        }
227
    }
228
}
229