1: <?php
2:
3: namespace Budabot\Core;
4:
5: use ReflectionAnnotatedClass;
6:
7: class ClassLoader {
8:
9: public $logger;
10:
11: private $moduleLoadPaths;
12:
13: public function __construct($moduleLoadPaths) {
14: $this->moduleLoadPaths = $moduleLoadPaths;
15: }
16:
17: public function loadInstances() {
18: $newInstances = $this->getNewInstancesInDir("./core");
19: forEach ($newInstances as $name => $className) {
20: Registry::setInstance($name, new $className);
21: }
22:
23: $this->loadCoreModules();
24: $this->loadUserModules();
25:
26: $this->logger->log('DEBUG', "Inject dependencies for all instances");
27: forEach (Registry::getAllInstances() as $instance) {
28: Registry::injectDependencies($instance);
29: }
30: }
31:
32: private function loadCoreModules() {
33:
34: $this->logger->log('INFO', "Loading CORE modules...");
35: $core_modules = array('CONFIG', 'SYSTEM', 'ADMIN', 'BAN', 'HELP', 'LIMITS', 'PLAYER_LOOKUP', 'BUDDYLIST', 'ALTS', 'USAGE', 'PREFERENCES', 'PROFILE', 'COLORS');
36: forEach ($core_modules as $MODULE_NAME) {
37: $this->registerModule("./core", $MODULE_NAME);
38: }
39: }
40:
41: 42: 43: 44:
45: private function loadUserModules() {
46: $this->logger->log('INFO', "Loading USER modules...");
47: forEach ($this->moduleLoadPaths as $path) {
48: $this->logger->log('DEBUG', "Loading modules in path '$path'");
49: if (file_exists($path) && $d = dir($path)) {
50: while (false !== ($MODULE_NAME = $d->read())) {
51: if ($this->isModuleDir($path, $MODULE_NAME)) {
52: $this->registerModule($path, $MODULE_NAME);
53: }
54: }
55: $d->close();
56: }
57: }
58: }
59:
60: private function isModuleDir($path, $moduleName) {
61: return $this->isValidModuleName($moduleName)
62: && is_dir("$path/$moduleName");
63: }
64:
65: private function isValidModuleName($name) {
66: return $name != '.' && $name != '..';
67: }
68:
69: public function registerModule($baseDir, $MODULE_NAME) {
70:
71: if (file_exists("{$baseDir}/{$MODULE_NAME}/module.ini")) {
72: $entries = parse_ini_file("{$baseDir}/{$MODULE_NAME}/module.ini");
73:
74:
75: if (isset($entries["minimum_php_version"])) {
76: $minimum = $entries["minimum_php_version"];
77: $current = phpversion();
78: if (strnatcmp($minimum, $current) > 0) {
79: $this->logger->log('WARN', "Could not load module"
80: ." {$MODULE_NAME} as it requires at least PHP version '$minimum',"
81: ." but current PHP version is '$current'");
82: return;
83: }
84: }
85: }
86:
87: $newInstances = $this->getNewInstancesInDir("{$baseDir}/{$MODULE_NAME}");
88: forEach ($newInstances as $name => $className) {
89: $obj = new $className;
90: $obj->moduleName = $MODULE_NAME;
91: if (Registry::instanceExists($name)) {
92: $this->logger->log('WARN', "Instance with name '$name' already registered--replaced with new instance");
93: }
94: Registry::setInstance($name, $obj);
95: }
96:
97: if (count($newInstances) == 0) {
98: $this->logger->log('ERROR', "Could not load module {$MODULE_NAME}. No classes found with @Instance annotation!");
99: return;
100: }
101: }
102:
103: public static function getNewInstancesInDir($path) {
104: $original = get_declared_classes();
105: if ($dir = dir($path)) {
106: while (false !== ($file = $dir->read())) {
107: if (!is_dir($path . '/' . $file) && preg_match("/\\.php$/i", $file)) {
108: require_once "{$path}/{$file}";
109: }
110: }
111: $dir->close();
112: }
113: $new = array_diff(get_declared_classes(), $original);
114:
115: $newInstances = array();
116: forEach ($new as $className) {
117: $reflection = new ReflectionAnnotatedClass($className);
118: if ($reflection->hasAnnotation('Instance')) {
119: if ($reflection->getAnnotation('Instance')->value != '') {
120: $name = $reflection->getAnnotation('Instance')->value;
121: } else {
122: $name = Registry::formatName($className);
123: }
124: $newInstances[$name] = $className;
125: }
126: }
127: return $newInstances;
128: }
129: }
130: